Welcome to MEI's On-line Technical Support

.
 | Welcome <%=Session("FullName")%>
Support for SynqNet Phase II Upgrading Software to SynqNet Phase II Bode Tool Utility MPX -- a new way of writing application code pdfs of the MPI Software | Connector Pinouts SynqNet-XMP Quick Start Guide Software FAQs
 | Current MPI Version: 20030620.1.1 See the General Release Note for changes. Select Your Version of the MPI
Legal Notice tel: (805) 681-3300 | fax: (805) 681-3311
Copyright 2003 Motion Engineering

Find any errors, discrepencies, etc.? Please email us at docs@motioneng.com


Technology

.

Select a section below.
Legal Notice
Copyright © 2003 Motion Engineering


SynqNet Technology Home

.

Introduction to SynqNet
 Overview
Features / Performance
Physical Layer
Abbreviations and Definitions

Topology
 SynqNet Topologies (string/ring)
Node, Cable, Motor Addressing

LEDs
 Controller (SynqNet and CAN)
Node

Node Specific Features
SynqNet Node Library
Drive Parameters

Packet Configuration
 SynqNet Packet Formats
User Configurable Packets

Faults Detection and Recovery
 Node Faults Diagram
Packet Error Counter
Packet Error Rate Counter
CRC Error Counter
SynqNet Fault Recovery
SynqNet Node Failure

Network Initialization and Verification
 Overview of Network Initialization
Default Initialization
Network Configuration
Automatic Initialization
Network Confirmation (save to flash)
Node Identification (device, vendor, serial number, etc)
Application Verification (responsibilities)
Cable Length

Configuration Management
 Introduction
Version Control
Compatibility
Automated Software Configuration
 FAQs

Binary Images
 Controller
Node
Drive
Controller Binary Files Table
Node Binary Files: Product Table (runtime)
Node Binary Files: Features Table (runtime)
Node Binary Files: Boot Table (boot)

>> For additional information, visit www.synqnet.org


Abreviations and Definitions

.

Abreviations and Definitions

Boot Image | A node binary image that contains just enough information for the SynqNet controller to identify and communicate with the connected node(s) on a SynqNet network. Boot image should be preloaded on node. See run-time image.
Cat 5 | Category 5, specification for twisted cables (5e is enhanced).
Control latency | The network latency plus internal delays within a node.
Controller | The Motion controller and SynqNet network host, there should only be one controller per network.
CRC | Cyclic Redundancy Check. See CRC Error Counter.
Data Class | All SynqNet data falls into one of two classes: cyclic or service
Data Type | On each node, cyclic data is mapped to logic modules based on dataType.
Downstream | From the controller to a node. Usually refers to the direction of the data flow.
DP | Drive Processor
Drive Processor | Digital signal processor or other processor responsible for controlling the motor currents.
Drive_Mode | Specifies the operational mode of the drive e.g. torque / braking etc.
Dual String | A topology which consists of two String networks connected to one controller. This topology is currently unsupported.
Earth | Ground
EFT | Electrical Fast Transients
ESD | End of Stream Delimiter (IEEE802.3)
Farthest node | The node that is located the furthest down on the network from the controller. It is also the node that is connected to the redundant link in a Ring topology.
Fault | A 'fault' prevents a drive from working.
FDDI | Fiber Distributed Data Interface
Ground | Earth
Little-endian | Memory organizations where, within a given 16- or 32-bit word, bytes at lower addresses have lower significance (the word is stored "little-end-first").
MAC | Medium Access Controller (see SynqNet MAC)
Message | The unit of communication inbetween the SQNL and the Drive Processor.
MII | Media Independent Interface (IEEE802.3: connects PHY to MAC devices)
Motion Block | A set of hardware functions relating to motion control such as an encoder counter, capture, and compare functions, pulse generators and so forth.
Network latency | The sum of the time taken to (1) send the feedback data to the controller over SynqNet, (2) manipulate the data at the controller, (3) and send the demand data to the node over SynqNet.
Network Phase | The mode of operation of SynqNet, determined by the controller.
Node | Means 'slave node' and not the controller, unless otherwise stated.
Node State | Internal SynqNet state of one given node in the network. Determines the basic behavior allowed for the node.
Packet | The unit of communication in SynqNet™
PHY | Physical Layer Interface: a device that translates 100BT signals into 4 bit MII interface data.
PLL | Phase Locked Loop
Port energized | The receive PHY in a port is in receipt of valid symbols.
PRBS | Pseudo Random Binary Sequence
PSU | Power Supply Unit
Quadlet | A 32-bit word (from IEEE 1394)
Receive port | The port selected at a node to receive the command packets, whichis is normally the IN port.
Redundant link | In a Ring topology only: a point-to-point link that is not used to carry normal operational traffic, it is usually the link connected to the controller's IN port.
Remote Motion Block | A SynqNet node that can be connected to a drive that has a +/-10V or pulse control interface.
Ring | The standard SynqNet topology
Ring of Rings | A topology which consists of two Ring networks connected to one controller. This topology is currently unsupported.
RMB | Remote Motion Block
Run-time Image | A node binary image contains the logic for full operation of the node on a SynqNet network. The run-time image needs to be manually downloaded. See boot image.
Screen | Shield
Shield | Screen
SMI | Serial management interface (part of the MII)
SMPS | Switch Mode Power Supply
SQNL | SynqNet Node Logic.
SSD | Start of Stream Delimiter (IEEE802.3)
STP | Shielded Twisted Pair
String | An alternative to the Ring topology without the redundant link.
Synq_Cycle | One SynqNet cycle consists of one downstream cycle and one upstream cycle, in which packets are sent/received across the network by the controller and the connected node(s).
SYNQ packet | The SynqNet™ packet that is used as a network timing reference.
Synq_Rate | The rate of cyclic communication over SynqNet™.
SynqNet | MEI's motion control network that is specifically designed for high-speed cyclic messaging in high performance motion control applications.
SynqNet MAC | Medium Access Controller: Standard data link layer logic function in all nodes. Translates MII signals from PHY into internal module bus.
SynqNet Node Logic | A digital logic circuit (located in a node) that implements both SynqNet MAC and Motion Block functions. May be supplied either as an FPGA or as an ASIC.
SynqNet™ | A 100Mbit, full-duplex motion control network devised by MEI.
Tree | A topology which consists of a combination of Ring and String networks connected to one controller. This topology is currently unsupported.
Upstream | From the node to the controller . Usually refers to the direction of the data flow.
UTP | Unshielded Twisted Pair
Warning | A 'warning' is an indication that a drive, though operational, is likely to exhibit a fault soon.


Node, Cable, Motor Addressing

.

Node, Cable, Motor Addressing

During network initialization the SynqNet nodes are discovered and identified. Each node is assigned a number (0, 1, 2, etc.) in the order it is discovered. Each cable is assigned a number (0, 1, 2, etc.) in the order it is discovered. Also, each motor (drive interface) is assigned a number (0, 1, 2, etc.) in the order it is discovered.


AMC Digiflex Drive

.

AMC Digiflex Drive

Monitor Table

/* amc_digiflex.h */

/*
 *  Drive Monitor Table
 */

typedef enum DIGIFLEXMonitorIndex {
    DIGIFLEXMonitorIndexBUS_VOLTAGE      =  0,
    DIGIFLEXMonitorIndexDEMAND_TORQUE,
    DIGIFLEXMonitorIndexMEASURED_TORQUE,
    DIGIFLEXMonitorIndexBASE_PLATE_TEMP,
    DIGIFLEXMonitorIndexANALOG_INPUT1,
} DIGIFLEXMonitorIndex;


Application Verification

.

Application Verification

SynqNet nodes are discovered during network initialization and addressed by the controller/software in the order they are found. Please see the Node, Cable, Motor Addressing page for more details. During machine prototyping and development this technique makes it very easy to add or remove nodes. But, this flexibility can also cause problems for the higher level application code if the application does not verify the expected topology.

For example, suppose an application expects to operate with 2 nodes. Each node has one motor and is connected to an X,Y stage (X = motor 0, and Y = motor 1). Suppose there is a bad network cable that is causing the network initialization to find only one node. Or, suppose the 2 nodes were connected in reverse order, so that X = motor 1, and Y = motor 0. An application could easily deal with these situations if it verifies the expected topology during initialization.

An application can compare the expected topology to the discovered topology using the MPI information methods:

meiSynqNetInfo(...) - reads SynqNet information discovered during network initialization. See meiSynqNetInfo(...).

meiSqNodeInfo(...) - reads SqNode information discovered during network initialization. See meiSynqNetInfo(...).

meiSqNodeDriveInfo(...) - reads SqNode Drive information discovered during network initialization. See meiSqNodeDriveInfo(...).

You will need to decide which information to check and how your application should respond to any unexpected topology changes. Here are a few helpful guidelines:

Always Check

SynqNet Network Type - Identifies the network topology (String, Ring, or Terminated String). This is important if an application uses the Fault Recovery feature, which is only supported by Ring topologies. See MEISynqNetInfo and MEINetworkType.

SynqNet Node Count - Make sure the number of expected nodes are found during the Discovery phase. See MEISynqNetInfo.

SqNode Node Type and Option - Make sure the nodes are discovered in the proper order and are of the expected hardware type and option. See MEISqNodeInfoId.

SqNode FPGA Type - Identifies whether the FPGA image is a Boot or Runtime. ALL FPGAs must be Runtime images. Boot images only contain enough logic to be discovered and support the download of the Runtime image. See MEISqNodeFpgaType.

FPGA VendorDevice - Identifies the FPGA image. See MEISqNodeInfoFpga.

SqNode FPGA Version - Make sure the FPGA version is up to date with the software version. Software and FPGAs are tested, packaged, and released together. Mixing FPGAs with different software versions can cause unexpected behavior. See MEISqNodeInfoFpga.

Good Idea to Check

SqNode Exact Match - Identifies whether or not the software exactly knows the node type and FPGA image combination. If the Exact Match is 0 (FALSE), then the software is making its best guess for the node and FPGA features. Please contact MEI if the Exact Match is 0 (FALSE). See MEISqNodeInfoId.

SqNode Motor Count and Offset - The number of motors per node and their offsets. Make sure the motor numbers match the expected node-to-motor number order. See MEISqNodeInfo.

SqNode Drive Firmware Version - Make sure the drive firmware version is correct for your application. Contact the drive manufacturer for firmware version updates. Please see the Drive Partners: Contact Info for contact information. See MEISqNodeDriveInfo.

SqNode SwitchId - Some nodes have a physical dial to set an address. SynqNet does not use the address to identify the node. However, it is useful for applications that want to use the SwitchId to differentiate nodes that use identical node models. This can be useful to correctly identifying a setup or for dynamically mapping MS, Axis, Filter, and Motor objects. See MEISqNodeInfoId.

Optional Information to Check

SqNode Node Name - Text string used to identify the Node Type. Sometimes it's easier to identify nodes by a string instead of by a number. See MEISqNodeInfoId.

SqNode Model and Serial Number - Identifies the particular node model and its serial number. This is useful for tracking nodes. See MEISqNodeInfoId.

SqNode Unique - The Node Type, Option, and Unique values will always uniquely identify every SynqNet node. It is useful for tracking nodes or for applications that use software identification to map the Motion Supervisor, Axis, Filter, and Motor objects. See MEISqNodeInfoId.

SynqNet Cable Length - Measurement is derived from propagation delay during network initialization. It is useful for roughly checking the expected cable lengths. Measurements are accurate to ±8 meters. See MEISynqNetInfo.

SqNode Drive Count - Identifies the number of drives on a node. See MEISqNodeInfo.

Saving Topology

If the network topology is saved to flash, then the controller performs the network initialization and compares the discovered network topology to the topology information saved in flash memory. If the topology does not match, the MPI will return either:
MEISynqNetMessageTOPOLOGY_MISMATCH or
MEISynqNetMessageTOPOLOGY_MISMATCH_FLASH.
See meiSynqNetTopologySave.

The controller uses the following criteria to determine whether the discovered topology matches the saved topology:

  • Network Type
  • Node Count
  • Node Type
  • Node Option
  • FPGA VendorDevice


Automatic Initialization Routine

.

Automatic Initialization Routine

If the network verification passes, then it is safe for the controller to assume that previously saved configurations in the Flash object are correct. The controller can then automatically enables the use of the Flash object, loads flash memory into working memory, transitions the network into the CYCLIC phase, and streams down FPGA configuration data to each node on the network.

All of these steps of execution occur without the help of the MPI.

It is only after all FPGA Configuration data is sent across the network, that execution control is passed to the MPI. At this point, the MPI is required to initiate Drive Specific Initialization routines and return control to the Host application.


Automated Software Configuration

.

Automated Software Configuration

During the machine development phase, several different versions of MPI DLLs and/or XMP firmware might be used. You may want to upgrade to new releases to take advantage of new features or MEI may provide custom features or bug patches for previous releases. During the machine production phase, you will want to guarantee software configuration consistency. MEI recommends using the InstallShield release package, a third party installer program, or batch scripts to install your application code and MEI’s software onto your machine.

You will also want to guarantee that the controller’s flash memory configuration and the SynqNet node runtime FPGA images are consistent. To load the flash, you could automatically download the controller firmware (.bin), FPGA (.fpg) image(s), and node runtime FPGA (.sff) images during software installation OR during your application initialization. For example, the flash.exe and sqNodeFlash.exe utilities could be executed from an installer or batch script during software installation. Included in the XMP\Apps directory, is a sample program called “initFlsh.c” that demonstrates how to read the controller’s firmware/FPGA versions, check if they match the desired configuration, and download the correct versions (if needed).

Also, you can create your own custom firmware file by saving configurations to flash, and uploading the firmware file to your hard drive. The firmware contains a “userVersion” field, so you can keep track of your custom configured files. Using this technique, the firmware can be configured with Motion Console, uploaded to a file (myfirm.bin) and downloaded to future machines using Motion Console, flash.exe or your application.


Controller Binary Images

.

Controller Binary Images

All SynqNet controllers are shipped with a simple, default flash image, that allows the controller to be recognized by the MPI library. The default flash memory does not contain processor or FPGA code. You must download firmware and FPGA code to the controller's flash memory. You can use Motion Console or the flash.exe utility to download firmware (.bin) and FPGA (.fpg) images. Motion Console will automatically prompt you to download the firmware to a new controller. The firmware file (.bin) contains the binary code and configuration data for the controller's processor. The FPGA file (.fpg) contains the binary code for the local FPGA (Rincon). During firmware download, the software will identify the local FPGA type (Rincon) and download the appropriate binary (.fpg file) image.

The controller's processor code, FPGA code, and configuration data are stored in the controller's Flash memory. The code and configuration is loaded during power-on or when the controller is reset. The Flash memory can be updated with the Flash.exe utility, Motion Console, or application code.

A node FPGA binary image (boot or runtime) is required for a SynqNet controller to communicate with a SynqNet node over a SynqNet network. For more information about how the boot and runtime images are used to communicate with the SynqNet controller, please see the Node Binary Images section.


Controller Binary Files Table

.

Controller Binary Files Table

Motion Engineering's MPI software releases include FPGA images and DSP firmware for SynqNet controllers. The FPGA image contains the code to send/receive network data. The DSP firmware contains code and data to operate the controller's processor. The controller's FPGA image is automatically downloaded when the controller firmware is downloaded. The MPI automatically reads the controller type and selects the appropriate FPGA image type (9601, 9201, etc.). The MPI selects the FPGA version based on the software release version. Controller firmware and FPGA can be downloaded with the flash.exe utility or Motion Console.

Controller Name | PN | FPGA | Firmware
XMP-SynqNet-PMC | T009-0001* | N/A | N/A
 | T009-0002 | xxx_9601.fpg | XMPxxxxx.bin
XMP-SynqNet-PCI | T014-0001, T014-0002 | xxx_9201.fpg | XMPxxxxx.bin
XMP-SynqNet-NM | T100-0001 | xxx_9201.fpg | XMPxxxxx.bin
XMP-SynqNet-CPCI | T011-0003, T011-0004 | xxx_9201.fpg | XMPxxxxx.bin
* T009-0001 XMP-SynqNet-PMC controllers are not supported by software releases after the 20021212.1.3 release. Please contact MEI for other compatibility options.

It is possible to manually download a specific FPGA file (version) with the flash.exe utility or Motion Console. In some special cases, using a different FPGA file may be necessary. Using different FPGA images should only be downloaded when directed by an MEI applications engineer.


Drive Binary Images

.

Drive Binary Images

Some SynqNet nodes have a high speed serial or parallel memory interface to an integrated drive processor. The FPGA binary images for SynqNet nodes with integrated drives (ex: Node 1 in diagram below), have the same functionality as other SynqNet nodes (Node 0). Please see the Node Binary Images section for information about the Node FPGA binary boot and runtime images.

SynqNet nodes with drives will need binary code for the drive processor(s). Some node manufacturers will install the drive firmware at the factory. Other node manufacturers may require customers to download the drive firmware images. For hardware that supports downloading of firmware, the drive firmware can be downloaded with Motion Console, the sqNodeFlash.exe utility, or application code. For drive manufacturer contact information, please see the list of SynqNet Drive Partners.


Node Binary Files: Boot Table

.

Node Binary Files: Boot Table

Motion Engineering's SynqNet nodes are shipped with boot FPGA images. The boot images are programmed on the controller at the factory and are not distributed with the software releases. The boot image contains minimal functionality to allow the node to be accessed by the SynqNet controller for the purpose of downloading a runtime image. To have full functionality of the node, you will need to download the appropriate FPGA (runtime) image (*.sff). See the Node Binary Files: Product Table.

For more information about node FPGA images (boot and runtime), please see the Binary Images section.

Filename | Node Manufacturer | Node Series | Node Type | Comments
C0FEB011_xxxx.mcs | MEI | RMB-10V | C0FEA001 | Outrigger, XC2S150-5FG256
C0FEB012_xxxx.mcs | Panasonic | Minas-B | 0050001 | Outrigger, XC2S150-5PQ208
C0FEB014_xxxx.sff | Yaskawa Yaskawa Yaskawa Yaskawa Kollmorgen Kollmorgen Glentek Sanyo Trust TA801 Trust TA802 | Sigma3-71 Sigma3-72 DMD-4 DMD-3 DASA CD Omega Q-Series Trust Trust | 00020010; -1 00020010; -0 00020001; -0 00020001; -1 00030001 00030010 00060001 00070001 00090001; -0, -1 00090001; -3, -4 | Bowsprit, XC2S200E-6PQ208
C0FEB021_xxxx.mcs | MEI | RMB-10V | COFEA001 COFEA002 COFEA003 | Outrigger, XC2S200-5FG256
C0FEB022_xxxx.mcs | MEI | RMB-10V2 | COFEA001 | Bowsprit, XC2S300E-6FT256
C0FEB023_xxxx.mcs | MEI | SQUIM |  | Bowsprit, XC2S300E-6FT256
C0FEB024_xxxx.mcs | MEI | SGDG |  | Outrigger, XC2S150-5PQ208


Node Binary Files: Features Table

.

Node Binary Files: Features Table

The following table summarizes the supported features of each FPGA (runtime) image. One of the following runtime images must be downloaded to a SynqNet node for normal operation over a SynqNet network. If you are not sure which runtime image should be downloaded for a particular SynqNet node, please refer to the Node Binary Files: Product Table.

For more information about node FPGA images (boot and runtime), please see the Binary Images section.

FILENAME
C0FE0011_xxxx.sff | 4 | 0 | 1 | 1 | 0 | 4 | 8 | 8 | 5 | 0 | 0 | 0 | 5 | 2 | 0
C0FE0014_xxxx.sff | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 16 | 5 | 0 | 0 | 0 | 3 | 2 | 0
C0FE0018_xxxx.sff | 4 | 4 | 1 | 1 | 0 | 0 | 0 | 6* | 2 | 0 | 0 | 0 | 5 | 0 | 0
C0FE0019_xxxx.sff | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 16 | 6 | 0 | 0 | 0 | 3 | 2 | 0
C0FE0021_xxxx.sff | 2 | 0 | 1 | 1 | 0 | 2 | 4 | 5 | 5 | 0 | 0 | 0 | 3 | 0 | 0
C0FE0024_xxxx.sff | 2 | 1 | 1 | 1 | 1 | 0 | 0 | 8 | 6 | 0 | 0 | 0 | 4 | 2 | 0
C0FE0025_xxxx.sff | 1 | 0 | 1 | 1 | 0 | 1 | 2 | 5 | 5 | 0 | 0 | 0 | 2 | 2 | 0
C0FE0026_xxxx.sff | 4 | 0 | 1 | 1 | 0 | 0 | 8 | 3 | 5 | 0 | 0 | 0 | 0 | 0 | 0
C0FE0027_xxxx.sff | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 16 | 6 | 0 | 0 | 0 | 4 | 2 | 0
C0FE0029_xxxx.sff | 4 | 0 | 4 | 1 | 0 | 4 | 8 | 8 | 5 | 0 | 0 | 0 | 5 | 2 | 0
C0FE002B_xxxx.sff | 1 | 0 | 1 | 1 | 0 | 0 | 2 | 8 | 2 | 0 | 0 | 0 | 2 | 2 | 0
C0FE002C_xxxx.sff | 4 | 0 | 4 | 1 | 0 | 4 | 8 | 8 | 5 | 0 | 0 | 0 | 9 | 2 | 0
C0FE002D_xxxx.sff | 2 | 0 | 2 | 1 | 0 | 8 | 4 | 16 | 2 | 0 | 0 | 0 | 2 | 2 | 0
* = motor 0, 1 only


Node Binary Files: Product Table

.

Node Binary Files: Product Table

Motion Engineering's SynqNet nodes are shipped with boot FPGA images. The boot image contains minimal functionality to allow the node to be accessed by the SynqNet controller for the purpose of downloading a runtime image. To have full functionality of the node, you will need to download the appropriate FPGA (runtime) image (*.sff). The table below provides a breakdown of the various SynqNet nodes and their appropriate runtime images.

NOTE: Binary Image Files that are released by SynqNet drive partners (not by MEI) are not shown in this table.

For a breakdown of the features supported on each binary file, please refer to the Node Binary Files: Features Table.

For more information about node FPGA images (boot and runtime), please see the Binary Images section.

Node Name Node Type, Option | Comments | Binary Image File | Distributed in the MPI?
Glentek Omega 0060001 0000 | 1 motor, parallel | C0FE0019_xxxx.sff | Y
Kollmorgen DASA 0030001 0000 | 2 motors, serial | C0FE0024_xxxx.sff | Y
Kollmorgen CD 0030010 0000 | 1 motor, serial | C0FE0027_xxxx.sff | Y
MEI RMB-10V COFEA001 0000 | 4 DACs, no feedback 2 motors, analog 1 motor, analog 4 motors, analog | C0FE0026_xxxx.sff C0FE0021_xxxx.sff C0FE0025_xxxx.sff C0FE0011_xxxx.mcs | Y Y Y N
MEI RMB-10V COFEA001 0001* | 2 motors, analog | C0FE0021_xxxx.sff | Y
MEI RMB-10V COFEA001 0002* | 1 motor, analog | C0FE0025_xxxx.sff | Y
MEI RMB-10V2 COFEA001 0000 | 4 motors, analog 4 motors, analog, SSI | C0FE0029_xxxx.sff C0FE002C_xxxx.sff | Y Y
Panasonic Minas-B 0050001 0000 | 1 motor, parallel | C0FE0014_xxxx.sff | Y
Sanyo Denki Q-Series 00070001 0000 | 1 motor, parallel | C0FE0019_xxxx.sff | Y
Trust TA801 00090001 0000 00090001 0001 | 1 motor, analog | C0FE002D_xxxx.sff | Y
Trust TA802 00090001 0003 00090001 0004 | 2 motors, analog | C0FE002D_xxxx.sff | Y
Yaskawa DMD-4 00020001 0000 | 4 motors, serial | C0FE0018_xxxx.sff | Y
Yaskawa DMD-3 00020001 0001 | 3 motors, serial | C0FE0018_xxxx.sff | Y
Yaskawa Sigma3-71 00020010 0000 | 1 motor, parallel** | C0FE0019_xxxx.sff C0FE0028_xxxx.sff | Y Y
Yaskawa Sigma3-72 00020010 0001 | 1 motor, parallel | C0FE0019_xxxx.sff | Y
* Currently there are no products that have been shipped with these configurations.
** COFE0028 is no longer supported for the Sigma3-71.

Downloading the Node FPGA

For SynqNet Phase 1

Open a Command Prompt window and go to the following directory to download the proper *.sff file: C:\MEI\XMP\bin\WinNT\rmbFlash -rmb 0 -file ..\c0fe0001_20020430.sff

The selected FPGA file has been downloaded after all of the pages have been counted.

Refresh Motion Console by maximizing the screen. The following screen should appear. Notice that the Version IDs have changed to reflect the version of the downloaded FPGA.

For SynqNet Phase 2

Please refer to the sqNodeFlash Utility.


Node Binary Images (boot vs. runtime)

.

Node Binary Images (boot vs. runtime)

All SynqNet nodes are shipped with a boot FPGA binary image. Some SynqNet node manufacturers may also load the FPGA runtime image in the node's flash memory. The boot image contains just enough logic for the SynqNet controller to identify and communicate with the node over the SynqNet network. This allows the host to communicate with the node after the network has been initialized for the first time. After network initialization, the runtime image should be downloaded to the node. The runtime image contains the logic for full operation.

Once the hardware has been connected and the system is powered up for the first time, the SynqNet controller will attempt to find all the nodes on the SynqNet network. The FPGA on the controller enables it to talk to the node(s) on the network that have a boot image. Since each node is shipped with a default boot image and possibly a default runtime image, the controller can immediately talk to the node and retrieve basic information.

The node FPGA boot image will enable the controller to do the following:

  • Identify all of the nodes on a SynqNet network
  • Determine if the node is operating from the boot image (not the runtime image)
  • Identify the boot image version
  • Download a runtime image to the node

If a controller is unable to find a node on the network, it may be a result of either a bad cable, improper wiring, or other hardware problem.

Once the controller has found all of the nodes on the network, you will need to download the runtime image to the nodes before you can move a motor. If the node manufacturer loaded the runtime image at the factory, a runtime image does not need to be downloaded. But, you should check the node FPGA version to make sure it is appropriate for your application. Please refer to the Node Binary Files: Product Table.

You can download a runtime image, by one of the following ways:

  • MPI
  • Utility (sqNodeFlash.exe)
  • Motion Console

The Node FPGA runtime image contains the following:

  • Interface code for SynqNet (SQMAC)
  • Interface code for digital and analog I/O
  • Interface code for Drive Modules

Once the runtime image has been downloaded, the boot image is no longer needed and the runtime image is used for normal operation. See diagram below.


Cable Length

.

Cable Length

The SynqNet cable lengths are derived from the measured propogation delays during network initialization. This information is used to determine the spacing between packets for each node. SynqNet networks can have up to 32 nodes and cables can be up to 100 meters in length. By measuring the actual propogation delays and optimizing the packet spacing, the network performance and actual bandwidth is improved.

Typical CAT5 cable propogation delays are roughly 0.005 microsec per meter. Actual values are affected by cable construction and will vary, but the variation will be small for any reasonable cable. The propogation delay can be estimated by a cable propogation velocity of 70% the speed of light, using the formula:
delay = meters * 1,000,000 / (.7 * 299,722,458)

For example, here are some rough values for various cable lengths:

Length (meters) | Time (microsec)
1 | 0.005
10 | 0.048
25 | 0.119
50 | 0.238
100 | 0.477

Measurement

During SynqNet initialization the controller sends a packet to each node, waits for the node to repeat the packet back, and measures the elapsed time. In ring topologies, the last cable requires the packet to travel around the network and return to the controller. The controller reads the clock values for each measurement packet and stores the values. The MPI converts the raw time values into cable length (meters). The MPI also uses the propogation delay values to calculate the packet spacing.

The propogation delay measurement is based on the SynqNet clock rate, which is 25MHz (period = 0.040 microseconds). At 25MHz, the clock resolution is 0.040 microseconds, which translates to roughly 8 meters. The accuracy is based on the forwarding variations for each node (+/- 1 clock) and the resolution of the propogation delay timer (+/- 0.5 clocks). The accuracy for each cable can be determined from:
accuracy = ((.020 microsec) + (.040 microsec * nodeCount)) / 2

in terms of meters:
accuracy = ((4 meters) + (8 meters * nodeCount)) / 2

For example, a network with 3 nodes has following cable length accuracies:

Cable | Resolution + Variation = Accuracy
0 | (.02 + .04)/2 = +/- .03 microsec (+/- 6 meters)
1 | (.02 + .08)/2 = +/- .05 microsec (+/- 10 meters)
2 | (.02 + .12)/2 = +/- .07 microsec (+/- 14 meters)

To read the measured cable lengths from the MPI, see meiSynqNetInfo(...).

Configuration

In some high performance networks, the system designer may want to optimize the packet spacing by configuring the cable length values. Most networks will not need this type of optimization. The SynqNet network has maximum, minimum, and nominal cable length configurations. Changing these configurations will affect the packet spacing calculations and the topology mismatch checking. During network initialization, if a measured cable length is not between the minimum and maximum values, a Topology Mismatch error will be returned by the MPI.

Cable Length Check

During network initialization, the nominal cable lengths will be measured and the minimum and maximum values will be calculated. The minimum cable length will be set to the nominal - 8 meters. The maximum cable length will be set to the nominal + 8 meters. During subsequent network initializations, the measured cable length will be compared to the minimum and maximum values. If the measured cable length is not between the minimum and maximum values, a Topology Mismatch error will be returned by the MPI. To recover, use a control reset to clear the previous minimum and maximum cable values, re-initialize the network, and set the new min/max values.


Compatibility

.

Compatibility

The MEI software has compatibility checking. If there is a compatibility problem between software components an error code will be returned.

If an application (Motion Console and Motion Scope are applications too) and MPI DLL are NOT compatible, the error message "Control: application not compatible with MPI DLL" will be returned. To correct the problem, you can recompile your application with the appropriate MPI import library OR install the proper MPI DLL.

If the MPI DLL and firmware versions are NOT compatible, the error message "Control: firmware version mismatch" will be returned. The user or application must download the appropriate firmware to correct the problem. The DLL and firmware versions can be determined with the version.exe utility, Motion Console, or application code.

If the controller flash memory has NOT been configured, the error message "Control: no firmware found (factory default)" will be returned. The user or application must download the appropriate XMP firmware and FPGA images to correct the problem. Firmware and FPGA images can be downloaded from Motion Console, flash.exe, or application code.

For example, if Motion Console detects that the controller is in the factory default configuration (no firmware) or if the MPI DLL is not compatible with the firmware, it will prompt the user to download firmware:

Click Yes. Motion Console will then prompt you for the firmware file. Notice that the necessary firmware version is shown at the top of the window. Browse and select the appropriate firmware file (.bin).

The firmware is stored in the mei\xmp\bin directory (by default):

Click Open.

To download the firmware file to the controller, click Yes.

If the SynqNet Node Runtime FPGA image is NOT compatible with the software version, an error message will be returned. The user or application must download the appropriate node runtime FPGA image(s) to correct the problem. SynqNet Node FPGA images can be downloaded from Motion Console, sqNodeFlash.exe, or application code.

For example, if Motion Console detects that the SynqNet Node Runtime FPGA image is NOT compatible, it will prompt the user to download an FPGA image:

Click Yes. Motion Console will then prompt you to download the binary image. Select the Node FPGA and click Browse...

Select the appropriate file for the Node type (RMB-10v2):

Then press Open.

To download the firmware file to the controller, click Download and a downloading progress bar will then be shown.

When the download is complete, you can close the download window by pressing the Close button.


Node Binary Files: Boot Table

.

Node Binary Files: Boot Table

Motion Engineering's SynqNet nodes are shipped with boot FPGA images. The boot images are programmed on the controller at the factory and are not distributed with the software releases. The boot image contains minimal functionality to allow the node to be accessed by the SynqNet controller for the purpose of downloading a runtime image. To have full functionality of the node, you will need to download the appropriate FPGA (runtime) image (*.sff). See the Node Binary Files: Product Table.

For more information about node FPGA images (boot and runtime), please see the Binary Images section.

Filename | Node Manufacturer | Node Series | Node Type | Comments
C0FEB011_xxxx.mcs | MEI | RMB-10V | C0FEA001 C0FEA002 C0FEA003 | Outrigger, XC2S150-5FG256
C0FEB012_xxxx.mcs | Panasonic | Minas-B | 00020010 | Outrigger, XC2S150-5PQ208
C0FEB014_xxxx.sff | Yaskawa Yaskawa Kollmorgen Kollmorgen Glentek | Sigma-III DMD/IDM-4 DASA CD Omega | 00020010 00020001 00030001 00030010 00060001 | Bowsprit, XC2S200E-6PQ208
C0FEB021_xxxx.mcs | MEI | RMB-10V | COFEA001 COFEA002 COFEA003 | Outrigger, XC2S200-5FG256
C0FEB022_xxxx.mcs | MEI | RMB-10V2 | COFEA001 | Bowsprit, XC2S300E-6FT256
C0FEB023_xxxx.mcs | MEI | SQUIM |  | Bowsprit, XC2S300E-6FT256
C0FEB024_xxxx.mcs | MEI | SGDG |  | Outrigger, XC2S150-5PQ208


CRC Error Counter

.

CRC Error Counter

The Cyclic Redundancy Check (CRC) is a way of detecting small changes in blocks of data. This type of error detection is especially useful when sending packet data across a network such as SynqNet. Whereas the Packet Error Counter checks for missing or invalid packets, the CRC Error Counter checks the validity of the data inside the packets.

Each node has a CRC Error Counter at each port (IN and OUT), although packets are only checked at either the node's IN port or OUT port, depending on where the packets are received.

The controller has a CRC Error Counter at each port (IN and OUT), although packets are checked at the controller's IN port and/or OUT port depending on where the packets are received. For string topologies, packets are received at the controller's OUT port only. For ring topologies, packets are received at the controller's OUT port and IN port, depending on the location of the redundant cable. For example, in a ring topology if the last cable (from the last node to the controller's IN port) is idle, then no data is received at the controller's IN port and the CRC counter at the IN port will remain idle.

The CRC error count will increment by one for bad packets that are addressed to other nodes (or to the controller) or for packets received with a bad CRC. "Lost" packets, which never reach the node, do not increment the CRC error count (it increments the Packet Error Counter). The counters are unsigned, 8-bit values and saturate at a maximum of 255 (0xFF) errors. The counter also goes back to zero after a hardware reset and can be cleared by controller software. Unlike packet errors, CRC errors are NOT node-specific (i.e. All packets are checked at each node, as well as at the controller).

NOTE: Data errors in the start delimiter may prevent the CRC errors from being counted.

In Motion Console

Node CRC Error Counters

In Motion Console, you can see the node's CRC Error Counters in the SqNode Summary Window. It counts the number of upstream CRC Errors for each port.

Controller CRC Error Counters

In Motion Console, you can see the controller's CRC Error Counter in the SynqNet Summary Window. It counts the number of upstream CRC Errors for each port.

See Also

Packet Error Counter
SynqNet Fault Recovery
SynqNet Failure


Default Initialization Routine

.

Default Initialization Routine

Due to blank Node Identification data in flash memory, the default network verification will "Fail." Another reason for failure is due to a mismatch between the verify data in flash memory and the discovered network configuration. In these cases the DSP must request for the MPI to complete the DISCOVERY Network Phase and take the right-hand path of execution (Figure 2). This requires the MPI to:

  • Request Drive Resource information from each node on the network.
  • Use this information to configure the controller cyclic data buffers.
  • Configure the default FPGA configuration buffers.
  • Set any drive specific values and signal the DSP to transition to the CYCLIC Phase.
  • Signal the DSP to transmit FPGA Configuration data.
  • Initiate Drive Specific Initialization routines.
  • Return control to Host application.

For safety reasons, because the network verification failed, the MPI Flash object will be disabled (please see Network Confirmation section for more information).

If the network verification failed due to a configuration mismatch, the mpiControlInit(...) method must return an error code. The error code is to alert the motion application that network verification has failed.

This default initialization will be executed whenever verification of the network fails.


Default Packet Configuration

.

Default Packet Configuration

Node | Controller

Node

SynqNet controllers are able to configure the packet payloads of each node. This feature allows you to optimize the network performance for any given system by sending only the data that is actually used. Or stated the other way, configurable packets allow a minimal data set in most cases, but expand the data set when additional step, capture, compare, I/O, or other special features are required.

After a reset, the SynqNet node FPGA defaults to a fixed packet configuration. This configuration supports ONLY the service channel fields of the CONTROL and STATUS packets (the DEMAND and FEEDBACK packets are not allowed until Cylic phase). During discovery, the controller will write the desired packet configurations to each node, where it is stored in RAM (one RAM for each configurable packet on each node). Details of each configuration ram, and the rules for configuration each packet, are defined in the sqMac datasheet.

Please note that packet configurations are determined by the application, NOT by the hardware. Any given hardware can support many configurations. Only the system designer knows what data is relevant to a given system.

Also note that in general, any configuration can be commanded on any node. If the node lacks support for some input value, it will return garbage. If the node lacks support for some output value, the output data will be ignored.

Controller

SynqNet controllers will build packet structures in memory that match the configured payload of each packet for each node. The packet structures are influenced by controller's memory read and write alignment restrictions as well as the node packet configuration rules. For example, a controller based on the Sharc DSP should structure all data to be 16-bit or 32-bit fields on natural boundaries. Thus a node with one IO input bit and one encoder feedback should have a 16-bit ioInput field on a natural 16-bit boundary in the STATUS packet, and a 32-bit feedback field on a natural 32-bit boundary in the FEEDBACK packet. The Sharc doesn't directly support byte data, so 8-bit fields are not recommended (although allowed by the node hardware). In some cases, null fields may be required to fill in unusable portions of the packet structure in order to meet the controller processor memory alignment rules.

Note the contoller's SynqNet interface FPGA is transparent to the packet payloads, and adds no restrictions to the packet configuration process. The FPGA simply transmits or receives a packet of given length to or from a given address, without any consideration of the data field structure within the packet. The Rincon1 controller does require the total packet length to be a multiple of 4 bytes.


Drive Parameters

.

Drive Parameters

Under Construction.
Coming Soon!


CRC Error Counters

.

CRC Error Counters

Each node also has a CRC error counter for each port (IN and OUT). This counter increments for any packet received with a bad CRC. "Lost" packets, which never reach the node, will not increment the CRC error count. The CRC error count will only increment for bad packets addressed to other nodes (or to the controller).

For more information about packet errors, please see the Node Packet Errors and Controller Packet Errors sections.


Controller Error Counters

.

Controller Error Counters

The controller has a Packet Error Count and Packet Error Rate for each node (up to 32 of each). These counters function exactly the same fashion as the node counters (except 2 packets per controller cycle are sent by each node).

The controller also has one CRC error counter, which reflects the combined total of packets with bad CRC on both IN and OUT ports.


Node Error Counters

.

Node Error Counters

The Packet Error Counter on each node checks to make sure that it received all three of its packets (sent from the controller) during each SynqNet cycle. This counter is used for long-term performance monitoring (ex: Have any errors occured since startup?). For each invalid or missing packet, the Packet Error Counter increments by one. The counter is reset to zero after a hardware reset or can be manually reset in Motion Console. The counter saturates at 255 (0xFF).

There is also a Packet Error Rate Counter on each node, which increments by one for every packet error received, and decrements by one for every 16th valid packet received. This provides a "pessimistic" or "rate" counter function for the fault recovery and failure logic. If communication fails completely, the Packet Error Rate Count will match the number of packets lost. If only 1 packet in 100 is bad, the counter will occasionally increment to 1 and then decrement back to zero. If 1 packet out of 10 is bad, the counter will gradually increment until fault and/or fail thresholds are reached. The counter is an unsigned 8-bit value, and saturates at 0xFF. It is reset to zero after a hardware reset or can be manually reset in Motion Console. The counter saturates at 255 (0xFF).

For more information about fault thresholds, see the SynqNet Fault Recovery section.

For more information about fail thresholds, see the SynqNet Failure section.


Configuration Management FAQs

.

Configuration Management FAQs

- Why do I need to download firmware to my controller?

- Why do I need to download runtime FPGA images to my SynqNet nodes?

- Why can’t MEI download firmware to my controller at the factory?

- What if I need to upgrade software in the field?

- Can I modify the FPGA (.fpg and .sff) files?

Why do I need to download firmware to my controller?

Only the machine developer knows what firmware version and configuration works with their application. By downloading firmware directly, you have complete control over your development and release versions.

Why do I need to download runtime FPGA images to my SynqNet nodes?

The node FPGA runtime images are tested and distributed with the software package. Using node FPGA runtime images from other software releases might work properly, but may not contain all the features needed for a particular software release. To guarantee compatibility, you should always use the node FPGA runtime images included with the software package.

Why can’t MEI download firmware to my controller at the factory?

MEI can download your firmware, but it is expensive and causes several problems:

  1. You would need a custom part number for each controller with a different firmware image. Even if you use the same controller hardware in several machines, each version would need to be ordered, purchased, tracked, and stocked separately.

  2. Changing a firmware image (version or configuration) would require a new part number. This causes transition problems between “old” parts and “new” parts.

  3. Repairs and replacements are much more complicated.

  4. Field upgrades are not possible. Controllers must be returned to the factory to receive new firmware and a new part number.

What if I need to upgrade software in the field?

If you configure the flash memory as part of your application or installation, then it is very easy to upgrade software and/or firmware in the field. If you do not, you will need to manually update the flash memory.

Can I modify the FPGA (.fpg and .sff) files?

No. These files are binary and do not contain any configuration data.


SynqNet Technology FAQs Home

.

SynqNet Technology FAQs

- What is the difference between a Node and a SynqNet Block?

- What topologies are supported by SynqNet?

- Can I control an analog motor with SynqNet?

What is the difference between a Node and a SynqNet (Motion) Block?

"All SynqNet Blocks are Nodes, but not all Nodes are SynqNet Blocks." A node is basically a place on a network where something happens. A motion block refers to a specific type of node on a SynqNet Motion Network. SynqNet amplifiers/drives and RMB-10Vs are examples of synqnet blocks. A typical SynqNet Motion Network consists of a motion controller, one or more synqnet blocks, and one or more axes.

What topologies does SynqNet support?

Currently, only the string and ring topologies are supported by SynqNet. In the future, SynqNet will support additional topologies such as a Ring of Rings, Dual String, and Tree topology. For more information about the string and ring topologies, click here.

Can I control an analog motor with SynqNet?

Yes. You can connect an analog motor to a SynqNet Network with an RMB-10V.
Return to SynqNet Technology


SynqNet Features / Performance

.

SynqNet Features / Performance

SynqNet is the only motion control network that offers all of the following:

  • Centralized software and control with distributed hardware.

  • Choice of motor/drive vendors. Choose from a variety of SynqNet motor/drive vendors (Yaskawa, AMC, Panasonic, etc.).

  • Support for up to 32 coordinated axes.

  • Support for up to 32 coordinated nodes on one network.

  • Support for up to 16 user limits per motor.

  • Support for up to 16 bits of configurable I/O.

  • Network bandwidth for torque updates up to 48kHz (4axes)

  • Real-time digital network connection.

  • Plug 'n' Play nodes. SqNode library automatically identifies and configures nodes by type.

  • Automatic network configuration and integrity check.

  • Network Fault Recovery with Ring Topology -
    In a ring topology, if any one cable fails, the network will redirect packet data around the break and notify the application with an event. The location of the break can be determined by the application.

  • Failed Node Tolerance - If one or more nodes fail, the network will continue to operate in SYNQ mode, communicating with the good nodes.

  • Scalable Networking Timing -
    The MPI automatically scales the packet timing based on the node number and type. The maximum controller/network sample rate and servo control latency depends on controller/network load. The minumum sample rate is 1kHz.

  • The use of inexpensive cable to communicate between controller and drive (100baseT Ethernet cable), which can transfer more data than traditional serial cables, thereby reducing wiring and maintenance costs.

  • Cable Length -
    Network cable lengths of up to 100 meters are supported. The network timing calculations automatically compensate for various cable lengths. The MPI also supports configurable cable lengths.

  • Software Configurable Data Packets -
    The MPI automatically configures the packets during network initialization based on the node type. The MPI also supports user configurable packets.

  • String (open or closed) and Ring topologies are supported.

  • Time-Based Capture -
    This is a special technique to derive a captured position from a node’s latched time value, the controller’s actual position, and the previous sample’s actual position. This feature is useful for high accuracy capturing when the controller reads position feedback from a drive (not from the node’s FPGA).

  • Centralized software tools for drive configuration, tuning, and diagnostics that are in real-time. Motion Console, Motion Scope, VM3, Control Filter Toolkit, and MPX.

  • Remote diagnostics for nodes and drives.

  • Drive setup, configuration, and current loop tuning through the network, from a centralized PC (host). This eliminates the time consuming and error-prone process of connecting a serial cable to each drive in the system in succession.

  • Ability to develop custom nodes.

  • Widely available network components. (i.e. standard connectors and cables are used).

  • Node-to-Node transformer isolation for robust noise immunity.

  • Bad Packet Feedback Compensation -
    The controller maintains the previous sample’s actual position and calculates the actual velocity. If the feedback packet is corrupted, the controller will interpolate the expected actual position. This feature prevents motor jumps due to network data integrity problems.

  • Topology Save to Flash -
    The network topology can be saved to the controller's flash. After a reset, the controller will automatically initialize the network and verify that the number and type of discovered nodes match the expected topology.

  • SynqNet eliminates the ground loops and common-mode electrical noise that are the root cause of many intermittent and systematic motion performance problems.

  • Node FPGA download via SynqNet -
    RMB-10v (via Outrigger circuit) and all other supported nodes (via Bowsprit circuit).


Fault and Fail Limits

.

Fault and Fail Limits

Each node contains configurable fault and fail limits. By default, the downstream fault limit has an error rate of 6 (all packets lost in two consecutive SYNQ periods). When the fault limit is reached, the node will attempt a fault recovery by switching its upstream port. The default fail limit is an error rate of 12 (two additional periods with all packets lost). When the fail limit is reached, the node will enter the SYNQ Lost state and disable its outputs. A service command can configure these limits for any value between 1 and 0xFF. Similarly, the controller fault limit defaults to an error rate of 4 (two periods) and the fail limit defaults to an error rate of 8 (two additional periods). These limits may be configured between 1 and 0xFF.


Packet Error Fault and Fail Limits

.

Packet Error Fault and Fail Limits

Node | Controller

Node

Each node contains configurable Packet Error Fault and Fail Limits. By default, each node has a Packet Error Fault Limit of 6 (all packets lost in two consecutive SYNQ periods).

In Ring topologies, when the fault limit is reached, the node will attempt a fault recovery by switching to its upstream port using the redundant link.

By default, the Packet Error Fail Limit has an error rate of 12 (all packets lost in four consecutive SYNQ periods). When the fail limit is reached, the node will enter the SYNQ Lost state and disable its outputs.

NOTE: A service command can configure these limits for any value between 1 and 0xFF.

The diagrams below help explain what happens when packet errors reach fault and fail limits on the node.

In Motion Console

The SqNode Summary Window displays the Packet Error information for each node.

SynqNet Cycle 1

During the first SynqNet cycle, all three packets for N0 are bad packets, therefore the packet error for N0 is 3. Notice that the Packet Error Count for N1 is zero, because packet errors are node-specific (unlike CRC errors).

SynqNet Cycle 2

During the second consecutive SynqNet cycle, there are three more bad packets for N0. Therefore, the packet error for N0 is 6. The node has now reached its Packet Error Fault Limit threshold. The default Packet Error Fault Limit has 6 packet errors.

In Ring topologies, once the Fault Limit has been reached, the controller will attempt to send the packets using the redundant link via its IN port.

SynqNet Cycle 3

If the node reaches its Packet Error Fail Limit, a network failure will occur. The node will enter the SYNQ Lost state and disable its outputs. The default Packet Error Fault Limit is 12 packet errors.

Controller

The functionality of the Packet Error Fault and Fail Limits for the controller is the same as the functionality for the node except the defaults are different.

The controller's default Packet Error Fault Limit has an error rate of 4 (all packets lost in two consecutive SYNQ periods).

The controller's default Packet Error Fail Limit has an error rate of 8 (all packets lost in four consecutive SYNQ periods).

These limits may be configured between 1 and 0xFF.

In Motion Console

The SynqNet Summary Window displays the Packet Error information for the controller.


FPGA C0FE0011

.

FPGA- C0FE0011

Number of Motors: 4
Number of Secondary Encoders: 1
Supported Drives: RMB-10V

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 4 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 5 |  |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 8 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 5 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | NO | 0 |  |
 |  | Time | NO |  |  |


FPGA C0FE0014

.

FPGA- C0FE0014

Number of Motors: 1
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 16 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 5 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 0 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | NO | 0 |  |
 |  | Time | NO |  |  |


FPGA C0FE0018

.

FPGA- C0FE0018

Number of Motors: 4
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 6 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 5 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 0 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | NO | 0 |  |
 |  | Time | NO |  |  |


FPGA C0FE0019

.

FPGA- C0FE0019

Number of Motors: 1
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 1 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 16 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 1 | pin(s) per motor |
 |  | Brake Drive |  | 1 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 0 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE0021

.

FPGA- C0FE0021

Number of Motors: 2
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 2 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 3 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 4 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 3 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE0024

.

FPGA- C0FE0024

Number of Motors: 2
Number of Secondary Encoders: 0
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 1 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 1 | pin(s) per motor |
 |  | Brake Drive |  | 1 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 0 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE0025

.

FPGA- C0FE0025

Number of Motors: 1
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 1 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 2 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  | Include 1 register when available
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE0026

.

FPGA- C0FE0026

Number of Motors: 4
Number of Secondary Encoders: 0
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 4 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 8 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 3 |  |
 | Capture | Position | NO | 0 | per encoder |
 |  | Time | NO |  |  |
 | Compare | Position | NO | 0 |  |
 |  | Time | NO |  |  |


FPGA C0FE0027

.

FPGA- C0FE0027

Number of Motors: 1
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 1 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 16 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 1 | pin(s) per motor |
 |  | Brake Drive |  | 1 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 0 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE0029

.

FPGA- C0FE0029

Number of Motors: 4
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 4 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 5 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 8 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  | Include 4 registers when available
 | Encoder |  |  | 5 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | NO | 0 |  | Include 1 register when available
 |  | Time | NO


FPGA C0FE002B

.

FPGA- C0FE002B

Number of Motors: 1
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 0 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 2 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | NO | 0 |  |
 |  | Time | NO |  |  |


FPGA C0FE002C

.

FPGA- C0FE002C

Number of Motors: 4
Number of Secondary Encoders: 1
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 4 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 8 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 5 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 0 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 8 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 0 |  |
 | Encoder |  |  | 5 |  |
 | Capture | Position | YES | 1 | per encoder | Include SSI support on encoder 0-3 only
 |  | Time | YES
 | Compare | Position | YES | 0 |  | Include 1 register when available
 |  | Time | YES


FPGA C0FE002D

.

FPGA- C0FE002D

Number of Motors: 2
Number of Secondary Encoders: 0
Supported Drives:

 | Feature |  |  | Quantity | Units | Comments
sqNode | sqMac |  |  | 1 | per node |
 | Serial Eeprom |  |  | 1 |  |
 | UART |  |  | 0 |  |
 | ADC |  |  | 8 |  |
 | FPGA Download |  |  | 0 |  |
Drive / Motor | Motor I/O (general purpose) |  |  | 16 | pin(s) per motor |
 | Dedicated I/O Bits (Group of 16) |  |  | 2 | group(s) per node |
 | Dedicated I/O Pins (Hardware Pins) | Brake Applied |  | 1 | pin(s) per motor |
 |  | Brake Drive |  | 0 |  |
 |  | Amp Enable |  | 1 |  |
 |  | Amp Fault |  | 1 |  |
 |  | Home |  | 1 |  |
 |  | Positive Limit |  | 1 |  |
 |  | Negative Limit |  | 1 |  |
 |  | Encoder Index |  | 1 | per encoder |
 | DAC |  |  | 4 | per node |
 | 1/N |  |  | 0 |  |
 | 1/T |  |  | 0 |  |
 | Pulse |  |  | 2 |  |
 | Encoder |  |  | 2 |  |
 | Capture | Position | YES | 1 | per encoder |
 |  | Time | YES |  |  |
 | Compare | Position | YES | 1 |  |
 |  | Time | YES |  |  |


Glentek Omega Drive: Config Structure

.

Glentek Omega Drive

Config Structure

/* glentek_omega.h */

/*
 *	Drive Config Structure
 */
typedef enum GLENTEKOmegaOptionMask {
    GLENTEKOmegaOptionMaskRS232_ECHO        = 0x0001, /* 1: Echo On, 0: Echo Off */
    GLENTEKOmegaOptionMaskTRAP_MODE         = 0x0002, /* 1: Trap Commutation 0:
                                                       Sine Commutation */
    GLENTEKOmegaOptionMaskVELOCITY_METHOD   = 0x0004, /* 1: Traditional, 0: 1/T */
    GLENTEKOmegaOptionMaskVELOCITY_REVERSE  = 0x0008, /* 1: Negate, 0: Do not negate */
    GLENTEKOmegaOptionMaskENCODER_REVERSE   = 0x0010, /* 1: Negate, 0: Do not negate */
} GLENTEKOmegaOptionMask;

typedef enum GLENTEKOmegaIoInvertMask {
    GLENTEKOmegaIoInvertMaskNODE_ALARM      = 0x0008, /* read-only */
    GLENTEKOmegaIoInvertMaskNEG_LIMIT       = 0x0020,
    GLENTEKOmegaIoInvertMaskPOS_LIMIT       = 0x0040,
    GLENTEKOmegaIoInvertMaskHOME            = 0x0080,
    GLENTEKOmegaIoInvertMaskAMP_FAULT_OUT   = 0x0100, /* read-only */
    GLENTEKOmegaIoInvertMaskAMP_TEMP_FAULT  = 0x0200, /* read-only */
    GLENTEKOmegaIoInvertMaskMOTOR_TEMP      = 0x0800,
    GLENTEKOmegaIoInvertMaskHALL0           = 0x1000,
    GLENTEKOmegaIoInvertMaskHALL1           = 0x2000,
    GLENTEKOmegaIoInvertMaskHALL2           = 0x4000,
} GLENTEKOmegaIoInvertMask;

typedef enum GLENTEKOmegaCommInitMethod {
    GLENTEKOmegaCommInitMethodTWANG_SEARCH  =   1,
    GLENTEKOmegaCommInitMethodDITHER_SEARCH =   2,
    GLENTEKOmegaCommInitMethodHALL_EDGE     =   3,
    GLENTEKOmegaCommInitMethodCOMM_TRACK    =   3,
} GLENTEKOmegaCommInitMethod;

typedef enum GLENTEKOmegaCommCrctMethod {
    GLENTEKOmegaCommCrctMethodHALL_EDGE        =   1,
    GLENTEKOmegaCommCrctMethodCOMM_TRACK_EDGE  =   1,
    GLENTEKOmegaCommCrctMethodINDEX_AUTO       =   2,
    GLENTEKOmegaCommCrctMethodINDEX_MANUAL     =   3,
} GLENTEKOmegaCommCrctMethod;

typedef struct GLENTEKOmegaFilterCoeff {
    long    A2;        /* -32768 to 32767 = -1.0 to 1.0*/
    long    A1;        /* -32768 to 32767 = -1.0 to 1.0*/
    long    B2;        /* -32768 to 32767 = -1.0 to 1.0*/
    long    B1;        /* -32768 to 32767 = -1.0 to 1.0*/
    long    B0;        /* -32768 to 32767 = -1.0 to 1.0*/
    long    scale;     /* Bit shift used to scale*/
                       /* coefficients to within +/-1.0*/
                       /* range. Coefficients should be*/
                       /* scaled by 2^-scale before*/
                       /* storing.*/
} GLENTEKOmegaFilterCoeff;

typedef struct GLENTEKOmegaConfig {
    struct {
        unsigned long   inductance;    /* Units of 0.01 mH*/
        unsigned long   resistance;    /* Units of 0.01 Ohm*/
        unsigned long   encoderType;   /* 0: rotary, 1: linear*/
        union {
            struct {
                unsigned long   motorPole;  /* even numbers only*/
                unsigned long   lineCount;  /* lines per rev*/
            } rotary;
            struct {
                unsigned long   polePitch;  /* units of 0.01mm*/
                unsigned long   resolution; /* A to B edge res (0.01um)*/
            } linear;
        } encoder;

    } motor;

    unsigned long            busVoltage;    /* DC Volts*/
    unsigned long            rs485Address;  /* Communication address*/
    GLENTEKOmegaOptionMask   optionMask;    /* Option register*/
    GLENTEKOmegaIoInvertMask ioInvertMask;  /* Digital input invert mask*/

    struct {
        float           peakLimit;          /* Amps - Peak Current Limit*/
        float           ecbThreshold;       /* Amps - Low speed threshold*/
        unsigned long   ecbTime;            /* units in 0.01 Sec*/
        float           foldbackThreshold;  /* Amps*/
        unsigned long   foldbackTime;       /* units TBD*/
    } current;

    struct {
        long            accelLimit;         /* not supported*/
        long            decelLimit;         /* not supported*/
    } trajectory;

    struct {
        unsigned long   edgePerCycleNumer;  /* edges/cycle numerator*/
        unsigned long   edgePerCycleDenom;  /* edges/cycle denominator*/
        unsigned long   encoderScale;       /* normalizes edgePerCycleNumer*/
        long            hallOffsetAngle;    /* -180 to + 180*/
        long            leadAngle;          /* -180 to + 180*/
        long            leadGain;           /* proportional to degrees/RPM*/
    } commutation;

    struct {
        GLENTEKOmegaCommInitMethod	method;

        float           phaseSearchCurrentLimit;
        unsigned long   currentSlewRate;        /* proportional to Amps/Sec*/
        long            rotationRate;           /* degrees/sec, phase vector*/
        long            limitSwDistance;        /* Distance to move away from a*/
                                                /* tripped limit switch before*/
                                                /* re-attempting phase search.*/
                                                /* Units of electric degrees.*/
    } comm_init;

    struct {
        GLENTEKOmegaCommCrctMethod    correctMethod; /* commutation correction*/
        long                          indexOffset;   /* -180 to + 180*/
    } commCorrectionOptions;

    struct {
        union {
            unsigned long   highZ;        /* (PWM Cycles) reduced wire enc*/
            unsigned long   hallFault;    /* (mSec)std encoders*/
        } timeout;
        unsigned long       highZtoLatch; /* PWM Cycles to latch Hall state*/
        unsigned long       LatchToValid; /* PWM Cycles from latch Hall to encoder read*/
    } commutationTiming;

    struct {
        unsigned long   loopGain;           /* 0 to 32767 = 0 to 1.0*/
        unsigned long   proportionalGain;   /* 0 to 32767 = 0 to 1.0*/
        unsigned long   integralGain;       /* 0 to 32767 = 0 to 1.0*/
        unsigned long   masterGain;         /* P&I gain multiplier*/
        unsigned long   smallErrThreshold;
        unsigned long   smallErrP_Gain;     /* 0 to 32767 = 0 to 1.0*/
    } currentLoopTuning;

    struct {
        unsigned long   proportionalGain;   /* 0 to 32767 = 0 to 1.0*/
        unsigned long   intergalGain;       /* 0 to 32767 = 0 to 1.0*/
        unsigned long   derivativeGain;     /* 0 to 32767 = 0 to 1.0*/
        unsigned long   masterGain;         /* P&I gain multiplier*/
    } velocityLoopTuning;

    struct {
        unsigned long   encoderPrescale;    /* 0 - 14*/
        unsigned long   velocityGain;       /* 0 to 32767 = 0 to 1.0*/
    } velMeasurementGains;

    struct {
        unsigned long   commandLimit;       /* If in Velocity mode, the*/
                                            /* velocity command is limited*/
                                            /* to this value.*/
        unsigned long   warningLimit;       /* Threshold for velocity*/
                                            /* warning flag*/
        unsigned long   warningTime;        /* Time above Warning Limit*/
                                            /* before setting warning flag*/
        unsigned long   faultLimit;         /* Threshold for velocity Fault*/
                                            /* flag.*/
        unsigned long   faultTime;          /* Time above Fault Limit before*/
                                            /* setting fault flag*/
        unsigned long   zeroSpeedWindow;    /* Threshold for setting zero*/
                                            /* speed status bit, Also used*/
                                            /* for zero speed detection*/
                                            /* during phase search algrthm.*/
        unsigned long   zeroSpeedTime;      /* Time for zero speed detection*/
    } velocityFunctions;

    /*
        Biquad Filter CoefficientsAll biquad filters implement the following
        difference equation:
           y(n)=[a2*y(n-2)+a1*y(n-1)+b2*x(n-2)+b1*x(n-1)+b0*x(n)]*2^scale
        where y(n), y(n-1), y(n-2) is the present and past filter outputs
           x(n), x(n-1), x(n-2) is the present and past filter inputs.

        The following values can be used to set the filters to No
        filtering:B0=32677, A2=A1=B2=B1=Scale=0
    */

    GLENTEKOmegaFilterCoeff	forwardPathFilter1;      /* default: no filtering*/
    GLENTEKOmegaFilterCoeff	forwardPathFilter2;      /* default: no filtering*/
    GLENTEKOmegaFilterCoeff	forwardPathFilter3;      /* default: velocity 320Hz,*/
                                                         /* first order, low pass*/
    GLENTEKOmegaFilterCoeff	velocityFeedbackFilter1; /* default: velocity 160Hz,*/
                                                         /* first order, high pass*/
    struct{
        unsigned long   parameterSelect;   /* table TBD*/
        long            dacOffset;
        long            dacGain;
        long            testVoltage;
    } analogOutput;

} GLENTEKOmegaConfig;


Glentek Omega Drive: Info Structure

.

Glentek Omega Drive

Info Structure

/* glentek_omega.h */

/*
 * Drive Info Structure
 */
#define GLENTEKOmegaStringMax	(24)

typedef struct GLENTEKOmegaInfo {
    struct {
        unsigned long   baseModel;
        unsigned long   powerBoardTab;
        unsigned long   preAmpTab;
        float           currentRatingCont;    /* Amps - Cont. Current Rating */
        float           currentRatingPeak;    /* Amps - Peak Current Rating */
        float           busUnderVoltage;      /* Volts - Bus Threshold */
        float           busOverVoltage;       /* Volts - Bus Threshold */
        GLENTEKOmegaIoInvertMask ioInvertMask;/* Factory I/O Invert Mask */
    } mode;

    struct {
        long            adcOffsetPhaseR;    /* R (U) Phase ADC Offset */
        long            adcOffsetPhaseS;    /* S (V) Phase ADC Offset */
        long            adcOffsetPhaseT;    /* T (W) Phase ADC Offset */
    } calibration;

    struct {
        unsigned long   commandSet;         /* used by MotionMaestro */
        char            version[GLENTEKOmegaStringMax];
    } firmware;

} GLENTEKOmegaInfo;


Glentek Omega Drive: Monitor Table

.

Glentek Omega Drive

Monitor Table

/* glentek_omega.h */

/*
 *  Drive Monitor Table
 */

typedef enum GLENTEKOmegaMonitorIndex {
    GLENTEKOmegaMonitorIndexU_PHASE_CURRENT     =  0,
    GLENTEKOmegaMonitorIndexV_PHASE_CURRENT     =  1,
    GLENTEKOmegaMonitorIndexW_PHASE_CURRENT     =  2,
    GLENTEKOmegaMonitorIndexU_DEMAND_VOLTAGE    =  4,
    GLENTEKOmegaMonitorIndexV_DEMAND_VOLTAGE    =  5,
    GLENTEKOmegaMonitorIndexW_DEMAND_VOLTAGE    =  6,
    GLENTEKOmegaMonitorIndexBUS_VOLTAGE         =  7,
    GLENTEKOmegaMonitorIndexACTUAL_TORQUE       =  10,
    GLENTEKOmegaMonitorIndexACTUAL_VELOCITY     =  11,
    GLENTEKOmegaMonitorIndexSHAFT_POSITION_LSW  =  14,
    GLENTEKOmegaMonitorIndexSHAFT_POSITION_MSW  =  15,
} GLENTEKOmegaMonitorIndex;


Introduction to Configuration Management

.

Configuration Management

Introduction

System designers need to give careful consideration to the software configuration management procedures for their machines. To ensure machine consistency and quality, a process for software installation, configuration, version control, and verification must be implemented. Addressing this issue early in the development cycle will significantly reduce confusion and mistakes. Failure to implement some basic procedures can cause unknown machine configurations, costly field repairs/upgrades, mysterious intermittent problems, broken equipment, and possible injury.

SynqNet, the MPI, and Software tools contain several features to make configuration management easy. Please take the time to understand and use these features before you begin development.

Software Components

The MEI software distribution contains several software components which need to be loaded onto the machine, controller, and SynqNet nodes. The MPI DLL, header files, import libraries, device driver, utility programs, controller binaries, sample code, etc. are all loaded onto your hard drive by the InstallShield distribution. Additionally, the controller contains on-board flash memory to store DSP code, FPGA code and configuration information. MEI controllers shipped from the factory will NOT have DSP code or FPGA code in flash memory. You will need to download the appropriate controller firmware (.bin) and FPGA (.fpg) code into your controller’s flash memory. Each SynqNet node has flash memory to store the FPGA runtime image. MEI nodes shipped from the factory will not have FPGA runtime images in flash memory. You will need to download the appropriate node FPGA image (.sff) into each of your node's flash memory. Some nodes have drive processor(s) which also require drive firmware to be downloaded. Please consult your drive manufacturer's documentation for details.

See Also

Controller Binary Images
Node Binary Images
Drive Binary Images


Kollmorgen CD Drive: Config Structure

.

Kollmorgen CD Drive

Config Structure

/* kollmorgen_cd.h */

/*
 *	Drive Config Structure
 */

typedef struct CDDriveConfig {
    long mpitch;     /* Defines the pole-pitch of the motor and allow the drive to
                        be able to calculate other values. */
    long motortype;  /*       */
    long mipeak;     /* Sets the motor's peak rated current */
    long micont;     /* Sets the motor's continuous rated current */
    long mspeed;     /* Defines the maximum recommended velocity of the Motor */
    long mkt;        /* Motor torque constant */
    long mencres;    /* Displays the resolution of the motor encoder in number
                        of lines per revolution of the motor */
    long menctype;   /* Motor encoder type */
    long mencoff;    /* Sets the encoder index position */
    long mlmin;      /* Sets the motor's minimum line-to-line inductance */
    long mphase;     /* Defines the encoder phase relative to the "standard"
                        commutation table */
    long mpoles;     /* Sets the number of motor poles */
    long mbemfcomp;  /* Sets a back EMF compensation percentage value */
    long mlgainc;    /* Sets the current loop adaptive gain value at continuous
                        motor current */
    long mlgainp;    /* Sets the current loop adaptive gain value at peak
                        motor current */
    long mtanglc;    /* Sets the value of the torque-related commutation angle
                        advance at the motor's continuous current rating */
    long mtanglp;    /* Sets the value of the torque-related commutation angle
                        advance at the motor's peak current */
    long mvanglf;    /* Sets the value of the velocity-rated commutation angle
                        advance for when the motor is operating at motor max speed */
    long mvanglh;    /* Sets the value of vel-rated commutation angle advance for
                        when the motor is operating at half of the motor max speed */
    long mhinva;     /* HALL A inversion */
    long mhinvb;     /* HALL B inversion */
    long mhinvc;     /* HALL C inversion */
    long vbus;       /* Sets the drive bus voltage */
    long ilim;       /* Sets the application current limit */
    long icont;      /* Sets the system continuous current */
    long vlim;       /* Sets the application velocity limit. */
    long mfbdir;     /* Motor & feedback direction. */
    long anoff1;     /* Analog offset 1. */
    long anoff2;     /* Analog offset 2. */
    long initgain;   /* gain for encoder initalization. */
    long iencstart;  /* Maximum current for wake no shake. */
    long uvmode;     /* Action in in response to under-voltage. */
    long uvtime;     /* Under voltage warning time. */
    long uvrecover;  /* Recovery from under-voltage fault. */
    long thermmode;  /* Action when motor thermostat opens. */
    long thermtype;  /* Motor temperature sensor type. */
    long izero;      /* Sets the ZERO mode current. */
} CDDriveConfig;

typedef struct CDDriveInfo {
    long dicont;     /* continuous rated current for drive */
    long dipeak;     /* peak rated current of the drive */
    long imax;       /* max current for the motor drive combination */
    long pwmfrq;     /* PWM frequency */
    long ver;        /* indicates the version of drive firmware to use */
} CDDriveInfo;


Kollmorgen CD Drive: Monitor Table

.

Kollmorgen CD Drive

Monitor Table

/* kollmorgen_cd.h */

/*
 *  Drive Monitor Table
 */

typedef enum CDMonitorIndex {
    CDMonitorIndexU_PHASE_CURRENT    =  0,
    CDMonitorIndexV_PHASE_CURRENT    =  1,
    CDMonitorIndexW_PHASE_CURRENT    =  2,
    CDMonitorIndexACTUAL_TORQUE      =  10,
    CDMonitorIndexANALOG_IN0         =  30,
    CDMonitorIndexANALOG_IN1         =  31,
} CDMonitorIndex;


Kollmorgen DASA Drive: Config Structure

.

Kollmorgen DASA Drive

Config Structure

/* kollmorgen_dasa.h */

/*
 *	Drive Config Structure
 */
typedef struct DASADriveConfig {
    long mipeak;     /* Sets the motor's peak rated current*/
    long micont;     /* Sets the motor's continuous rated current*/
    long mspeed;     /* Defines the maximum recommended velocity of the Motor*/
    long mkt;        /* Motor torque constant*/
    long mencres;    /* Displays the resolution of the motor encoder in number
                        of lines per revolution of the motor*/
    long menctype;   /* Motor encoder type*/
    long mencoff;    /* Sets the encoder index position*/
    long mlmin;      /* Sets the motor's minimum line-to-line inductance*/
    long mphase;     /* Defines the encoder phase relative to the "standard"
                        commutation table*/
    long mpoles;     /* Sets the number of motor poles*/
    long mbemfcomp;  /* Sets a back EMF compensation percentage value*/
    long mlgainc;    /* Sets the current loop adaptive gain value at continuous
                        motor current*/
    long mlgainp;    /* Sets the current loop adaptive gain value at peak
                        motor current*/
    long mtanglc;    /* Sets the value of the torque-related commutation angle
                        advance at the motor's continuous current rating*/
    long mtanglp;    /* Sets the value of the torque-related commutation angle
                        advance at the motor's peak current*/
    long mvanglf;    /* Sets the value of the velocity-rated commutation angle
                        advance for when the motor is operating at motor max speed*/
    long mvanglh;    /* Sets the value of vel-rated commutation angle advance for
                        when the motor is operating at half of the motor max speed*/
    long mhinva;     /* HALL A inversion*/
    long mhinvb;     /* HALL B inversion*/
    long mhinvc;     /* HALL C inversion*/
    long vbus;       /* Sets the drive bus voltage*/
    long ilim;       /* Sets the application current limit*/
    long icont;      /* Sets the system continuous current*/
    long vlim;       /* Sets the application velocity limit.*/
    long mfbdir;     /* Motor & feedback direction.*/
}DASADriveConfig;


Kollmorgen DASA Drive: Info Structure

.

Kollmorgen DASA Drive

Info Structure

/* kollmorgen_dasa.h */

/*
 *	Drive Info Structure
 */
typedef struct DASADriveInfo {
    long dicont;    /* continuous rated current for drive*/
    long dipeak;    /* peak rated current of the drive*/
    long imax;      /* max current for the motor drive combination*/
    long pwmfrq;    /* PWM frequency*/
    long ver;       /* indicates the version of drive firmware to use*/
} DASADriveInfo;


Kollmorgen DASA Drive: Monitor Table

.

Kollmorgen DASA Drive

Monitor Table

/* kollmorgen_dasa.h */

/*
 *  Drive Monitor Table
 */
typedef enum DASAMonitorIndex {
    DASAMonitorIndexU_PHASE_CURRENT    =  0,
    DASAMonitorIndexV_PHASE_CURRENT    =  1,
    DASAMonitorIndexW_PHASE_CURRENT    =  2,
    DASAMonitorIndexACTUAL_TORQUE      =  10,
    DASAMonitorIndexANALOG_IN0         =  30,
    DASAMonitorIndexANALOG_IN1         =  31,
    DASAMonitorIndexANALOG_IN2         =  32,
    DASAMonitorIndexANALOG_IN3         =  33,
    DASAMonitorIndexANALOG_IN4         =  34,
    DASAMonitorIndexANALOG_IN5         =  35,
    DASAMonitorIndexBUS_VOLTAGE        =  36,
    DASAMonitorIndexDRIVE_TEMP         =  37,
} DASAMonitorIndex;


Loopback Connector

.

Loopback Connector

It is easy to make a loopback connector for a SynqNet Terminated String Topology. Simply follow the diagrams below in order to modify an existing RJ-45 or Micro-D cable into a functional loopback connector.

See also: SynqNet Topologies

RJ-45 Loopback Connector

Pin | In | Out | Color
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X) | 100BaseT Cable
1 | Transmit + | Receive + | orange/white
2 | Transmit - | Receive - | orange
3 | Receive + | Transmit + | green/white
4 | UUPI + | UUPI + | blue
5 | UUPI - | UUPI - | blue/white
6 | Receive - | Transmit - | green
7 | UUP2 + | UUP2 + | brown/white
8 | UUP2 - | UUP2 - | brown
- | SHLD | SHLD |

Micro-D Connector

Pin | In | Out
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X)
1 | Transmit + | Receive +
2 | UUPI + | UUPI +
3 | SHLD | SHLD
4 | UUP2 + | UUP2 +
5 | Receive + | Transmit +
6 | Transmit - | Receive -
7 | UUPI - | UUPI -
8 | UUP2 - | UUP2 -
9 | Receive - | Transmit -


SynqNet Node Library

.

SynqNet Node Library

Under Construction.
Coming Soon!


Network Configuration

.

Network Configuration

After the network has been Powered-On or Reset, and finished the Reset Network Phase, the controller enters the DISCOVERY Network Phase and verifies the configuration of the network. CONTROL packets are sent out to all the nodes on the network by the controller in order to determine the network configuration. The packets serve three main purposes:

  • Read Node Identification into XMP memory
  • Set node addresses
  • Enable node repeaters

Discovery continues until every node on the network has been found. After all of the nodes have been discovered, the Controller can then verify if the network is properly configured. The discovered Node Identification that was just read into XMP memory is compared with data written to XMP Flash memory using the Network Confirmation Method. If all the node IDs match, the verification "Passes." if they do not match, the verification "Fails."

Possible Reasons for Failure:

  • The Node Identification structure in Flash memory is blank (the network has not been confirmed).
  • The Node Identification doesn't match (network confirmed, but wrong). The latter failure condition will result in an error code being returned by the mpiControlInit(...) method.

At this point there are two paths the initialization routine can take:

  • If the verification Passes, the XMP will perform the Automatic Initialization Routine
  • If the verification Fails, the XMP will perform the Default Initialization Routine


Network Confirmation

.

Network Confirmation

Sending the wrong configuration settings to a SynqNet node could pose serious safety hazards. To avoid these hazards, the MPI will always configure and send the default FPGA settings to each node until the motion application has "confirmed" that the discovered network is correct. In addition, the motion application will not be able to access the MPI Flash module to save/load custom node configuration settings. These preventive measures will ensure that the network configuration is correct before any motion can take place over the network.

To "confirm" the network configuration, the SynqNet method, meiControlTopologytoFlash(...) must be called. Confirming the network configuration will allow the controller to perform automatic initialization, as well as enable access to the MPI Flash module. A space will be allocated in flash memory where the Confirmation Method will save the node identification, for each node found on the network. This node information will be used by the XMP to verify the network on the next power cycle or reset. Once the XMP verifies that the network nodes are in the proper sequence, the FPGA settings in flash memory will be streamed down instead of the defaults. Also, the motion application will be able to access the MPI Flash module to save/load custom node configuration settings.

For an overview of Network Initialization and its flowchart diagram, click here.

For more information about "Saving to Flash," click here.


Node Faults Diagram

.

Node Faults Diagram


Node Identification

.

Node Identification

Node Identification refers to the data that is stored in addressable memory locations on a node. SynqNet nodes include single or multi-axis partner drives, MEI motion blocks, and other SynqNet compatible devices. SynqNet nodes can be manufactured by either MEI, a SynqNet Drive Partner, or a customer.

SynqNet nodes typically contain an FPGA, which manages the SynqNet interface and most of the node I/O. Nodes may also contain other memory or processing units. A SynqNet drive is a good example of a node that contains multiple control and storage devices. A SynqNet drive will typically contain the FPGA, a serial EEPROM, the drive DSP(s), and the drive DSP associated memory and flash. FPGAs are primarily designed by MEI, while other parts of the node may be designed and supplied by drive partners or customers. Therefore, the node supplier may be different than the FPGA supplier. It is important that the application software has adequate ID information so that it knows how to communicate and control all elements of the node.

Node Identification is comprised of two parts:
FPGA ID Data
Node ID Data

The tables below explain where the appropriate information can be accessed.

FPGA Identification Data (Required)

Data Type | Description | Size | Address | Assigned By
Vendor / Device | Code which identifies the FPGA supplier and device type | 32 bits | 0x00010000 Lower- Device Upper- Vendor | MEI
Version | FPGA Version Number and MAC Version Number | 32 bits | 0x00010000 Lower- FPGA Upper- MAC | MEI

Node Identification Data (Required)

Data Type | Description | Size | EEPROM Address | Node Address | Assigned By
Product | Code which identifies Node type | 16 bits | 0x00 | 0x000C0400 | Vendor
Manufacturer | Code which identifies Node manufacturer | 16 bits | 0x01 | 0x000C0404 | MEI
ID LSW | Unique Identifier (possibly derived from vendor serial number) | 16 bits | 0x02 | 0x000C0408 | Vendor
ID MSW | Unique Identifier (possibly derived from vendor serial number) | 16 bits | 0x03 | 0x000C040C | Vendor
Boot Device | FPGA type of Boot Image (must be zero if no boot image) | 16 bits | 0x04 | 0x000C0410 | Vendor
Boot Vendor | FPGA supplier of Boot Image (must be zero if no boot image) | 16 bits | 0x05 | 0x000C0414 | Vendor
Option LSW* | Assembly stuff option id (must be zero if not defined) | 16 bits | 0x06 | 0x000C0418 | Vendor
Option MSW** | Assembly stuff option id (must be zero if not defined) | 16 bits | 0x07 | 0x000C041C | Vendor
Reserved | Reserved for MEI (must be zero if not defined) | 16 bits | 0x06-0x0F | 0x000C0418-0x000C043C | MEI
Reserved | Reserved for User (must be zero if not defined) | 16 bits | 0x10-0x1F | 0x000C0440-0x000C047C | User
 |  |  | LSW* - Least Significant Word MSW** - Most Significant Word

MEI Serial EEPROM Data (Optional)

The following table shows the addresses of the optional ID information in nodes that are manufactured by MEI.

EEPROM Address | Node Address | Data / sample | Description | Example
0x20 | 0x000C0480 | 0x3031 | Part # LLSW | T010-0001
0x21 | 0x000C0484 | 0x3030 | Part # LMSW
0x22 | 0x000C0488 | 0x3130 | Part # MLSW
0x23 | 0x000C048C | 0x5430 | Part # MMSW
0x24 | 0x000C0490 | 0x6865 | Part # LSW | 420228
0x25 | 0x000C0494 | 0x0006 | Part # MSW

Vendor Defined Data (Optional)

For SynqNet nodes that are manufactured by MEI, the MEI Serial EEPROM Data configuration (see above) will be used. There are also additional addresses that can by used to provide additional information such as a serial number, product description, etc.

For SynqNet nodes that are NOT manufactured by MEI, the vendor will be required to provide a breakdown of the addresses and definitions for the node.


Overview of Network Initialization

.

Overview of Network Initialization

In an effort to improve efficiency, some of the responsibilities of the network initialization phases have been shifted from the MPI to the XMP controller. This sharing of the network initialization burden requires a cooperative effort between the MPI and the Controller DSP. The flowchart below shows the steps necessary to complete an initialization of the network, as well as the processor required for initiating each step. The column on the left shows the steps performed by the XMP controller DSP and the column on the right shows those performed by the MPI (or host processor).

There are two initialization routines that can be used for Network Initialization:

  • Default Network Initialization - this routine is used when a SynqNet network is connected and booted up for the first time.
  • Automatic Network Initialization - this routine should be used for everytime afterwards. When the network is Powered-On or Reset, the controller will assume that the previously saved configurations in the Flash object are correct and use them.

Power-On / Reset
After the initial power-on or controller reset, the XMP controller does not know what nodes are connected to the network.

VALIDATE, READY, RESET, and Verify
The controller takes the network through the VALIDATE, READY, and RESET Network Phases.

Verify Network Configuration (Discovery Phase)
See Network Configuration for more information.

Automatic Initialization Routine
See Automatic Initialization Routine for more information.

Default Initialization Routine
See Default Initialization Routine for more information.


Overview of SynqNet

.

Overview of SynqNet

What is SynqNet?

SynqNet is a high-performance, synchronous network technology specifically designed for multi-axis motion control applications. It is the only system that dramatically reduces system wiring while simultaneously providing higher performance than conventional analog control systems.

SynqNet replaces the noise-prone analog drive - motion controller interface (±10V + Encoder) with a real-time digital network that brings additional diagnostic, performance and reliability benefits to a machine.

SynqNet is an all-digital, motion control interface for connections between controllers and drives. The physical layer of SynqNet is based on IEEE 802.3 standards for 100Base-TX, the physical layer of Ethernet. The data link and application layers of SynqNet are specifically designed for motion control applications. The 100BASE-TX media system is based on specifications published in the ANSI TP-PMD physical media standard. The 100BASE-TX system operates over two pairs of wires, one pair for 'receive' data signals and the other pair for 'transmit' data signals.

How does the SynqNet network actually work?

SynqNet is a synchronous network that employs a centralized motion controller to transmit regular synchronization data to every node around the network. Each receiving node uses advanced digital time-correction techniques to minimize both skew and jitter to levels that are comparable to or better than high performance analog systems. Service channel capability is used to query nodes regarding a variety of information. In the case of SynqNet drives, separate diagnostic tools are not required; a user can simply acquire drive information (depending on manufacturer specifications) via a service channel command and the standard SynqNet programming interface.


Panasonic Minas B Drive: Info Structure

.

Panasonic Minas B Drive

Info Structure

/* panasonic_minasb.h */

/*
 *	Drive Info Structure
 */
#define	MINASBProductCodeSize	(12)

typedef struct MINASBDriveInfo {
    char    productCode[MINASBProductCodeSize];
    long    version;
    long    pwmFrequency;
    long    encoderType;
    long    inputVoltage;
} MINASBDriveInfo;


SynqNet Phase II Overview

.

Synqnet Phase II Overview

Introduction

The 20030423 software release supports SynqNet controllers. SynqNet is a high performance synchronous network designed for multi-axis motion control applications.

SynqNet Phase II Development

The SynqNet development has occurred in two major phases. SynqNet Phase 1 ported internal XMP-Series controller communication protocols to run over 100BaseT network hardware. This allowed MEI to develop SynqNet with minimal software changes. It also allowed our drive partners to design and build SynqNet servo drives. Due to the protocol internals, SynqNet Phase I has several limitations. It only supported 6 nodes, string topologies, nonconfigurable packet data, and a maximum update rate of 5kHz.

SynqNet Phase 2 is an upgrade to the SynqNet internals. It is a fully scalable network protocol that offers higher performance, reliability, and several additional features including:

  • Up to 32 nodes on one network
  • Fault Recovery (ring topology only)
  • Optimized Packet Timing
  • Bad Feedback Packet Compensation
  • Amp Enable Safety Features
  • User Configurable Data Packets
  • Capture (time-based)
  • Cable Length Compensation (up to 100m in length)
  • Scalable networking timing
  • Downloadable FPGA and drive binary code over SynqNet

Beyond Phase II, more features will be added with future software upgrades.

WARNING!
SynqNet software releases do NOT support XMP-Series Analog, SERCOS, or Pulse controllers.

Features and Limitations

This release supports the SynqNet Phase II protocol. The following are available in this release:

  • Up to 32 nodes on one network
  • Scalable networking timing - the MPI automatically scales the packet timing based on the node number and type. The maximum controller/network sample rate depends on controller/network load. The minumum sample rate is 1kHz.
  • String and Ring topologies are now supported.
  • Network Fault Recovery is now supported on Ring topologies.
  • Cable Lengths of up to 100 meters are now supported.
  • Software configurable data packets - The MPI automatically configures the packets during network initialization based on the node type. Packets are also user configurable.
  • Node FPGA download via SynqNet-RMB-10V (via Outrigger circuit) and all other supported nodes (via Bowsprit circuit). See the list of Supported SynqNet Nodes below.

The following features are NOT supported in this release:

  • Compare
  • ADCs
  • Stepper (pulse) motor type

Supported SynqNet Controllers

All XMP-Series SynqNet controllers are supported with this release. XMP-Series controllers with local motion blocks are supported, but the local motion blocks are not supported. Please see the SynqNet Hardware section on the support website for a complete list and details about SynqNet controllers.

Supported SynqNet Nodes

The following SynqNet node types are supported:

  • MEI RMB-10V
  • MEI RMB-10V2
  • AMC Digiflex
  • Glentek Omega
  • Glentek SQ
  • Kollmorgen CD
  • Kollmorgen DASA
  • Panasonic Minas B
  • Sanyo Denki Q
  • Yaskawa DMD/IDM
  • Yaskawa Sigma-III

Future Phase II releases will add support for other node types and SynqNet drives as they become available.

Please see the SynqNet Hardware section on the support website for details about supported SynqNet nodes.

Upgrading to SynqNet Phase II

If you have SynqNet Phase I hardware/software and would like to upgrade to SynqNet Phase II, please contact MEI and the node manufacturer. SynqNet controllers can be upgraded in the field by downloading new firmware and a new FPGA image. This can be performed with Motion Console or the flash.exe utility. Most SynqNet nodes must be returned to the factory for boot ROM upgrade. Once you have Phase II compatible nodes, then binary FPGA images and drive firmware can be downloaded. Not all nodes support download, so be sure to contact the node manufacturer for the latest information.

After nodes have been upgraded to Phase II, all future upgrades will be possible via software download.

Node FPGA Binary Files

Please see the Node Binary Files: Product Table on the SynqNet Technology page for details about binary file to product compatibility. For information about the supported features of each binary file, see the Node Binary Files: Features Table.

MPI

The MPI has been expanded to support SynqNet Phase II. The SynqNet specific methods and structures are located in synqnet.h and sqnode.h. Please see the support website the MPI Software Documentation section for details.

If you are porting application code from SynqNet Phase I, then the SynqNet portion of your code will need to change to match the new Phase II interface. The motion portions of your application should not require changes.

Here is a summary of the major MPI changes in Phase II. For additional information, please see the Upgrading Software to SynqNet Phase II section.

Block to sqNode - In Phase I, the block object was responsible for local and remote motion blocks. Each physical block had a fixed set of resources to support 4 motors. In Phase II, local motion blocks are NOT supported. Remote blocks are SynqNet nodes that can support 0 to 8 motors. The block object was replaced with the sqNode object and modified to support Phase II features.

SynqNet to sqNode - In Phase I, the SynqNet module contained methods and structures to read network info and status from the controller and nodes. Also, it provided an interface to send service commands, clear faults, get/set the drive configuration and read drive info. In Phase II, the SynqNet node specific methods and structures have been modified and moved from synqnet.h, into sqnode.h. Now, only network methods and data are handled through the SynqNet object and SynqNet node methods and data are handled through the sqNode object.

Network Initialization - In Phase I, the network was automatically initialized when mpiControlInit(…) was called. The MPI Library handled all network initialization.

In Phase II, the network initialization responsibility is split between the controller and the MPI library. The controller begins the network initialization by checking network integrity, then resets the nodes, and discovers each node. If the controller finds the expected topology it will transition the network to cyclic mode, stream down the FPGA configuration data to each node and return control to the MPI library to complete any node specific initialization. If the controller finds a topology that doesn't match its expected topology, it will return an error. If the controller doesn't have an "expected" topology, then the MPI Library will transition the network to cyclic mode, stream down the default FPGA configuration data (via the controller), and complete any node specific initialization.

Network Verification/Confirmation - In Phase I, the network topology was always discovered by mpiControlInit(…). Any configurations saved in the controller's flash memory would be loaded on a powerup or reset and the FPGA service commands would be sent to the nodes. No matter what network topology was found during discovery, the controller flash configurations would be applied.

In Phase II, the controller determines whether the discovered topology matches the expected topology, does not match the expected topology, or is not specified (default). If the topology information is saved to the controller's flash using meiControlTopologyToFlash(…), then the controller will compare the discovered topology to the expected topology. If the discovered topology matches the expected topology, the controller will send its FPGA configuration data (from flash memory) to the nodes. If the discovered topology does not match the expected topology, then mpiControlInit(…) will return a TOPOLOGY_MISMATCH error and the FPGA configurations will not be sent to the nodes. To recover from this error, the network topology must be corrected, or the new topology must be saved to flash with meiControlTopologyToFlash(…). If the topology information is not saved to the controller's flash, then the MPI library will send the default FPGA configuration data to the nodes.

Packet Errors - In Phase I, the controller and each SynqNet node had one CRC error counter. In Phase II, the controller and each SynqNet node has CRC error counters on each port, a packet error counter and a packet error rate counter.

Capture - In Phase I, the FPGA capture logic was copied from the XMP-Series Analog controller. Each motion block (4 motors) contained 10 configurable capture blocks. The capture object was indexed by number and statically allocated in the controller's memory.

In Phase II, the FPGA capture logic has been redesigned. The feature set is very similar to the older Analog controller-based capture. The capture objects are now associated with motor objects. The motor object now supports two encoder interfaces. Each encoder interface supports two capture blocks. Initially, each encoder will support two capture blocks. In the future, the number of capture blocks per encoder will be variable depending on the FPGA logic.

mpiCaptureCreate(…) has new parameters to create a capture object based on a motor handle, an encoder (primary or secondary), and a capture number (0 or 1).

MPICaptureConfig{…} has been changed to support configurable capture trigger sources, edge, and a global trigger.

MPICaptureStatus{…} has been changed to support a single latched position value per capture.

IoAbort - In Phase I, the IoAbort for remote nodes could be enabled or disabled. When a network fault occurred, the IoAbort (if enabled) would force the remote block outputs to their powerup state. In Phase II, the IoAbort is configurable. The input conditions for a SynqNet node IoAbort can be configured with meiSqNodeConfigGet/Set(…) using the MEISqNodeConfigIoAbort{...} structure. And the state of each output (in an IoAbort condition) can be configured through the MEIMotorIoConfig{…} structure with mpiMotorConfigGet/ Set(…).

MEIMotorConfig{…} - In Phase I, the MEIMotorConfig{…} structure contained support for transceiver I/O configuration. The transceivers were XMP-Series Analog and RMB-10v specific circuits. The features associated with the transceivers were hardware specific. In Phase II, the transceiver support was removed from MEIMotorConfig{…}. It was replaced with a general purpose MEIMotorIoConfig{…} structure to support various types of configurable I/O. There are 16 bits of configurable I/O per motor. The physical implementation and actual number of configurable motor I/O is node/drive specific. The generic bit masks are enumerated in MEIMotorIo.

A new structure MEIMotorFaultConfig{…} was added to support configuration for the MEIMotorDedicatedInAMP_FAULT bit. The MEIMotorFaultMask can be used to select the trigger conditions for the MEIMotorDedicatedInAMP_FAULT.

MEIMotorInput/Output - In Phase I, these enumerations contained the bit masks for all motor I/O. These enumerations included a mixture of the following bit masks: Dedicated, Transceiver, SIM4, User, Capture, and Compare. In Phase II, the MEIMotorInput/Output enumerations were replaced with Dedicated I/O and Configurable I/O enumerations. The MEIMotorDedicatedIn/Out enumerations contain bit masks for Dedicated I/O that is common to all SynqNet motor and drive interfaces. The MEIMotorIo contains bit masks for the configurable motor I/O. The configurable motor I/O number and mapping is node specific. You can use the MEIMotorIo bit masks or the node specific bit masks located in the node specific header files (SqNodeLib).

MEIMotorStatus{…} - This structure has been extended to add support for SynqNet MEIMotorFaultStatus bits.

Amp Fault Message/Clear - In Phase I, there were methods to read an Amp Fault message from a drive or clear the Fault message buffer. The meiSynqNetAmpFault(…) method was used to read the drive specific fault message(s) and meiSynqNetAmpFaultClear(…) was used to clear the message buffer.

In Phase II, these methods have been replaced with more generic meiMotorAmpFault(…) and meiMotorAmpFaultClear(…) methods. The MEIMotorAmpFaults{…} structure is used to retrieve the fault codes and string messages. The definitions for the faults codes are drive specific. Also, support has been added to read/clear drive warnings with meiMotorAmpWarning(…) and meiAmpWarningClear(…).

Monitor - The monitor packet field data is now configurable (for drives that support it). MeiSqNodeDriveMonitorConfigGet/ Set(…) can be used to configure each monitor field based on an index or address.

Node Download - A new method, meiSqNodeDownload(…) has been added to support FPGA and drive firmware download.

Utility Programs

The utility programs have been updated to support SynqNet. A new utility, sqNodeFlash.exe has been added to support FPGA and drive firmware download. Please see the sqNodeFlash Utility section on the support website for information about how to use this utility.


CRC Error Counters

.

CRC Error Counters

Introduction | Packet Flowchart | In Motion Console

Introduction

The Cyclic Redundancy Check (CRC) is a way of detecting small changes in blocks of data. This type of error detection is especially useful when sending packets data across a network.

A SynqNet network uses CRC to ensure the data integrity of each packet sent across its network. A CRC error counter exists on each port that transmits/receives data on the controller and node. These error counters may assist in isolating data integrity problems to determine if there is a faulty cable, node, node FPGA, etc. The counter increments by one for any CRC error found on any packet received at a particular port. The counters are unsigned, 8-bit values and saturate at a maximum of 255 (0xFF) errors. The counter also goes back to zero after a reset and can be cleared by controller software.

NOTE: Data errors in the start delimiter may prevent the CRC errors from being counted.

In order to understand how CRC Error Counters work on SynqNet, it is helpful to first understand how packets travel across the network.

Packet Flowchart

Under normal operation, the flow of packets over a SynqNet network is the same for the string and ring topology. In one sample over the network there will be one downstream cycle and one upstream cycle.

In a downstream cycle, the controller sends 3 different types of packets for each node on the network. In the example below, 6 packets are traveling downstream because there are 2 nodes on the network. Similarly, if there were 3 nodes on the network, there would be 9 packets traveling downstream.

In an upstream cycle, each node will be sending 2 packets back to the controller. In the example below, 4 packets are traveling upstream because there are 2 nodes on the network. Similarly, if there were 3 nodes on the network, there would be 6 packets traveling upstream.

For a breakdown of the various SynqNet packets, please see the SynqNet Packet Formats section.

Please see the CRC Error Counter Examples section for helpful diagrams and breakdowns of various scenarios.

In Motion Console

Node CRC Error Counters

In Motion Console, you can see the node's CRC Error Count in the SqNode Summary Window under the Status tab. Notice that there is a CRC Error Count for each port on each node.

Controller CRC Error Counters

In Motion Console, you can see the controller's CRC Error Count in the SynqNet Summary Window.


CRC Error Counter Examples

.

CRC Error Counter Examples

Downstream Cycle | Downstream Cycle (w/ error)

Upstream Cycle | Upstream Cycle (w/ error)

For information about CRC errors, please see the CRC Error Counters section.

Downstream Cycle

A downstream cycle consists of 3 packets/node that are sent from the controller to all the nodes on the SynqNet network. All packets that are sent by the controller are node-specific. For example, N0 will ignore the N1 packets. Although there is a CRC error counter on each IN/OUT port, only the "receiving" port will check the packets and report any errors. In the example below, the OUT port of N0 will not check any packets sent from the controller since it is a transceiving (not a receiving) port.

In the example above, the following steps occur:

  1. Controller 0 (C0) sends 6 packets to Node 0 (N0)
    The N0 packets that are sent by the controller are verified for data integrity at the IN port of N0. The N1 packets are ignored and passed through to N1. In this example, the Control packet for N0 has missing or corrupt data. Therefore, the CRC error counter for N0 is incremented by one. Motion Console displays the CRC errors in the SqNode Summary Window.

    SqNode 0
    SqNode1
    CRC Err. OUT 0
    0
    0
    CRC Err. IN 0
    1
    0

  2. N0 sends all 6 packets to N1

  3. The N1 packets are verified for data integrity at the IN port of N1. The N0 packets are ignored. Since there are no errors in any of the N1 packets, the CRC error counter for N1 is not incremented.

    SqNode 0
    SqNode1
    CRC Err. OUT 0
    0
    0
    CRC Err. IN 0
    1
    0

Downstream Cycle (w/ error)

When there is a hardware failure in a Ring topology, where communication via the OUT port of the controller cannot reach all of the nodes, the redundant link will be used to reestablish communication with the "lost" node(s). In the example below, there is an error between N0 and N1. As a result, the controller will also send the packets from its IN port to the OUT port of N1 via the redundant link.

In the example above, the following steps occur:

  1. C0 sends 6 packets to N0 for packet verification (using its OUT port).

  2. The N0 packets that are sent by the controller are verified for data integrity at the IN port of N0. The N1 packets are ignored. In this example, the Control packet for N0 has missing or corrupt data. Therefore, the CRC error counter for N0 is one.

    SqNode 0
    SqNode1
    CRC Err. OUT 0
    0
    0
    CRC Err. IN 0
    1
    0

  3. There is a hardware error that is preventing communication between N0 and N1.

  4. C0 sends 6 packets to N1 for packet verification (using its IN port).

  5. N1 verifies the data integrity of each of the N1 packets sent by the controller. The N0 packets are ignored. Since there are 2 errors in the N1 packets, the CRC error counter for N1 is 2. Notice that the CRC errors appear in the SqNode's OUT port, since that is where the packets were received and checked.

    SqNode 0
    SqNode1
    CRC Err. OUT 0
    0
    2
    CRC Err. IN 0
    1
    0

Upstream Cycle

An upstream cycle consists of 2 packets/node that are sent from each node to the controller on the SynqNet network.

In the example above, the following steps occur:

  1. Node 1 (N1) sends 2 packets to N0.

  2. N0 sends 4 packets to C0.

  3. C0 verifies the data integrity of each of the packets sent by the N0 and N1. Motion Console displays the error count in the SynqNet Summary Window.

    SynqNet 0
    Error Count
    0

Upstream Cycle (w/ error)

When there is a hardware error in a Ring topology where communication is lost between two nodes, the redundant link will be used to reestablish communication with the "lost" node(s). In the example below, there is an error between N0 and N1. As a result, N0 will send its packets to the IN port of C0 via the redundant link; N1 will send its packets to the OUT port of C0.

In the example above, the following steps occur:

  1. There is a hardware failure that is preventing communication between N1 and N0.

  2. N1 sends 2 packets to the IN port of C0.

  3. N0 sends 2 packets to the OUT port of C0.

  4. C0 verifies the data integrity of each of the packets sent by the N0 and N1. Motion Console displays the error count in the SynqNet Summary Window.

    SynqNet 0
    Error Count
    0


Packet Error Counters

.

Packet Error Counters

Packet error counters are used to monitor the long-term data integrity of the network. These counters are only used for gathering statistics, and are not directly involved in the fault and fail thresholds (described below). Each individual SynqNet network installation should be routinely monitored to detect error rates greater than the nominal rate. The monitor function can be as simple as daily logging of the packet error counters, or as sophisticated as a program that logs errors and correlates them with machine activity. The nominal rate is generally on the order of one packet error per hour (for each node), but may vary depending on the application. Rates greater than nominal may imply a failing or marginal cable or node. High rates may also imply a system noise problem, whose solution may require reducing emissions, or additional cable shielding, or changing cable routing. Since packets are node-specific, each node contains its own packet error counter to monitor downstream packet errors. The node expects to receive three packets in each controller period: SYNQ, DEMAND, and CONTROL. The counter is incremented once for each missing or invalid packet. The counter is an unsigned 8-bit value, and saturates at its maximum of 0xFF. The counter is zero after a reset, and can be cleared by controller software.

Similarly, the controller has individual packet error counters for each node to count upstream packet errors from each node. The controller expects to receive two packets from each node in each period: FEEDBACK and STATUS. Again the counter is incremented once for each missing or invalid packet. The counter is an unsigned 8-bit value, and saturates at its maximum of 0xFF. The counter is zero after a reset, and can be cleared by controller software.

See Also:

Packet Error Rate Counter
SynqNet Fault Recovery
SynqNet Failure


Packet Error Counter Examples

.

Packet Error Counter Examples

On the Node: Downstream Cycle | Upstream Cycles

On the Controller: Upstream Cycle

For information about packet errors, please see the Packet Error Counters section.

Node: Downstream Cycle

A downstream cycle consists of 3 packets/node that are sent from the controller to all the nodes on the SynqNet network. Each node has a packet error counter inside the FPGA that checks its own packets, but ignores all other packets. Each node has two counters that are related to packet errors: the Packet Error Counter and the Packet Error Rate Counter.

The Packet Error Counter on each node checks to make sure that it received all three of its packets during each SynqNet cycle. For each invalid or missing packet, the Packet Error Counter increments by one. This is a continuous counter that is automatically reset to zero after a hardware reset or can be manually reset in Motion Console.

There is also a Packet Error Rate Counter on each node, which increments by one for every packet error received, and decrements by one for every 16 valid packets received. Therefore, over a period of 100 cycles, a node's Packet Error Counter may be 15, but the Packet Error Rate Counter may still be 0 (zero). The counter is an unsigned 8-bit value, and saturates at 0xFF. It is automatically reset to zero after a hardware reset or can be manually reset in Motion Console.

In the example above, the following steps occur:

  1. Controller 0 (C0) sends packets downstream to Node 0 (N0).

    SqNode 0
    SqNode1
    Packet Err. Ctr
    1
    0
    Packet Err. Rate Ctr
    1
    0

  2. The FPGA in N0 checks the N0 packets to make sure that all 3 packets were received. Since one packet (the DEMAND packet) is missing during this cycle, the packet error counter for N0 is now 1. The N1 packets are ignored. All the packets are then sent down to N1.

  3. The FPGA in N1 checks the N1 packets to make sure that all 3 packets were received. Since all of its packets were received, the packet error counter remains 0 for N1. N0 packets are ignored.

    SqNode 0
    SqNode1
    Packet Err. Ctr
    1
    0
    Packet Err. Rate Ctr
    1
    0

    NOTE: In the ensuing cycles, assuming that N0 does not receive another error before it receives 16 valid packets, the Packet Err. Rate Ctr for N0 will go back to 0 (zero) after receiving the 16th valid packet.

Node: Upstream Cycle

Scenario 1 - Fault Limit is reached

After several consecutive cycles, N0 has accumulated 13 packet errors and a Packet Error Rate Counter of 6 (the default Fault Limit per node) while using the normal downstream route (C0 > N0 > N1).

Once the Fault Limit (Packet Error Rate = 6) has been reached on a node, C0 will attempt to switch the flow of packets to an upstream cycle in hopes of reducing or eliminating the number of invalid or missing packets. Therefore, C0 will send packets via the redundant link using its IN port.

As you can see, this rerouting of packets results in zero packet errors. The steps below further explain what happens on the SynqNet network at each step during one cycle.

  1. C0 sends all 6 packets to N1 for packet verification via the redundant link using its IN port.

  2. The FPGA in N1 checks the N1 packets to make sure that all 3 packets were received. (N0 packets are ignored.) There are no invalid or missing packets, so there is no packet error at N1 during this cycle. The packets are then sent to N0.

    SqNode 0
    SqNode1
    Packet Err. Ctr
    6
    0
    Packet Err. Rate Ctr
    6
    0

  3. The FPGA in N0 checks the N0 packets to make sure that all 3 packets were received. (N1 packets are ignored.) No packets are invalid or missing, so the packet error remains at 6.
    SqNode 0
    SqNode1
    Packet Err. Ctr
    6
    0
    Packet Err. Rate Ctr
    6
    0

    NOTE: After 13 more cycles without any more packet errors, the Packet Err. Rate Ctr for N0 is decreased to 3.

    SqNode 0
    SqNode1
    Packet Err. Ctr
    6
    0
    Packet Err. Rate Ctr
    3
    0

Scenario 2 - Fail Limit is reached

After several consecutive cycles, N0 has a Packet Error Rate Counter of 11. If N0 receives one more packet error before the Packet Error Rate Counter can go down, the node will have reached the default Fail Limit (Packet Error Rate Ctr = 12).

Once the Fail Limit has been reached, N0 will enter the SYNQ Lost State and will disable its outputs.

Controller: Upstream Cycle

The controller also has a Packet Error Counter and a Packet Error Rate Counter for each node on the SynqNet network. The controller expects to receive 2 packets from each node every SynqNet cycle.

The controller has a Packet Error Counter for each node on the SynqNet network. The counter checks to make sure that it received two packets from every node during each SynqNet cycle. For each invalid or missing packet, the Packet Error Counter increments by one. This is a continuous counter that is automatically reset to zero after a hardware reset or can be manually reset in Motion Console.

The controller has a Packet Error Rate Counter for each node on the SynqNet network. The counter increments by one for each packet error, and decrements by one for every 16 valid packets received. The counter is an unsigned 8-bit value, and saturates at 0xFF. It is automatically reset to zero after a hardware reset or can be manually reset in Motion Console.

In the example above, the following steps occur:

  1. Node 1 (N1) sends packets upstream to Node 0 (N0).

  2. Node 0 (N0) sends packets upstream to the controller (C0).

  3. The FPGA in the controller checks the packets received from N0 and N1 to see if there were any invalid or missing packets. Since it received a missing packet from N1 the packet error counter for N1 is 1.

    SqNode 0
    SqNode1
    Packet Err. Ctr
    0
    1
    Packet Err. Rate Ctr
    0
    1

Scenario 1 - Fault Limit is reached

After several consecutive cycles, C0 has accumulated 6 packet errors and a Packet Error Rate Counter of 4 (the default Fault Limit for the controller) while using the normal upstream route (N1 > N0 > C0).

Once the Fault Limit (Packet Error Rate = 4) has been reached on the controller,

<What happens???>

Scenario 2 - Fail Limit is reached

After several consecutive cycles, the controller shows that N1 has a Packet Error Rate Counter of 7. If the controller receives one more invalid or missing packet from N1 before the Packet Error Rate Counter can go down, the controller will have reached the default Fail Limit (Packet Error Rate Ctr = 8) for N1.

Once the Fail Limit has been reached for N1, the network will enter the SYNQ Lost State and will disable all of its outputs.


Cabling

.

Cabling

The ring is implemented with straight through cables. In SynqNet, the master node is referred to as the "Controller," and the slave nodes are referred to as "Nodes." Each link runs from an IN port to an OUT port. IN and OUT connector pinouts are complementary (Receive+ on OUT pin 1 connects to IN pin 1 Transmit+ and so on). The IN and OUT port names are arbitrary conventions to assist in cabling systems properly since each link is bi-directional and there is no significant functional difference.

The redundant link plays no part during normal operation of SynqNet. This link will become active if fault recovery in necessary. In this example, the redundant link is shown between Node 1 and the controller. Although it may be any link in the network.

The "farthest node" has the greatest number of downstream hops from the controller; in this case it is Node 1.


Fiber Medium

.

Fiber Medium

This is described in:

IEEE 802.3-1998 Clause 26 100BASE-FX

SynqNet makes the additional requirement that the connector arrangement is the MT-RJ style such as Agilent's HFCT-5903E. In this case, there is no crossover within the connector and the crossover must be made in the fiber bundle.


Physical Layer

.

Physical Layer

The physical layers of SynqNet are taken directly from 'Ethernet' and FDDI.

IEEE 802.3-1998 | Clause 24 | 100BASE-X
IEEE 802.3-1998 | Clause 25 | 100BASE-TX
IEEE 802.3-1998 | Clause 26 | 100BASE-FX
ANSI X3.263-1995 |  | FDDI on copper

Signaling Method
 | Scrambler Seeds
 | Twisted Pair Medium
 | Fiber Medium
 | Controller LEDs
 | Node LEDs
 | Interface to the MAC
 | Selection of the PHY
Topology
 | Cabling
 | Packet Routing in Normal Operation
 | MAC Repeater Functionality
 | Input Buffer Functionality


Input Buffer Functionality

.

Input Buffer Functionality

In the upstream direction, the repeater also functions as an input buffer to improve network efficiency. Packet timeslots are scheduled for minimum packet spacing, in order to have maximum bandwidth. Yet the phase error between node timers may vary by ±16 MII clocks. Therefore an upstream packet may arrive at a node's OUT port as much as 16 clocks before the node completes sending its own packet. To prevent losing data during this "collision," the OUT port repeater FIFO will be deep enough to hold 16 nibbles of data. After the node finishes sending its own packet, a minimum number of IDLEs are inserted, and finally the upstream packet will be forwarded.


Interface of the MAC

.

Interface to the MAC

There are three interfaces between the MAC and the PHY: SMI, Transmit, and Receive.

Collectively they are referred to as the MII and are defined in IEEE 802.3-1998 Clause 22.

Transmit is a nibble wide interface that is clocked by a local 25MHz clock. The clock must always be present. If there is nothing to transmit then the TXEN line is inactive and the PHY automatically transmits IDLE symbols.

Receive is a nibble wide interface that reconstructs its clock from the received bit stream.

The SMI (serial management interface) provides a standardized method of accessing the registers within the PHY via a two-wire interface. The basic and extended register sets are defined in IEEE 802.3-1998 Clause 22. Some PHYs may support additional registers.

The SMI interface is currently not required for SynqNet, and is reserved for future use.


MAC Repeater Functionality

.

MAC Repeater Functionality

The MAC devices in the nodes act as either the originator of a packet or they can repeat the packet from one PHY to the other PHY.

The repeater function requires the use of a nibble wide FIFO in each direction. The purpose of the FIFO is two-fold:

  1. It isolates the clock domain of the receiver from the local clock domain, which is also the transmitter clock.
  2. It allows slight differences in the clock frequencies to be tolerated without losing data.

The required depth of the FIFO depends upon the maximum discrepancy between clock frequencies and the maximum packet size.

Since the frequency variation is +/- 100 PPM and the maximum packet size is 1024 bytes, the FIFO must allow for (200/1,000,000)*(1024*8) = 1.6 bits of variation in each packet. It is critical that the repeater delay must be both consistent and known. The delay must be known in order to correctly calculate SynqNet time slot assignments. Fluctuations in repeater delay during cyclic operation may cause errors. Note that it is not required that all nodes have identical delays.


Packet Routing in Normal Operation

.

Packet Routing in Normal Operation

Downstream | Upstream

In normal operation, packets are routed downstream from the controller to nodes, and upstream from nodes to controller.

Downstream Packet Routing

Downstream Packets proceed as indicated from controller to all nodes. Each node forwards (repeats) each downstream packet as it is received. All packets eventually reach all nodes.

The redundant link is essentially ignored in this situation. However, it is critical for fault recovery. To make fault recovery possible, the controller is actually sending identical packet streams on both the IN and OUT ports, however Node 1 is aware that its OUT port is redundant, therefore that stream is ignored.

Upstream Packet Routing

Upstream packets proceed as indicated from each node to the controller. Each node forwards (repeats) each packet as it is received from node to node. All packets eventually reach the controller (but all nodes do not see all upstream packets).

The redundant link plays no part in the flow of upstream packets. However, it is critical for fault recovery. To make fault recovery possible, the controller will accept packets arriving at either the OUT or IN ports. SynqNet timeslot allocation ensures that packets will not collide by arriving on both ports at the same time.


Scrambler Seeds

.

Scrambler Seeds

Each PHY devices shall be arranged to have a different scrambler seed and thereby reduce RF emissions.


Selection of the PHY

.

Selection of the PHY

Although any PHY, meeting the requirements of IEEE 802.3-1998, should function correctly with any FPGA implementation of a SynqNet MAC, there are certain potential sources of incompatibility that must be carefully guarded against. These include:

  • Poorly characterized portions of the MII timing.
  • Use of non-standard registers via the SMI.

At this time, only two devices have been tested and recommended for SynqNet: Broadcom's BCM5221 and BCM5222.


Signaling Method

.

Signaling Method

A detailed description of the signaling method can be found in ANSI X3.263-1995 and IEEE 802.3-1998 Clauses 24-26. However, a brief summary is provided below.

The signaling scheme is strictly point-to-point, i.e. one transmitter is connected to one receiver. Each link is full duplex, i.e. capable of transmitting and receiving simultaneously. The electronic component sited at each end of the link is known as a PHY. A typical setup is illustrated below:

The data is presented to and retrieved from the PHY on separate four-bit wide data paths.

The PHY block itself is a complex device. Data is accepted as 'nibbles' at a rate of 25MHz. Each nibble is mapped from a four-bit data set to a five-bit symbol. This type of mapping ensures that there are sufficient transitions to permit clock recovery and it also allows control symbols to be transmitted. The symbols are then scrambled to avoid peaks in the emission spectrum from the cabling. The scrambled symbols are then converted to a serial bit-stream that is NRZI encoded (transitions on 1s; no transitions on 0s) so as to lower the edge rate. Finally, this bit stream is presented to the copper twisted pair or fiber as appropriate. The receive process is naturally the reverse of the transmit process.

The transmit process is illustrated below:

The PHY is also responsible for ensuring the correct byte alignment. In addition to data symbols, the PHY supports the following control symbols:

Symbol Name | Meaning
/H | HALT, transmitted to indicate a fault condition such as a bad packet
/I | IDLE, transmitted when there is no packet to transmit
/J/K | SSD, two symbols used to indicate the start of a packet
/T/R | ESD, two symbols used to indicate the end of a packet

In its inactive condition the transmitter sends IDLE symbols, which ensures that the receiver is provided with transitions so that clock recovery can occur correctly at the receiver.

The IDLE symbols are also necessary to ensure that the descrambler can be trained to operate correctly at the receiver. The scrambler is guaranteed (ANSI X3.263-1995 Clause 7.2.3.2.2) to acquire synchronization after 30 error free bits including several IDLEs and /J /K (i.e. four IDLE symbols before the start of transmission). The PHY will detect an error condition (ANSI X3.263-1995 Clause 7.2.3.3) if four IDLE symbols are not found within each 1.5ms period. Some PHY watchdogs are stricter and require eight or even twelve IDLE symbols every 722ms (8k bytes). SynqNet fulfils this requirement during the SYNQ network operational phase by ensuring that sufficient idle time is present per communication cycle. As a result, 2kHz is the minimum cyclic rate, unless other measures are taken to insert IDLEs.


Twisted Pair Medium

.

Twisted Pair Medium

Overview | Cable Shielding | Controller Shielding | Node Shielding

Overview

This is described in the following documents. SynqNet follows these two documents in every respect.

IEEE 802.3-1998 | Clause 25 | 100BASE-X
ANSI X3.263-1995 |  | FDDI on copper

SynqNet has defined two standard connectors: RJ-45 and Micro-D. The RJ-45 connector is standard for commercial 100BT applications and conforms to CAT-5. MEI currently uses the RJ-45 connector in a horizontal orientation. If you wish to use a vertical RJ-45, please contact MEI.

As an alternative to the RJ-45, where additional tolerance of vibration is required, the commercial Micro-D connector (Molex Part No. 83611-9006) is supported. MEI currently uses the Micro-D connector in a horizontal orientation. If you wish to use a vertical Micro-D, please contact MEI.

The cabling scheme uses straight through cables. The crossover of transmit and receive is carried out at the connectors. These two pinouts have been named the "OUT" port and the "IN" port to assist in the setup of hardware , but remember that each port is full duplex and has the ability to transmit and receive data. Please see the following links for pinout information: Micro-D or RJ-45.

Cable Shielding

SynqNet defines cable shielding conventions in order to properly isolate local node signals and power while minimizing EMI (both emission and reception). Shielded cabling is strongly recommended for SynqNet. This will reduce EMI coupled from other devices in the system. The cables shall have their shields connected to the metal connector shell using the crimped collar (on RJ-45s) or clamp (on Micro-D). The use of unshielded cabling is permitted but not preferred. Cable shield connections are treated slightly differently at the controller and node PCBs. Both are detailed below.

Controller Shielding

Controller shielding follows standard 100BT NIC design conventions: the connector shell shall tie to the bracket or front panel, and not directly connected to the controller's local digital ground (the host computer chassis is responsible for grounding the chassis, which is normally tied to a safety ground at a central point along with digital ground). The cable shield shall also tie to an isolated plane section on the controller PCB to minimize EMI.

Node Shielding

Node shielding shall be DC isolated from port to port and from local node chassis, as well as from ground and power signals. (Molex offers an insulated screened connector that makes this a lot easier to implement: PN 85504.) This prevents currents at DC or main frequency from circling the ring, or coming back via some system ground path. The shields are AC coupled via capacitors (one for each port) to a nearby earth point on the node and/or machine chassis. The capacitor value shall be between 1 nF and 10 nF, and the rated voltage shall be 2000 V. This capacitor reduces EMI by dumping high frequency energy to the earth ground. The cable shields are also tied to isolated plane sections (one for each port) on the node PCB to minimize EMI.

In conformance with normal industrial practice it is recommended that the local logic power supplies within a node should be derived using a local isolating power supply and that the 0V should be grounded locally.


CONTROL Packet

.

CONTROL Packet

The CONTROL packet is sent from the contoller to each node in CYCLIC phase. It is also used for configuration during the DISCOVERY phase. The CONTROL packet contains only service channel data during DISCOVERY phase. In CYCLIC phase, it also contains various I/O data: I/O outputs, compare values, capture flags, and compare flags.

NOTE: The controller may require that the fields of the configured packet structure lie on natural boundaires. In which case, it may be necessary to create dummy fields.

Data | Bits | DataType and modules | Packet Section
packetType 0x05 CONTROL | 8 |  | Header (Fixed)
nodeAddress | 8
serviceFlags | 16 | serviceFlags (all modules) | Service (Required)
serviceAddress | 32 | serviceAddress (all modules)
serviceData | 32 | serviceData (all modules)
dedicatedOut | 16 | dedicatedOut | Axis[0] Configurable
ioOut | 16 | ioOut
captureCommand | 16 | captureFlags (capture2 Module)
compareCommand | 16 | compareFlags (compare2 Module)
compare0 | 32 | compareData (compare2 Module)
compareN (up to 16 compares, default=2) | 32
extension | 8 | axisExtension (future modules)
each axis configured independently | 32 | As required | Axis[N] Configurable
extension (I/O, etc.) | 8 | nodeExtension (future modules) | Node Configurable
CRC | 32 |  | CRC (Fixed)


DEMAND Packet

.

DEMAND Packet

The DEMAND packet is sent from the contoller to each node in CYCLIC phase. It provides torque, velocity, or pulse data.

NOTE: The controller may require that the fields of the configured packet structure lie on natural boundaires. In which case, it may be necessary to create dummy fields.

Data | Bits | DataType and modules | Packet Section
packetType 0x04 DEMAND | 8 |  | Header (Fixed)
nodeFlags | 8 | nodeFlags | Mac (Required)
demandFlags | 16 | demandFlags | Axis[0] Configurable
demandA | 16 | demandData
demandB | 16
demandC | 16
dac0 | 16 | dacData
dac1 | 16
pulseCount | 16 | pulseData
pulsePeriod | 16
pulseInitial | 16
pulse.Width | 16
extension | 8 | demandExtension (future modules)
each axis configured independently | 32 | As required | Axis[N] Configurable
CRC | 32 |  | CRC (Fixed)

NodeFlags

Each DEMAND packet contains a 16-bit nodeFlags field.

Bit | Description | Definition
0 | upstreamFault | 1 = upstream fault threshold exceeded on controller 0 = upstream fault threshold NOT exceeded on controller Resets to 0
1 | recoveryEnable | 1 - enable node network fault recovery 0 - diable fault recovery Resets to 0
2 | led5 | 1 - turn on LED5 of this node 0 - turn off LED5 of this node Resets to 1
15:3 | Reserved |


Packet Error Counter

.

Packet Error Counter

Node | Controller

Introduction

The Packet Error Counter checks for missing or invalid packets over a SynqNet network. It is used for long-term performance monitoring (i.e. Have any errors occured since startup?). Since communication over a SynqNet network is based upon the sending and receiving of packets, it is important to monitor the data integrity of the system. Packets must be checked to ensure that they are being sent/received properly and that the packets that are sent contain the right information. The Packet Error Counter increments by one for each invalid or missing packet. There are Packet Error Counters on the individual nodes and the controller to check packets on the upstream and downstream cycle. Unlike CRC Errors, packet errors are node-specific (i.e. Nodes only check their own packets and ignore all other packets).

Node

The Packet Error Counter on each node checks to make sure that it received all three of its packets that were sent from the controller during each downstream SynqNet cycle. Each downstream cycle, a node expects to receive a SYNQ, DEMAND, and CONTROL packet. The counter is reset to zero after a hardware reset or can be manually reset in Motion Console. The counter is an unsigned 8-bit value, and saturates at a maximum of 0xFF.

Controller

The controller also has a Packet Error Counter for each node (up to 32 of each). Their function is identical to the node counters except the controller expects to receive two packets (FEEDBACK and STATUS) from each node for every upstream SynqNet cycle. The controller has individual packet error counters for each node, which count the number of upstream packet errors from each node. The counter increments by one for each invalid or missing packet. The counter is reset to zero after a hardware reset or can be manually reset in Motion Console. The counter is an unsigned 8-bit value, and saturates at a maximum of 0xFF.

See Also:

Packet Error Rate Counter
SynqNet Fault Recovery
SynqNet Failure
CRC Error Counter


Packet Error Rate Counter

.

Packet Error Rate Counter

The Packet Error Rate Counter is in charge of tracking the rate of packet errors per SynqNet cycle. If the Packet Error Rate reaches the FAULT limit, the network will attempt a SynqNet Fault Recovery (for Ring topology only). If the Packet Error Rate reaches the FAIL limit, the network will shutdown. There are Packet Error Rate Counters on the node and controller, which check packets on the upstream and downstream cycle.

The Packet Error Rate Counter also features a "pessimistic" counter function for the fault recovery and failure logic, which increments by one for every packet error received, and decrements by one for every 16th valid packet received. This provides a tolerance buffer on the network, which allows packets to be missed without having to shutdown all communication.

Therefore, if only 1 packet in 100 is bad, the counter will occasionally increment to 1 and then decrement back to zero. If 1 packet out of 10 is bad, the counter will gradually increment until fault and/or fail thresholds are reached. If communication fails completely, the Packet Error Rate Count will match the number of packets lost. The counter is an unsigned 8-bit value, and saturates at 0xFF. It is reset to zero after a hardware reset or can be manually reset in Motion Console. The counter saturates at 255 (0xFF).

See Also:

Packet Error Counter
SynqNet Fault Recovery
SynqNet Failure


FEEDBACK Packet

.

FEEDBACK Packet

The FEEDBACK packet is sent from each node to the contoller in CYCLIC phase. It provides position (encoder) feedback.

NOTE: The controller may require that the fields of the configured packet structure lie on natural boundaires. In which case, it may be necessary to create dummy fields.

NOTE: When an auxiliary encoder is present on an N axis node, it is simply appended as axis[N+1].

Data | Bits | DataType and modules | Packet Section
packetType 0x80 FEEDBACK | 8 |  | Header (Fixed)
nodeStatus | 16 | nodeStatus | Mac (Required)
feedback | 32 | feedbackData (6 parallelFeeback Module, 7 serialFeedback Module) | Axis[0] Configurable
1_tPeriod | 16 | 1/TData (1/T Module)
1_tPhase | 16
extension | 8 | feedbackExtension (future modules)
each axis configured independently | 32 | As required | Axis[N] Configurable
CRC | 32 |  | CRC (Fixed)

NodeStatus

Each FEEDBACK packet contains a 16-bit nodeStatus field.

Bit | Description | Definition
0 | downstreamFault | 1 - downstream fault threshold exceeded on node 0 - downstream fault threshold NOT exceeded on node
1 | recoveryMode | 1 - node is in recovery mode 0 - node is NOT in recovery mode
2:3 | Reserved |
7:4 | nodeState | encoded node network state (undiscovered, discovered, synqOperation, etc.)
11:8 | Reserved |
12 | ioAbort | 1 - ioAbort internal signal is asserted 0 - ioAbort internal signal is negated
13 | nodeAlarm | 1 - nodeAlarm output asserted; no current through opto 0 - nodeAlarm output negated; current through opto
14 | nodeDisable | 1 - nodeDisable input asserted (or not used); no current through opto 0 - nodeDisable input negated (normal state when used); current through opto
15 | nodeError | 1 - one or more error flags are set in the sqMac status register 0 - no node error flags set


Packet Flowchart

.

Packet Flowchart

Under normal operation, the flow of packets over a SynqNet network is the same for the string and ring topology. In one sample over the network there will be one downstream cycle and one upstream cycle.

In a downstream cycle, the controller sends 3 different types of packets for each node on the network. In the example below, 6 packets are traveling downstream because there are 2 nodes on the network. Similarly, if there were 3 nodes on the network, there would be 9 packets traveling downstream.

In an upstream cycle, each node will be sending 2 packets back to the controller. In the example below, 4 packets are traveling upstream because there are 2 nodes on the network. Similarly, if there were 3 nodes on the network, there would be 6 packets traveling upstream.

The data integrity of each packet is verified by the CRC. For more information about this type of data verification, please see the CRC Error Counters section.

For a breakdown of the various SynqNet packets, please see the Packet Formats section.


SynqNet Packet Formats

.

SynqNet Packet Formats

There are currently nine SynqNet Packet formats. Each packet is a unit of communication in a SynqNet Network. Theses packets are used by the controller to send and retrieve information about the network and its nodes. The packets that are configurable are: DEMAND, CONTROL, FEEDBACK, and STATUS. A breakdown of the packets is provided in the table below.

For information about CRC errors, please see the CRC Error Counters section.

Type | Name | Comments
0x01 | SYNQ | Sent from controller to all nodes (broadcast) in CYCLIC phase. Provides time synchronization.
0x04 | DEMAND | Sent from controller to each node in CYCLIC phase. Provides torque (or velocity, etc.) demands.
0x05 | CONTROL | Sent from controller to each node in CYCLIC or DISCOVERY phase. Provides I/O and configuration.
0x80 | FEEDBACK | Sent from each node to controller in CYCLIC phase. Provides position feedback.
0x82 | STATUS | Sent from each node to controller in CYCLIC or DISCOVERY phase. Provides I/O and configuration.
0x20 | PROBE | Sent by the controller and repeated by the nodes in VALIDATE phase. Confirms ring integrity (all nodes connected and powered up).
0x21 | RESET_REQUEST | Sent by the controller and repeated by the nodes in any network phase. Resets nodes when the controller stops sending this packet.
0x22 | RESET_COMPLETE | Sent by the controller and repeated by the nodes in the RESET phase. Confirms that all nodes have completed reset.
0x23 | CHANGE | Sent by node (not controller) when changing upstream port selection due to network fault. Sent on new upstream port.


STATUS Packet

.

STATUS Packet

The STATUS packet is sent from each node to the contoller in CYCLIC phase. It is also used for configuration in DISCOVERY phase. The STATUS packet contains only service channel data in DISCOVERY phase. In CYCLIC phase, it also contains vaious I/O data: I/O inputs, capture values, capture flags, and compare flags.

NOTE: The controller may require that the fields of the configured packet structure lie on natural boundaires. In which case, it may be necessary to create dummy fields.

Data | Bits | DataType and modules | Packet Section
packetType 0x82 STATUS | 8 |  | Header (Fixed)
nodeAddress | 8 |
serviceStatus | 16 | serviceStatus (all modules) | Service (Required)
serviceResponse | 32 | serviceResponse (all modules)
dedicatedIn | 16 | dedicatedIn | Axis[0] Configurable
ioIn | 16 | ioIn
monitorA | 16 | monitorData
monitorB | 16
monitorC | 16
adc | 16 | adcData
capture0 | 32 | captureData capture2 Module
captureN (up to 16 captures, default=2) | 32
captureStatus | 16 | captureStatus capture2 Module
compareStatus | 16 | compareStatus compare2 Module
extension | 8 | axisExtension (future modules)
each axis configured independently | 32 | As required | Axis[N] Configurable
extension (I/O, etc.) | 8 | nodeExtension (future modules) | Node Configurable
CRC | 32 |  | CRC (Fixed)


SynqNet Failure Example

.

SynqNet Failure Example

For information about packet errors, please see the Packet Error Counters section.

A SynqNet Failure occurs when a node on the network reaches its FAIL threshold. The example below explains what happens on a SynqNet network when a node has reached its Fail Limit threshold.

The default, downstream Fail Limit is when the Packet Error Rate Counter = 12
The default, upstream Fail Limit is when the Packet Error Rate Counter = 8

The table below shows the Packet Error Rate Counter at the controller and nodes during each controller period. For simplicity, the example below assumes that the Packet Error Counter and Packet Error Rate Counter are identical.

Controller Period | Node 0 | Node 1 | Controller 0 | Comments
P | 0 | 0 | N0 = 0 N1 = 0 | All nodes receive their packets. No packet errors.

The SynqNet network is operating normally and zero packets are being lost.

The next few controller periods show a problem with the downstream flow of packets from N0 to N1. Packets are not being received by N1.

Controller Period | Node 0 | Node 1 | Controller 0 | Comments
P + 1 | 0 | 3 | N0 = 0 N1 = 0 | N1 missed 3 packets.
P + 2 | 0 | 6 | N0 = 0 N1 = 0 | N1 missed 3 more packets.
P + 3 | 0 | 9 | N0 = 0 N1 = 0 | N1 missed 3 more packets.
P + 4 | 0 | 12 | N0 = 0 N1 = 0 | N1 missed 3 more packets. The default Fail Limit has been reached on N1.

The default downstream Fail Limit for each node is when the Packet Error Rate Counter = 12. In the example above, N1 reaches its Fail Limit in four consecutive cycles. Once the Fail Limit has been reached, the node will enter the SYNQ Lost State and disable its outputs. The controller stops sending packets over the network because communication has been lost with N1.

MPI Software Perspective

Node failure tolerance is supported with string, ring, or other topologies. If one or more nodes fail, the network will continue to operate in SYNQ mode, sending and receiving data to/from the good nodes. Typically, a node failure indicates a serious problem. For instance, a broken cable in a string topology, loss of power to a node, or a large number of packet errors. A node failure is not automatically recoverable, because the state of the node is unknown and network timing schedule can only be transmitted to the node at initialization time. To recover a system with failed nodes, the node or cable hardware must be repaired or replaced and then the network must be shutdown and re-initialized.

Events
When a node failure occurs, the controller will generate a MEIEventTypeSYNQNET_NODE_FAILURE status/event for the network when any node fails. The status can be read with meiSynqNetStatus(...) decoding the eventMask with mpiEventMaskBitGET(eventMask, MEIEventTypeSYNQNET_NODE_FAILURE). An application can determine the failed nodes by reading the failedNodeMask (one bit per node) with meiSynqNetStatus(...). The network node failure event generation is configured by setting the eventMask with meiSynqNetEventNotifySet(...). After the SYNQNET_NODE_FAILURE event occurs, the status/event can be cleared with meiSynqNetEventReset(...). This will allow another SYNQNET_NODE_FAILURE status/event to be triggered.

If a node fails, the controller will also generate a MEIEventTypeSQNODE_NODE_FAILURE status/event for each failed node. The status can be read with meiSqNodeStatus(...) decoding the eventMask with mpiEventMaskBitGET(eventMask, MEIEventTypeSQNODE_NODE_FAILURE). The node failure event generation is configured by setting the eventMask with meiSqNodeEventNotifySet(...). After the SQNODE_NODE_FAILURE event occurs, the status/event can be cleared with meiSqNodeEventReset(...). This will allow another SQNODE_NODE_FAILURE status/event to be triggered after the network has been re-initialized.

Node Failure Action
When any node fails, the controller can generate an action (NONE, STOP, E_STOP, or ABORT) for the motors associated with the good nodes. The default action is NONE. The nodeFailureAction configuration is a member of the MEIMotorConfig{...} structure and can be set with mpiMotorConfigSet(...).

If a node fails, the controller will automatically generate an ABORT action for the motor objects that are mapped to that node. This makes it easier for users and applications to identify node problems from the motor object.

Network Shutdown
Since the SynqNet network will continue to operate in SYNQ mode even if nodes fail, the only way to shutdown a network is to call meiSynqNetShutdown(...). To re-initialize the network, use meiSynqNetInit(...). An alternative way to shutdown and re-initialize the network is to use mpiControlReset(...), which performs a network shutdown, resets the controller, and re-initializes the network.

Examples
Here are a few possible scenarios for how an application could handle a network with failed nodes. For ring topology cases, the recovery mode is AUTO_ARM. For string topology cases, the recovery mode is DISABLED.

Ring Topology - One node fails due to loss of power

  1. Network traffic is automatically re-directed around the failed node. Network continues to operate in SYNQ mode.
  2. Controller generates a SYNQNET_RECOVERY event to the application, notifying that a re-direction occurred.
  3. Controller generates a SYNQNET_NODE_FAILURE and SQNODE_NODE_FAILURE status/event to the application, notifying that a node has failed.
  4. Application queries controller to determine the location of the fault.
  5. Application moves motors (on good nodes) to a safe location and disables servo control.
  6. User fixes node power.
  7. Application re-initializes network, re-starts machine operation.

String Topology - Single cable break causing node failures

  1. Network continues to operate in SYNQ mode, nodes downstream from the break don't receive data. Downstream nodes eventually fail when packet error rate failure limits are exceeded.
  2. Controller generates a SYNQNET_NODE_FAILURE and SQNODE_NODE_FAILURE status/event to the application, notifying that a node has failed.
  3. Application queries controller to determine the location of the fault.
  4. Application moves motors (on good nodes) to a safe location, disables servo control.
  5. User fixes broken cable.
  6. Application re-initializes network, re-starts machine operation.

There are several other variations. The motor's nodeFailureAction feature could be used to stop the motors that are not located on the faulted node(s). Or the motor's nodeFailureAction could be used to stop a select group of critical motors. Or, the motor's nodeFailureAction could be set to NONE, allowing the application to decide how respond to node failures. The general concept is to keep as much of the network/nodes functioning as possible when failures occur. This allows an application to deal with critical axes, non-critical axes, and axis relationships differently.

For example, suppose a machine has an X, Y gantry with 3 feeder axes. If the X or Y node fails, an application will want to Abort X, Y axes immediately and stop the machine operation to fix the problem. But, if a feeder axis fails, the application may want to continue X, Y control until the axes can be moved to a safe location and the feeder axes can be serviced.

Expected Behavior

A node will almost always receive ALL of its packets. An acceptable Packet Error Rate is roughly 0-1 errors per day. However, if you are experiencing one or more errors per hour, you should definitely check the data integrity of your system. A high error rate is almost always caused by a faulty cable/connector or a bad connection.

Troubleshooting

  1. Check all cables and connectors. Ensure that no cable or connector is damaged or has bent pins. If the LEDs are off at a connection, it means that communication has been lost at that port. If the cable is properly connected at that port, change the cable.
  2. Check to make sure that each node has power and that it has not been accidentally turned off.
  3. If communication problems persist, contact the node manufacturer.


SynqNet Fault Recovery

.

SynqNet Fault Recovery

On a SynqNet network, it is important that the communication between the nodes and the controller is not compromised by missing packets. If a significant number of packets are being lost, it is important that the network is able to reroute the flow of packets so that a sufficient level of data integrity can be maintained. One of the key safety features on a Ring topology is that when packets are being lost during either an upstream or downstream flow, the idle link can be used as an alternative path for sending and receiving packets.

The SynqNet Fault Recovery feature allows the network to use the idle link for correcting faulty communication without having to perform an emergency shutdown of the network. It essentially gives the system a buffer of tolerance that allows the network to continue to operate, as long as the Fail Limit has not been reached. Since the presence of a idle link is required for SynqNet Fault Recovery, this feature is NOT available on networks with String topologies.

WARNING!
If the idle cable is broken, and a second cable fails, then SynqNet Fault Recovery will not be able to fully recover from the fault. SynqNet will try to recover, but some nodes will be stranded. Presently, SynqNet does not support an event to notify the application if an idle cable fails. In the meantime, an application can periodically poll the idle cable with meiSynqNetIdleCableStatus(...) to test the connection. <link to samp app>

The example below explains what happens on a SynqNet network when a node enters the Fault Recovery mode after its Packet Error Rate Counter has reached its Fault Limit threshold. The table below shows the Packet Error Rate Counters at the controller and nodes during each controller period. For simplicity, the example below assumes that the Packet Error Counter and Packet Error Rate Counter are identical.

The default, downstream Fault Limit is when when the Packet Error Rate Counter = 6
The default, upstream Fault Limit is when when the Packet Error Rate Counter = 4

For information about packet errors, please see the Packet Error Counters section.

Controller Period | Node 0 | Node 1 | Controller 0 | Comments
P | 0 | 0 | N0 = 0 N1 = 0 | All nodes receive their packets. No packet errors.

In the example above, the SynqNet network is operating normally and all packets are being received. Since no packets are being lost, the network behaves just like a network with a String topology. Although packets are sent from both ports of the controller in a Ring topology, the Repeater on the last node blocks the packets from being received by the node when its Repeater is OFF. For example, although packets are being sent to the OUT port of N1, it is only receiving packets from its IN port. Therefore, the Repeater remains OFF at the last node in the network until the Fault Limit has been reached for a node.

The next two controller periods show a problem with the downstream flow of packets from N0 to N1. Packets are not being received by N1.

Controller Period | Node 0 | Node 1 | Controller 0 | Comments
P + 1 | 0 | 3 | N0 = 0 N1 = 0 | N1 missed 3 packets. The Repeater on N1 is OFF.
P + 2 | 0 | 6 | N0 = 0 N1 = 0 | N1 missed 3 more packets. The default Fault Limit has been reached on N1.

Once the Fault Limit has been reached (n = 6), N1 enters the Fault Recovery mode. The repeater on N1 is turned ON and N1 starts to receive its packets from its OUT port.

Controller Period | Node 0 | Node 1 | Controller 0 | Comments
P + 3 | 0 | 6 | N0 = 0 N1 = 0 | The Repeater at N1 is turned ON. N1 receives its packets from its OUT port.

In the next controller period (P + 3), zero packets are lost and the Packet Error Rate Counter for N1 remains at 6. N1 remains in Fault Recovery Mode until....

MPI Software Perspective

Network fault recovery is only supported with ring topologies. If any single network connection fails, the network traffic will be automatically re-routed around the faulty connection via the idle link. The controller can be configured to notify the host application when the fault recovery occurs.

WARNING!
If the idle cable is broken, and a second cable fails, then SynqNet Fault Recovery will not be able to fully recover from the fault. SynqNet will try to recover, but some nodes will be stranded. Presently, SynqNet does not support an event to notify the application if an idle cable fails. In the meantime, an application can periodically poll the idle cable with meiSynqNetIdleCableStatus(...) to test the connection. <link to samp app>

Events
When network fault recovery occurs, the controller will generate a MEIEventTypeSYNQNET_RECOVERY status/event. The status can be read with meiSynqNetStatus(...), decoding the eventMask with mpiEventMaskBitGET(eventMask, MEIEventTypeSYNQNET_RECOVERY). The recovery event generation is configured by setting the eventMask with meiSynqNetEventNotifySet(...). After the RECOVERY event occurs, the status/event can be cleared with meiSynqNetEventReset(...). This will allow another SYNQNET_RECOVERY status/event to be triggered.

Fault Location (Idle Cable)
The fault location can be determined using meiSynqNetIdleCableGet(...). A network with a ring topology has one idle cable. After network initialization, the default idle cable is the connection from the last node to the controller. Since no data is transmitted across this cable, it is considered to be idle. After network fault recovery, the idle cable is the connection that had the fault.

If the faulted cable is replaced or you want to test the idle cable, use meiSynqNetIdleCableStatus(...). This will send a special test packet across the idle cable to verify the upstream and downstream data path is operational. The status will report:

MEISynqNetCableStatusGOOD - communication test passed. MEISynqNetCableStatusBAD_UPSTREAM - upstream communication test failed. MEISynqNetCableStatusBAD_DOWNSTREAM - downstream communication test failed. MEISynqNetCableStatusBAD - communication test failed.

Recovery Mode
The controller supports several network fault recovery modes. It can be configured with meiSynqNetConfigGet/Set(...), using the MEISynqNetRecoveryMode enumeration:

MEISynqNetRecoveryModeDISABLED (default for string topology) - Network does not attempt to redirect network traffic around a fault.

MEISynqNetRecoveryModeSINGLE_SHOT - Network will redirect network traffic around a fault one time. A second fault will cause all nodes downstream from the fault to fail.

MEISynqNetRecoveryModeAUTO_ARM (default for ring topology) - Network will redirect network traffic around a fault each time a fault occurs. After the network traffic redirection, the controller will wait for the node(s) upstream and downstream packet error rate counters to decrement to zero until the recovery is re-armed. Then, the network will be able to respond to another fault.

Most applications will want to use the default recovery mode. If a ring topology network has marginal operational characteristics (large number of packet errors) it might be useful to set the mode to SINGLE_SHOT or DISABLED during troubleshooting. It is easier to determine the network behavior when it is not trying to recover from faults.

Examples
Here are a few possible scenarios for how an application could handle a faulted network with a ring topology. In these cases, the recovery mode is AUTO_ARM.

Single cable break causing a network fault.

  1. Network traffic is automatically re-directed around the broken cable. Network continues to operate in SYNQ mode.
  2. Controller generates a SYNQNET_RECOVERY status/event to the application, notifying that a re-direction occurred.
  3. The application queries controller to determine the location of the fault.
  4. The application decides how to recover.

    Recovery Option A:
    a) Application moves motors to safe location, disables servo control.
    b) Application notifies user and he/she fixes broken network cable.
    c) Application re-initializes by performing a network shutdown and initialization or a controller reset. Re-start machine operation.

    Recovery Option B:
    a) Application notifies user and he/she fixes broken network cable.
    b) Application verifies cable is good using meiSynqNetIdleCableStatus(...).
    c) Controller automatically re-arms fault recovery after the packet error rate counters decrement to zero. The network is ready for another recovery.

Expected Behavior

A node will almost always receive ALL of its packets. An acceptable Packet Error Rate is roughly 0-1 errors per day. However, if you are experiencing one or more errors per hour, you should definitely check the data integrity of your system. A high error rate is almost always caused by a faulty cable/connector or a bad connection.

Troubleshooting

  1. Check all cables and connectors. Ensure that no cable or connector is damaged or has bent pins. If the LEDs are off at a connection, it means that communication has been lost at that port. If the cable is properly connected at that port, change the cable.
  2. Check to make sure that each node has power and that it has not been accidentally turned off.
  3. If communication problems persist, contact the node manufacturer.


SynqNet Topologies

.

SynqNet Topologies

The MPI currently supports the following three SynqNet network topologies: String, Terminated String, and Ring. Additional topologies such as a Dual String, Ring of Rings, and Tree topology will be supported in the future.

String Topology

The String Topology is the most basic network configuration. Packets are sent downstream from the controller to the nodes. Each node repeats the downstream data to the next node. Packets are also sent upstream from the nodes to the controller. Each node repeats the upstream data to the next node. If a cable breaks, the nodes downstream from the break will no longer be able to send/receive packets to/from the controller.

NOTE: The string topology does not support fault recovery.

Terminated String Topology

The Terminated String Topology is the same as a string topology, except there is a "loop-back" connector that is added to the last node. The advantage of using a terminator on the last node is that the network initialization time is reduced, because the controller can deterministically find the last node on a network.

NOTE: The terminated string topology does not support fault recovery.

Please see the Loopback Connector page to learn how to create your own Loopback Connector.

Ring Topology

The Ring Topology is similar to the string topology, except an idle link is added between the last node and the controller. During normal operation the packet routing is identical to a string topology. If a cable breaks, the packets are automatically routed around the break using the idle link. Please see SynqNet Fault Recovery for more details.


User Configurable Packets

.

User Configurable Packets

SynqNet networks support configurable data packets. This feature makes it possible to fine tune the network traffic for optimum performance. Most applications will NOT need to configure the network packets.

During network initialization, the MPI/Controller discovers each node and reads its Node Type, Option, and FPGA DeviceVendor identifiers. The SqNodeLib library uses the node identifiers to determine an index into the resource tables. The resource tables are an array of structures containing the feature count for each node hardware and FPGA. If the SqNodeLib cannot find an exact match for the node identifiers, then it will take an educated guess and set the SqNodeInfo.id.exactMatch to 0 (FALSE). Based on the resource table, the packet data is automatically configured to match the features each node supports. Thus, features that are not supported by specific nodes have already been eliminated from the data packets.

For systems that have a large number of nodes or need to run at high sample rates, reducing the packet size can improve the control latency. If your application requires packet optimization, begin by examining the SynqNet Timing Calculations. This can be done through the MPI by using the meiSynqNetTiming(...) method. The timing calculations are based on several variables, so make sure you have all your nodes connected and all of your controller configurations set. Then, save a copy of the timing calculations. This will provide a baseline, so you can compare the timing after packet optimization.

Using the SynqNet Config methods and Packet Cfg structures you can optimize the packets by removing unused features:
meiSynqNetPacketConfigGet(...)
meiSynqNetPacketConfigSet(...)
MEISynqNetPacketCfg{...}

ALWAYS make the meiSynqNetConfigGet/Set(...) calls BEFORE mpiMotorConfigGet/Set(...), mpiMotorEventConfigGet/Set(...), mpiFilterConfigGet/Set(...), mpiAxisConfigGet/Set(...), mpiCaptureConfigGet/Set(...), and mpiCompareConfigGet/Set(...). The controller memory has several internal pointers that directly address the packet data. meiSynqNetConfigSet(...) will shutdown the network, initialize the network with the new packet data, and recalculate the internal pointers. Calls to configure the motor, filter, axis, capture, and compare objects may use these pointers. The network packets is the interface between the MPI/Controller and the node hardware. If you try to configure the motor, filter, and axis objects BEFORE configuring the packets, you might run into some trouble.

For example, if you configure a capture to trigger on a motor's dedicated home input and then use packet configuration to remove the capture data from the packets, the capture object will still have pointers to the old packet addresses. The capture object will not work properly. This type of problem can have much worse consequences if the previously configured object writes to an old packet address.

If you do not know what object configurations have been made, reset the controller. A controller reset will clear the controller's memory, initialize the network, and calculate the internal pointers. Then make your packet configurations and object configurations.

It's a good idea to make one packet configuration change at a time. Then test your application. It may not be obvious if your application uses a particular feature. It's much easier to make one change and determine the results then to make lots of changes and try to figure out which change caused problems.

After you have optimized your packet configuration and configured your objects, then read the SynqNet Timing Calculations again. Compare the baseline timing to the optimized packets timing. From the comparison, you can determine how much packet optimization improves your system. Then, you'll probably want to re-tune your servo loops to get the best performance.


Version Control

.

Version Control

Each software component has its own version number. These components have been tested together at the factory for interoperability. The software version numbers have the following format:

SW Component | Version Number | Description
Motion Console | NN.NN.nn | Major, Medium, minor
Motion Scope | NN.NN.nn |
MPI DLL | YYYYMMDD.b...r | Year, Month, Day, branch, ... rev
XMP Firmware | NNNnn | Major, minor
Controller FPGA Code | NNN | Revision
Node FPGA Code | NNNN | Revision
Drive Firmware Code | "string" | Drive Specific Format

See Also

Controller Binary Files Table
Node Binary Files: Product Table


Yaskawa DMD-4 Drive: Info Structure

.

Yaskawa DMD-4 Drive

Info Structure

/* yaskawa_dmd.h */

/*
 * Drive Info Structure
 */

#define DMDAmpStringMAX     (14)

typedef struct DMDInfoAmpRating {
    long current;      /* 0.1A peak */
    long maxCurrent;   /* 0.1A peak */
} DMDInfoAmpRating;

typedef struct DMDInfoEncoder {
    char type[DMDAmpStringMAX];
} DMDInfoEncoder;

typedef struct DMDInfoMotorMax {
    long current;           /* 10^-1 A peak  */
    long speed;             /* 100 rpm       */
    long torqueContinuous;  /* % rated torque*/
    long torquePeak;        /* % rated torque*/
} DMDInfoMotorMax;

typedef struct DMDInfoMotorRating {
    long current;           /* 10^-1 A  */
    long power;             /* W        */
    long speed;             /* 100 rpm  */
    long torque;            /* 10^-2 Nm */
} DMDInfoMotorRating;

typedef struct DMDInfoMotor {
    char                    type[DMDAmpStringMAX];
    long                    inertia;
    long                    voltage;
    DMDInfoMotorRating      rating;
    DMDInfoMotorMax         max;
} DMDInfoMotor;

typedef struct DMDInfo {
    long                    monitor;
    long                    serialNum;
    long                    version;
    DMDInfoAmpRating        ampRating;
    DMDInfoEncoder          encoder;
    DMDInfoMotor            motor;
} DMDInfo;


Yaskawa Sigma-3 Drive: Config Structure

.

Yaskawa Sigma-3 Drive

Config Structure

/* SIGMA3.h */

/*
 *	Drive Config Structure
 */
typedef struct SIGMA3Config {
    long    Pn000;    /* Function selection basis switch*/
    long    Pn001;    /* Function selection application switch*/
    long    Pn002;    /* Function selection application switch*/
    long    Pn006;    /* Function selection application switch*/
    long    Pn007;    /* Function selection application switch*/
    long    Pn008;    /* Function selection application switch*/
    long    Pn402;    /* ?? limitting torque*/
    long    Pn403;    /* Reverse limit torque*/
    long    Pn407;    /* Speed limit when torque is controlled*/
    long    Pn408;    /* Function switch related to torque*/
    long    Pn409;    /* Frequency of notch filter*/
    long    Pn40A;    /* Q-value of notch filter*/
    long    Pn40F;    /* Frequency of secondary torque of the second step instruction filter*/
    long    Pn410;    /* Q-value of secondary torque of the second step instruction filter 0.*/
    long    Pn411;    /* Torque of the third step instruction filter time constant*/
    long    Pn422;    /* Gravity compensating torque*/
    long    Pn506;    /* Brake instruction – servo off delay time*/
    long    Pn509;    /* ?? holding time*/
    long    Pn550;    /* Analog monitor one offset voltage 1000.*/
    long    Pn551;    /* Analog monitor two offset voltages 1000.*/
} SIGMA3Config;


Yaskawa Sigma-3 Drive: Info Structure

.

Yaskawa Sigma-3 Drive

Info Structure

/* SIGMA3.h */

/*
 * Drive Info Structure
 */
#define SIGMA3StringMax	(16)

typedef struct SIGMA3Info {
    long    Pn205;  /* Multi turn limit setting */
    long    Pn212;  /* Ratio of PG dividing frequency (pulse units) */
    long    Pn401;  /* The first torque of the first step instruction filter time constant */
    long    Pn50A;  /* Input signal selection 1 */

    long    FWVersion;
    long    MotorCapacity;
    long    MotorTorque;
    long    MotorTorqueMax;

    char    SerialNumber[SIGMA3StringMax];
    char    EncoderType[SIGMA3StringMax];
    char    MotorType[SIGMA3StringMax];
} SIGMA3Info;


XMP Technology Home

.

Introduction to SynqNet
 Overview
Features / Performance

Architectural Overview
Computer Hosts
DSP
Motor Control
Motion Feedback
MPI
Safety
Clock
Analog Power Supply
Components: Main Board, Expansion Board, SIM4

Topics
Host Bus Interface
Analog Inputs
SHARC DSP subsystem
Memory Organization
Faults and Resets
XMP Data Architecture
DAC Subsystem
Default Firmware Settings
Encoder Inputs
Position Capture
Position Compare
Transceiver Components used in I/O


Analog Inputs

.

Analog Inputs

Analog signals, from such external devices as optical sensors and LVDTs, can be fed to the XMP controller. They are wired through dedicated analog lines (e.g., ANALOG_IN_0+ and _0-), then converted to digital values by the XMP controller's analog-digital converter (ADC). The ADC used in XMP controllers is an Analog Devices 16-bit AD976A. The figure below outlines the analog input subsystem for the XMP controller.

The XMP controller accepts analog inputs having a maximum dynamic range of +10V or -10V, and converts these to 16-bit digital values within the ADC. 17 kHz noise filtering at the inputs removes unwanted voltage spikes. Because the highest digital resolution is attained when analog inputs are scaled to 10V, it is advantageous to rescale lower voltage inputs via the integrated programmable gain amplifier (PGA). Gain factors are individually selectable at gain select = 1, 2, 4, and 8, for ±10V, ±5V, ±2.5V, and ±1.25V inputs, respectively.

The multiplexer provides fault protection as well as channel selection. With no power applied, the switches are OFF. Overvoltage clamps become activated at ±13.5V.

ADC Subsystem Specifications
Max. Input Voltage | ± 10V
Input Ranges | ± 1.25V; ± 2.5V; ± 10V; or, ± (%)V
Resolution | 16 bits
Channels | 8
Input Impedance | 100k
Signal Bandwidth | DC - 17 kHz
Conversion Time | 10µs
Conversion Rate | Once per servo cycle (8 channels)1
DC Offset | 15mV (max.) on 10V range.
Gain Uncertainty | 0.5% (max.) on 10V range.
Nonlinearity | 6 LSB

1. Please note that ADC conversion rates vary slightly, depending upon where within the servo cycle an analog change occurs. If an analog input changes near the end of the cycle, the digital conversion may occur sooner after the change than if the change occurs at the very beginning of the servo cycle.

XMP Controller Systems and Subsystems

Main Board and Expansion Board
Each XMP controller contains one main control board, capable of operating up to eight (8) axes. The main board contains the SHARC DSP, which processes all data between the host computer and motion hardware. In addition, one optional expansion board may be connected to a main board to add up to eight (8) more axes. Unlike main boards, expansion boards do NOT have their own SHARC DSP; they rely on the main board's SHARC DSP to do all digital processing.

Motion Block
Each main and expansion board has two (2) "motion blocks." Each motion block, in turn, contains four (4) "motor blocks," each of which controls one motor (see "Motor Block" below). Because motion blocks contain multiple motor blocks and are linked to all other motion blocks on the controller, it is possible to freely map one object to another. This provides the XMP controller with unprecedented flexibility and speed in coordinated motion.

A motion block is not a single piece of hardware, but actually consists of one field programmable gate array (FPGA), plus other hardware components. It is useful to think in terms of motion blocks to best understand how the XMP controller works. The motion block serves as the interface between the SHARC processor subsystem and motion I/O signals, and handles the interface to output peripherals (DACs, XCVRs, and opto-I/O), as well as the interface to feedback peripherals. Each motion block subsystem has a high speed serial interface to the SHARC DSP subsystem.

Motor Block
Contained within each motion block are four (4) "motor blocks." Motor blocks represent the most basic unit of motion control within the XMP environment. Each motor block acts as a dedicated gateway between the host computer and motion control components such as motors and encoders.

List of Figures

The next three pages illustrate overall data flow and component architecture of a typical XMP controller, including:

  • See Overall architecture: main and expansion boards below.
  • See Motion block detail below.
  • See Motor block detail below.

A study of these figures will provide some insight into an XMP controller's component layout and data flow.

Overall architecture: main and expansion boards.

Motion block detail.

Motor block detail.

DAC Circuitry

The D/A converters are 16-bit and DC-specified for high performance.

DAC circuitry.

Four pairs of DACs (eight total) are associated with each motion block. The first DAC of the pair is the Servo Command Output DAC, the second is an Auxiliary DAC for optional two-phase sinusoidal commutation support. The serial stream is shifted out of the first DAC of each pair and into the second DAC. A common latch updates all DACs.

The outputs swing ±10V to provide the Command Output voltage. The reference signal for the Command Output is each individual DAC's analog ground. Each Command Output is capable of driving a load of 10k and 220pF (typical brushless amp input over 6 feet of cable) with a slew rate of 4 V/microsec (20 Volt swing at 20 kHz). See Chapter 3 for specifications on command voltage outputs.

Note

The AD7849BR DAC used on the XMP should not need calibration. The bipolar zero error is specified at ±2 LSBs (0.6 mV) at 25° C. Between -40° C and +85° C, bipolar zero error is ±12 LSBs (3.6 mV). Calibration should not be required. The outputs are fault protected (switched to AGND) for power-on/power-off and emergency conditions.


Digital-to-Analog Converter (DAC) Subsystem

.

Digital-to-Analog Converter (DAC) Subsystem

The command link from the XMP controller to analog input servo drive is the DAC. (In contrast, stepper drives receive commands from the XMP controller via transceivers; DACs are not used for steppers.) The XMP controller can have up to two DACs per axis. DACs are separated into primary and auxiliary DACs. One channel is used for standard servo control (“primary”) and the other channel is an auxiliary, OR both channels are used for sinusoidal commutation.

Using the firmware's default settings, motors are mapped to DACs according to the table below. The firmware provides for a fully configured, 16-motor controller (consisting of a linked main and expansion board) by mapping all 16 motors to 32 DACs (16 primary, plus 16 auxiliary). If a controller consists only of one main board (8 motors), the expansion hardware to support the additional motor-DAC mappings (motors 8-15, DACs 8-15, and AuxDacs 8-15) does not exist, and the firmware ignores them.

Default firmware motor-DAC assignments.


XMP Data Architecture

.

XMP Data Architecture

This section provides a dynamic look at the XMP's data architecture, between board components, and between the controller and external devices such as drive amplifiers.

XMP Power-up Sequence

When first powering-up the XMP controller, several actions initialize the controller according to the firmware's settings and prepare it for motion control.

Power is Applied
During power-up, the host computer initializes. Power is also supplied via bus lines to the XMP controller and other devices connected to the PCI bus. The XMP controller's power supervisor waits for the bussed power supply to attain voltage thresholds (2.93 for 3.3 VDC power, and 4.63 for 5 VDC power) before powering the controller's components. Until power fully stabilizes, the board is kept in a reset condition.

Once initialized, the CPU bios polls the bus and assigns an address to each device (including the XMP controller).

PCI handshakes with SHARC DSP and Lattice
When the XMP controller's PCI receives a bus address from the host computer's CPU bios, it handshakes with the SHARC and Lattice.

FPGAs Loaded
With the FPGA's file format determined, the SHARC loads both FPGAs with the following:

  • DSP variables (including default timing parameters)
  • FPGA image
  • SIM4 FPGA image (if a SIM4 module is installed)

Firmware loaded from flash memory into the DSP
With the FPGAs loaded, the controller is now ready to load the firmware from flash memory to the DSP.

DACs calibrated and activated
At the beginning of the power-up process, the digital-to-analog converters (DACs) are kept grounded (i.e., in an inactive, OFF state) until the controller is ready to switch them in. This avoids erroneous inputs-outputs with the drive. After the DSP is loaded, the DACs are internally calibrated and activated. The system may now accept input from the drives and send commands.

Controller Initializes
The controller's boot configuration is based upon parameters stored in flash memory; these determine the controller's (and drive's) start-up behavior. One of the programmer's first tasks is to define what this "hello world" starting state ought to be immediately after power-up. In some instances, it may prove advantageous to keep a default boot configuration in flash memory, then modify it from the application during boot-up. In other instances, it may be better for the application to flash the controller's memory with an entirely new set of parameters during boot-up. The user must determine the best approach.

Controller configuration can be done using Motion Console; however, during development of an application, it is the programmer's responsibility to write code that properly configures the controller for its next session upon exit of the application. The controller should utilize safe amp enabling and hardware I/O to prevent runaway conditions during start-up.

For this example, we will assume the following safety measures:

  • The drive is configured for active high amp enabling. (That is, the drive cannot be enabled without controller input.)
  • The controller is configured to awaken with the Amp Enable line set to low (off). This should keep an active high drive disabled.
  • The controller is configured to trigger an Abort if the Position Error is greater than some specified value. Because the controller's data registers are all set to zero at start-up (including the Command and Actual Position values), any mechanical movement will produce a Position Error. By triggering an Abort based on Position Error, the controller safeguards against uncommanded moves.1

Device Driver and Operating System Loads
At this point, the XMP controller is initialized and ready for use. The next and final phase of the power-up sequence is the loading of the XMP's device driver and operating system on the host computer. This must be completed before any motion control application can be loaded and run.

The XMP controller's device driver is shipped to load manually; however, it can be reconfigured to load automatically. To view the XMP's device driver, access your operating system's Devices window. (In WindowsNT? environments, the XMP controller's device driver is labeled as MeiXMP.)

The operating system completes its loading within several seconds of the XMP's initialization.

Load Motion Control Application

Application boot-up
When a motion control application (e.g., Motion Console) is loaded, it first verifies that the XMP controller is operational. The user interface is displayed and is now available for use.

Create Control Object and Initialize Controller

Before any motion application can move axes, it must create a controller object and initialize communication. This is a standard requirement for any application which intends movement.

Homing the Motion Control System

Homing is the setting of a coordinate system through detection of a known point in space (the "home" point). A home point can be defined using a limit switch, or by detecting a signal from the encoder such as a home or index pulse. This is typically the first act a controller must perform before running the main application code.

Before homing, objects must be created and the controller must be initialized (see above). One example of a homing sequence is shown below, consisting of:

  • Configure a capture to trigger off the home input.
  • Configure a home event action.
  • Arm the capture.
  • Command a velocity move while polling the capture trigger.
  • When the trigger changes (at the home point), set the origin.
  • Move the axis to the origin.

This homing example is taken from the home1.c sample application program, which may be found in the Sample Applications module and should be studied. For sake of clarity, excerpts are included below.

Configure the Capture trigger
After the motion objects are created and the controller is initialized, the MPI must configure and arm a capture. The trigger in this example is a home sensor (limit switch) on a stage.

Define motion parameters In preparation for commanding moves, there are several motion parameters which must be defined:

Two types of moves are used for this sample homing routine: a velocity move and a trapezoidal move. The velocity move consists simply of running the axis at a set velocity, hunting for the home point, without regard to its starting and ending positions.

Because a trapezoidal move requires beginning and ending positions (and we don't know the axis coordinates until the home point is detected), the first move must be a velocity move. After coordinates are established through detection of a home point, a trapezoidal move may be used to move the axis to the origin.

Configure the home event action
The "home event" is the what we use to detect the home point. The home event could be an input from a limit switch, triggered when the axis runs into it. The home event could be a home or index pulse on the encoder. For this example, the stage's HOME switch is used as the trigger, and the trigger's input is configured to be TRUE (active edge).

The "home action" is what happens when the home is detected. In this example, the programmer has decided to define the action as a command to STOP the axis.

Arm the Trigger
With the home event and action defined, all that is left is to "arm" the trigger by setting the mpiCaptureArm to TRUE. Recall that earlier, this was set to FALSE to "disarm" the system.

Start a Velocity Move
With the capture event and action defined, and the trigger armed, we are ready to hunt for the home point. This is accomplished by commanding a velocity move. Before the axis can be commanded, however, the XMP controller must first enable the drive. In this example, it is assumed that the drive is wired to be an active high type; therefore, the Amp Enable line is set to high (on). Drive enabling via software must be done as a separate code item and is not shown here:

As the leadscrew rotates, the slide approaches the home sensor.

Poll Trigger Status
With the trigger armed, the software's next task is to poll the status of the trigger while the axis continues rotating.

Home Event Detected
As the axis motor continues turning, the leadscrew rotates until the stage makes contact with the home sensor; this acts as the trigger. When the trigger event is detected, the encoder position is captured and a stop action is initiated.

Define the home position as the origin
When the home pulse is detected in our example, another simultaneous action is initiated: the axis's position is captured by the FPGA. At this point, the axis position is recorded in memory. Meanwhile, the axis slows to a stop. The mpiAxisOriginSet command is then used to set the capture position to zero, making it the new origin of the axis's coordinate system.

Move axis to the (new) origin
Our sample homing routine's last task is to move the axis to the origin. Recall that the home pulse was detected while in motion, and that after detection, the axis coasted to a stop. This means that the axis is now somewhere beyond the home point (our new origin).

Because we now have a coordinate system, we can perform a backward trapezoidal move from the current position to the intended position (the origin).

Delete Objects
Finally, the homing routine must delete the objects it has created. This is performed with a number of deletion objects such as mpiMotionDelete, mpiAxisDelete, mpiMotorDelete, etc.

Internal Data Movement via "Riptide"
Within a typical SHARC timer cycle, data is moved back and forth between the SHARC and the FPGAs and various feedback devices (e.g., encoders, resolvers, etc.). On the XMP controller, this is performed over a proprietary, dedicated data bus called the "Riptide." The Riptide is the serial backbone of all motion data flow. Within a given SHARC cycle, data moves first from the SHARC to the FPGAs, and then to the drives. Within the same cycle, data is moved in the opposite direction (inbound) from the drive and encoder(s) to the SHARC.

As more drives and encoders are added to the motion control system, the required data bandwidth increases across the Riptide, occupying a greater portion of the foreground tasks.

1. IMPORTANT! Use of Position Error and other positional inputs as safeguards assumes: a) good data connection between the encoder(s) and controller; b) normal conditions. If a higher level of safety is required, then extra measures should be utilized, such as broken encoder wire detection.


Encoder Inputs

.

Encoder Inputs

Each motion block provides up to five encoder interfaces (4 axes plus 1 auxiliary), with the following features:

  • 20 MHz maximum count rate (5 MHz quadrature cycle)
  • Digital noise filtering
  • Broken wire and illegal state detection

Having five (5) encoders allows an encoder to each axis, plus a fifth encoder for master-slave, master-cam or dual-loop operations. Each motion block has features for position capture and position compare. Digital noise filtering is enabled by default and limits the maximum count rate to 10 MHz (2.5 MHz quadrature cycle).

Position Capture

Each motion block maintains a set of ten 32-bit data capture registers (in hardware), used to store latched positions. The ten data capture registers are shared among the five encoder interfaces of each motion block. A specific capture register can be associated with any encoder (position) counter. Each capture register can be triggered by one of the five events (one from each of the five encoder interfaces). One event can trigger any number of captures, allowing probe capture of multiple axes.

Events/Data Capture Registers/Position Counters

The free-running, 32-bit position counter for any axis can be latched on the edge of an input. The latency for position capture is sub-microsecond, because the registers are implemented in hardware. The input source and polarity are configurable. The capture event can trigger on any of:

  • Twelve available RS-422 transceiver inputs per motion block
  • Dedicated Index_in (per axis)
  • Dedicated Home_in (per axis)

Additionally, the capture event trigger can be enabled or disabled with software. Capture logic may be triggered from any one of the five Event look-up tables in a given motion block FPGA (one Event look-up table per axis, plus one spare table). Each Event look-up table has seven inputs. These signals are the three Xcvr signals for that axis plus Home, Pos_LIM, Neg_LIM and Index. The Event look-up table can be configured to use either polarity of any one input or combinations of inputs (for example, capture data if Home is low and Index is high).

Event processing for data capture.

Although the Capture 0 register is normally used to capture the encoder (position) count for Axis 0, you can also use Capture 0 to capture the encoder counts for the other axes in that motion block (Axis 1,2,3), individually or as a group. Note that Capture events cannot cross between motion blocks, although you can work around this by externally wiring the axis inputs among multiple motion blocks.

External wiring between motion blocks.

Position Compare

Each motion block has a hardware register file of sixteen 32-bit registers which are used to provide compare setpoints. The sixteen registers are shared among the four axes. Buffer modes can be set up as FIFO or circular, so that compare events can occur faster than the servo update rate. Compare latency is less than 1µsec.

The compare event can set a Position_Compare output on any of the twelve available RS-422 transceiver outputs. The compare event status is also available to the DSP. The trigger event is software-configurable and will occur when the value loaded in the position compare register is either:

  • greater than the actual position
  • equal to the actual position
  • less than the actual position

In addition, the equality condition can be either transparent or latched. Note that the latched condition can be cleared. The Position_Compare output polarity is programmable and the compare output can be disabled. The register can also be read back by the host.

Scale Interpolation Modules (SIM4)

For encoders with sinusoidal outputs, the scale interpolation module provides increased position resolution for up to four axes. These outputs produce one cycle of sine and cosine analog signals for each encoder's line pair. At every sample, the scale interpolation module reads the sine and cosine levels and determines the angular position within the line pair. The sine and cosine outputs are also routed to the standard quadrature inputs, providing coarse position information.

The quadrature inputs generate 4 counts for every line pair, and the 12-bit interpolated value generates 4096 counts for each line pair. The full interpolated position is obtained by combining the number of quadrant counts divided by 4, with the position between two encoder lines. Essentially, the 12-bit scale interpolation provides a resolution increase of 1024 over the quadrature counters. To maintain accurate phase information, the sine and cosine signals are captured with simultaneous-sampling A/D converters.

Position Compare

To implement the position compare feature, the SIM4 compares the current position to a position latched in the FPGA. The A/D converters convert continuously, with a 10µsec latency.

  • 10 compare registers are available per SIM4 (4 axes).
  • Can compare two positions per servo cycle on 4 axes, or can compare 10 positions per servo cycle on 1 axis.
  • Delay from compare event to compare = 10µsec.

Position Capture

To implement the position capture feature, the SIM4 latches the full interpolated position when the user-supplied latch signal is pulsed.

Note

Different axes can be latched independently of each other.

  • 10 capture registers are available per SIM4 (4 axes)
  • Can capture two times per servo cycle on 4 axes, or can capture 10 times per servo cycle on 1 axis
  • Delay from capture event to capture = 5 µsec

For detailed information about SIM4 modules, please see Application Note 206.


Faults and Resets

.

Faults and Resets

The fault monitor circuitry detects faults and controls reset operations.

Resets

XMP system resets can occur due to hard reset (hardware reset) or soft reset (software reset). The DAC (digital-to-analog converter) outputs are disabled after both Hard Reset and Soft Reset events.

Fault monitor reset scheme.

Hard Reset
Hard resets are caused by:

  • Power-up
  • Low voltage conditions on either 5V, +15V or -15V, +12V or -12V, 3.3V
  • Software reset via the host (through Interface CPLD), or watchdog timeout
  • External reset line (TTL) activation (one dedicated input per board)

A Hard Reset occurs 400ms after power-on or fail events, and 200ms after software reset or external reset events. The Hard Reset lasts 200-400 msec, leaving the DACs with Vout switched away from the DAC and tied to the DAC's analog ground. The first write from the SHARC to the DAC will cause this switch (Vout) to shift back to the DAC for normal operations.

Soft Reset
Soft resets are caused by a watchdog timeout from the DSP's flag output, or when the host writes a key sequence to the host system registers. External reset is triggered using an external TTL input. Both software and external resets are active low. To guarantee reset when Vcc is low, the triple OR gate will operate down to Vcc = +1V. The software reset is handled by a Watchdog Timer with an adjustable timeout. The Watchdog Timer is intended to catch malfunctioning firmware. The Watchdog Timer does not monitor Vcc. The timer only responds to a timeout accompanied by a 200 ms reset. The Watchdog Timer is disabled during power-up, and following a reset of the SHARC DSP, allows the DSP to boot and begin instruction execution.

A Soft Reset will:

  • Cause all analog command outputs to switch away from the DAC to a low impedance path (to their associated analog ground).
  • Soft reset the motion blocks, causing them to clear dedicated I/O to their DSP-configured default state, and to reset the position counters and associated registers. Soft Reset will not enable the FPGA configuration to be reloaded. Note that it takes a power-on Hard Reset to cause the FPGAs to reload configurations.
  • Clear the host interface Reset Status register and all other host system registers.
  • Not reset the SHARC DSP. The host driver will soft-boot the DSP.

For the Soft Reset watchdog circuitry, a latched reset is used, which provides an added protection of not allowing a malfunctioning SHARC DSP to mistakenly write to the DAC (the Soft Reset is held until the host clears it, as part of the host's watchdog timeout recovery routine).

Power Fail Control of DAC Outputs
The DAC has embedded analog switches in the output stage. The analog switches G1 and G2 are controlled by the on-chip voltage monitor and by the dedicated reset input pin (Reset IN). A low voltage on the Reset IN input will cause G1 to open and G2 to close, clamping Vout to AGnd via a low impedance path (typically 1K ohms). This condition will remain until the reset input goes high and a valid word is written into the DAC.

DAC output protection.

The Reset IN input is the active low OR'ed condition of Hard Reset or Soft Reset.

A 65K ohm resistor from Vout to AGnd will maintain 0 volts on Vout until the supplies reach +1 volt. What happens if we lose an analog power rail? The Reset IN input will go low once one of our rails crosses the reset threshold. The Reset IN input is valid for Vdd and Vss to +1.2 volts, and below those voltage levels, the 65K ohm pulldown resistor protects the circuit.


XMP Features / Performance

.

XMP Features / Performance

XMP controllers have the following features:

  • 32-bit floating point SHARC DSP updates up to 8 coordinated axes at speeds up to 10kHz (16 axes at up to 5kHz).

  • Position feedback from incremental encoders (at count rates up to 40 MHz) and analog scales.

  • Support for up to 16 axes servos and steppers

  • 16-bit servo output resolution

  • 4 MHz digitally synthesized step output

  • Shielded high-density connectors

  • 16-bit differential analog inputs

  • Analog (joystick) jogging

  • Support for up to 82 lines of dedicated I/O (opto-isolated).

  • Centralized software tools for drive configuration, tuning, and diagnostics that are in real-time. Motion Console, Motion Scope, and VM3.

  • The use of PID or PIV control algorithms for each axis.

  • Optional scale interpolation module (SIM4) for submicron position accuracy.

  • Position Capture - The XMP can capture the exact position of one or more axes whenever a specified trigger occurs. This feature is useful for homing, probing, wafer centering, wafer mapping, and coordinate measurement applications.

  • Position Compare - The XMP includes comparison hardware to generate position of one or more axes. This feature us useful for triggering devices such as imaging subsystems.

  • On-the-fly trajectory modification

  • On-board settling

  • On-board sinusoidal commutation

  • 2D compensation tables

  • To see a full list of all the XMP features and specifications, please see the XMP Overview.


Host Bus Interface

.

Host Bus Interface

Data bussing between XMP controllers and hosting computers is similar in all cases, regardless of whether the controller is configured for PCI, CPCI, or PMC busses, or the choice of operating systems. The host communicates with the XMP using direct memory reads/writes over a 32-bit bus. The full DSP internal memory (128k bytes), external SRAM, and FLASH memory are accessible to the host, in a 32-bit flat memory window of 8 Mbytes in the PCI (or CPCI) memory map. The host bus interface includes system registers for host control of Reset, Write and Interrupt enables, system configuration, control and status.


Memory Organization

.

Memory Organization

The XMP has three memory regions: internal RAM (SRAM), external RAM (also SRAM), and flash memory. Internal RAM is split into two roughly equal sections of about 16K words (32-bit), one for code and the other for data. Another data-only region exists in external RAM. The MEIXmpData structure (defined in xmp.h) just about fills the internal RAM region. The MEIXmpBufferData structure is in the external memory region. (Almost all of the configurable parameters are in the MEIXmpData structure.)

XMP memory organization.

Immediately after power-on or reset, the SHARC loads a small boot loader (~128 words) from the bottom of flash memory into internal RAM, and then branches to the first instruction. This boot loader then loads the rest of the firmware code (~16K words) from the same flash memory page and then jumps to the first firmware instruction. The firmware then copies data into the MEIXmpData (internal RAM) and MEIXmpBufferData (external RAM) structures from identical copies stored in flash memory.

Memory Map

Memory map of XMP-PCI and XMP-CPCI.

Corrupted Flash Memory?
It is very difficult (but not impossible) to corrupt the flash memory, because there are software and hardware locks which make this improbable. If you suspect that the flash memory is being corrupted, make sure that all of your software developers know who is writing updated values to flash memory and when they are doing that. Often, one member of your software developer team is writing updated values to flash, and forgetting to tell the other team members about it.


SHARC DSP Processor Subsystem

.

SHARC DSP Processor Subsystem

The DSP processor subsystem includes the following subsystems:

  • SHARC DSP processor
  • DSP RAM
  • Flash memory
  • Host bus interface
  • Serial ports to motion blocks
  • Fault monitor
  • Clock generator
  • JTAG interface

SHARC DSP processor subsystem.

SHARC DSP Processor
The XMP's main DSP processor is a 32-bit Analog Devices 21061 Floating Point DSP (also known as the SHARC DSP) with a peak performance of 150 MFLOPs. The 21061 provides trajectory planning, coordination, interpolation and position/ velocity loop closure.

DSP RAM
External SRAM is available to the DSP for maintaining message buffers and storing data. The SRAM can be up to 2 Mbytes of zero-wait state RAM. The standard configuration is 64K x 32 bit words (256K bytes).

Flash Memory
An 8-Mbit FLASH memory stores the DSP boot code, FPGA configuration code and nonvolatile system information. The FLASH memory is rated for 100,000 write/erase cycles.

Serial Ports to Motion Blocks
The SHARC DSP communicates with the four peripheral motion blocks over two 40 Mbit/sec serial links. All DSP-to-motion block data transfers occur over these two links. Each SHARC DSP serial port connects to two motion blocks. The motion blocks are the gateways for all of the controller's I/O to the external system.


XMP Architectural Overview

.

XMP Architectural Overview

Introduction

This chapter presents a general description of the XMP controller's architecture. It is intended to help users better understand the XMP's inner workings, and also explains how hardware functions with external components such as host computers, drives, and encoders. Many components discussed in this chapter are detailed in other sections of the manual. To learn more about a specific component, please perform a keyword search.

Architectural Overview

The XMP controller is a remarkably integrated device, designed to link a host computer with industry-standard motion drives. While many motion controllers heavily task the host computer's CPU to calculate motion paths and execute commands, the XMP performs much like a computer-within-a-computer to free the host of these tasks. Because the controller dedicates itself 100 percent to the task of motion control, the host computer is tasked only with communicating high-level commands; it remains free to oversee other tasks. Meanwhile, your machine's motion drive is ensured the safest, most rapid and precise motion control possible. The XMP controller achieves this feat through a fully integrated architecture, consolidating all essential control components and subsystems onto one board.

Computer Hosts
XMP controllers can be hosted by both PCI and CompactPCI (CPCI) computers via a 32-bit direct memory interface. Remote hosting via an Ethernet (TCP/IP) connection is also available.

Digital Signal Processor (DSP)
The hardware centerpiece of the XMP is the SHARC DSP (Super Harvard ARchitecture Computer Digital Signal Processor). By taking full advantage of the DSP's horsepower, efficiency is optimized, by splitting the motion tasks between the host and XMP.

Motor Control
Each controller is capable of operating up to 16 axes (independently configurable to control a servo or stepper motor) at a sample rate of 5 KHz, or 8 axes at a sample rate of 10 kHz. Included with each axis is a high speed compare output, and a high speed capture or registration input. Each axis can also be configured to sinusoidally commutate servo motors via two analog outputs. Full tuning capability is offered with PID and advanced, post-PID filtering options for each axis, including gain-scheduling and dual-loop control. Stepper output rates can be as high as 2.5 MHz. This direct-digital pulse train can control an open or closed loop motor, enabling frequency-controlled servo operation. Axes can be configured for step-direction or clockwise-counterclockwise operation.

Motion Feedback
Motion feedback can be standard quadrature from an incremental encoder (10 MHz max, 40 MHz count rate), ±10 volt analog differential signal, or analog encoder signal routed to a 4096x Scale Interpolation Module (SIM4).

Motion Programming Interface (MPI)
The MPI (Motion Programming Interface) has two built-in software objects for easy real-time motion application control: the Event Manager and Program Sequencer. The Event Manager communicates to the XMP via the bus interface and interrupts. Multi-threaded applications can wake or put to sleep multiple threads based on user-defined events or standard MPI events, such as emergencies. The Event Manager facilitates efficient multi-threaded applications. The Program Sequencer allows onboard autonomous programs to execute instructions during each DSP sample period. Onboard XMP-handled programs require no host intervention for optimal host-processor efficiency and guaranteed time response.

Safety
Dedicated, DSP-based motion control optimizes safety: the controller's on-board watchdog timers constantly monitor handshaking, and a dedicated, general purpose E-stop input is at the ready. Each axis also has configurable, optically-isolated software and hardware limits up to 24 volts.

Clock
A phase-locked loop (PLL) clock generator provides the master clock to the DSP, PCI interface, state machines and FPGAs.

Analog Power Supply
Clean analog power is generated on ±15V power rails from Vcc. Each 8-axis controller has its own analog power supply.

XMP Components

Three key components comprise the XMP family: main boards, expansion boards, and SIM4 modules. Every XMP controller starts with one main board. Other components are added as needs dictate.

XMP main board
Every XMP controller consists of at least this component; in some cases (XMP-CPCI-3U and XMP-SERCOS-PMC) it is the only component. Each main board includes a SHARC DSP processor subsystem with up to two motion blocks each.

XMP expansion board (optional)
Connects directly to one main board (XMP-PCI and XMP-CPCI-6U only) via a ribbon cable. Adds up to two more motion blocks, with 4- and 8-axis models available.

SIM4 scale interpolation module (optional)
Plugs directly into main and/or expansion boards (XMP-PCI and XMP-CPCI-6U only) via mezzanine connectors. Up to two SIM4s may be added to each main or expansion board.

XMP boards and SIM4 modules.


Hardware

.

Select a section below.


SynqNet-XMP Hardware Home

.

Specifications
Hardware and Electrical Requirements

Select a SynqNet Controller
 CPCI
PCI
PMC

Cables

Node Binary Files: Product Table

Expansions and Add Ons
CAN

LEDs
 Controller (SynqNet and CAN)
Node

Pinouts
Select a SynqNet Node
RMB-10V-SynqNet (for analog)
SynqNet Drives

Connector Pinouts
Controller I/O
- Micro D15
- HD15
Micro D9
RJ-45
Backplane Bus Interface
CAN
Rear I/O Bus

SynqNet-XMP Quick Start Guide

SynqNet Drive Partners
 Contact Info


Backplane Bus Interface Connection

.

Backplane Bus Interface Connection

The XMP-SynqNet-CPCI controllers use a backplane bus connector.

Connector | Function
J1 | CPCI Bus
J3 | Rear I/O
J4 | (unused)
J5 | (unused)

Pin | A | B | C | D | E
1 | 5V | -12V | TRST# | +12V | 5V
2 | TCK | 5V | TMS | TDO | TDI
3 | INTA# | INTB# | INTC# | 5V | INTD#
4 | BRSVP1A4 | GND | V(I/O) | INTP | INTS
5 | BRSVP1A5 | BRSVP1B5 | RST# | GND | GNT#
6 | REQ# | GND | 3.3V | CLK | AD[31]
7 | AD[30] | AD[29] | AD[28] | GND | AD[27]
8 | AD[26] | GND | V(I/O) | AD[25] | AD[24]
9 | C/BE[3]# | IDSEL | AD[23] | GND | AD[22]
10 | AD[21] | GND | 3.3V | AD[20] | AD[19]
11 | AD[18] | AD[17] | AD[16] | GND | C/BE[2]#
12-14 | KEY AREA
15 | 3.3V | FRAME# | IRDY# | GND | TRDY#
16 | DEVSEL# | GND | V(I/O) | STOP# | LOCK#
17 | 3.3V | SDONE | SBO# | GND | PERR#
18 | SERR# | GND | 3.3V | PAR | C/BE[1]#
19 | 3.3V | AD[15] | AD[14] | GND | AD[13]
20 | AD[12] | GND | V(I/O) | AD[11] | AD[10]
21 | 3.3V | AD[09] | AD[08] | M66EN | C/BE[0]#
22 | AD[07] | GND | 3.3V | AD[06] | AD[05]
23 | 3.3V | AD[04] | AD[03] | 5V | AD[02]
24 | AD[01] | 5V | V(I/O) | AD[00] | ACK64#
25 | 5V | REQ64# | ENUM# | 3.3V | 5V


SynqNet Cables Home

.

SynqNet Cables

CBL - CAT5 MicroD / MicroD PN: C005-xxxx | -0001 200mm -0002 1.2m -0003 10m -0004 3m
RJ45 / RJ45 PN: C007-xxxx | -0001 1.2m -0002 3m -0003 10m
RJ45 / MicroD PN: C006-xxxx | -0001 1.2m -0002 10m -0003 3m
CBL / .050 SCSI, 68 Pin PN: C001-0028 | -0028 1m
uD 15(F) / DB 15(F) PN: C001-0036 |
Video 15(M) / DB 15(F) PN: C001-0037 |


CAN D-9 Connector

.

CAN D-9 Connector

The support of CAN is an assembly option on XMP-SynqNet controllers. There are currently two boards that have the CAN assembly option: XMP-SynqNet-CPCI-4c-5v-CAN and XMP-SynqNet-CPCI-4c-24v-CAN.

Pin | Signal | Description
1 | (unused) | Reserved
2 | CAN_L | CAN_L bus line dominant low
3 | CAN_GND | CAN Ground
4 | – | Reserved
5 | (CAN_SHLD) | Optional CAN Shield
6 | CAN_GND | CAN Ground
7 | CAN_H | CAN_H bus line dominant high
8 | – | Reserved
9 | CAN_V+ | CAN external supply*
* Used with opto-isolation mode


XMP-SynqNet-CPCI Home

.

SynqNet Motion Controller:
XMP-SynqNet-CPCI

Variations | Features | Assembly Options

Variations

XMP-SynqNet-CPCI-uD
PN: T011-0003
XMP-SynqNet-CPCI-RJ-CAN
PN: T011-0004
XMP-SynqNet-CPCI-Rear I/O
PN: T011-0005
XMP-SynqNet-CPCI-NM
PN: T100-0001

Features

Feature | Parameter | Specification
Processor | DSP | Analog Devices SHARC 32-bit floating point
 | Speed | 40 MHz / 150 MFLOPS
Board Interface | Connectors | RJ-45 or Micro D, CAN D-9 (optional)
 | Host Bus | Universal CPCI Slot
 | Memory Interface | 32-bit direct memory map
User I/O | Lines | 6+ dedicated ESTOP
Servo Loop | Update Rate | User programmable
 | 4 Axes Update Rate | Max: 20 kHz
 | 8 Axes Update Rate | Max: 10 kHz
Kinematic Ranges | Position, Velocity, Acceleration, Jerk | 32-bit floating point
CAN Network User I/O (optional) | Protocol | CANopen - DS401
Environment | Operating Temp. | 0-50 degrees C
 | Storage Temp. | 0-50 degrees C
 | Humidity | 20-90% RH, non-condensing
Safety | Encoder Broken Wire Detection | Enabled
 | Encoder Illegal State Detection | Enabled

Feature | Photo | Pinouts | PNs w/ Option
Backplane Bus Interface |  | pinouts | All

Assembly Options

Assembly Option | Photo | Pinouts | PNs w/ Option
Micro D |  | pinouts | T011-0003
RJ-45 |  | pinouts | T011-0004
Controller I/O |  | pinouts | T011-0003, T011-0004
Rear I/O |  | pinouts | T011-0005
CAN |  | pinouts | T011-0004


DSP Synchronization

.

DSP Synchronization

Pin | Signal
1 | Gnd
2 | SYN_XCVR_1+
3 | SYN_XCVR_1–
4 | Gnd
5 | No Connect
6 | No Connect
7 | Gnd
8 | SYN_XCVR_2+
9 | SYN_XCVR_2–
10 | Gnd


HD15 Connector

.

HD15 Connector

Pin | Signal
1 | OPTO_A
2 | OPTO_B_RTN
3 | OPTO_D
4 | OPTO_E_RTN
5 | XESTOP

Pin | Signal
6 | OPTO_A_RTN
7 | OPTO_C
8 | OPTO_D_RTN
9 | OPTO_F
10 | XESTOP_RTN

Pin | Signal
11 | OPTO_B
12 | OPTO_C_RTN
13 | OPTO_E
14 | OPTO_F_RTN
15 | SFGND

Cable Accessory

MEI offers the following cable accessory: C001-0037


SynqNet Controllers: Hardware and Electrical Requirements

.

XMP-SynqNet Controllers:
Hardware and Electrical Requirements

Environmental

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power

Below is shown a table of basic host computer electrical requirements for XMP-SynqNet controllers.

Controller | Voltage 1 | Current (Typ. amps) | Current (Max. amps)
XMP-SynqNet-CPCI 2 | + 5 VDC + 3.3 VDC + 12 VDC - 12 VDC | 0.90 1.00 0.03 0.01 | 1.40 1.60 0.05 0.01
XMP-SynqNet-PCI | +5 VDC | 2.00 | 3.00
XMP-SynqNet-RMB | +24 VDC ± 6 VDC | 0.50 | 1.00
XMP-SynqNet-PMC | +3.3 VDC | 1.00 | 1.50

1. Controller voltage required at computer or card cage.

2. Power draw for XMP-SynqNet-CPCI: 8.28 watts typ.; 13.00 watts total.


Controller LEDs

.

Controller LEDs

SynqNet | CAN
See also Node LEDs

SynqNet

SynqNet controller LEDs will BLINK to indicate a fault (or undiscovered network). A controller with no blinking LEDs is in normal cyclic operation (without faults). Each SynqNet port has two LEDs. And each LED has a particular function, which is described in further detail below.

Each controller will have four green LEDs:

LED State Table: SynqNet
LED | Port | Meaning | Controlled by | State
LED1 | OUT | Link Activity | PHY | ON = link active
 |  |  |  | OFF = link inactive
LED2 | OUT | Network Activity | MAC | ON = Tx and Rx active (cyclic phase)
 |  |  |  | BLINK = Tx only active (discovery phase)
 |  |  |  | OFF = Idle (shutdown phase), or during a network reset.
LED3 | IN | Link Activity | PHY | ON = link active
 |  |  |  | OFF = link inactive
 |  |  |  | ON = Tx
LED4 | IN | Network Activity | MAC | ON = Tx and Rx active (cyclic phase)
 |  |  |  | BLINK = Tx only active (discovery phase)
 |  |  |  | OFF = idle (shutdown phase), or during a network reset.

LED1 and LED3 = Link Activity

  • On (Link Active)
  • Off (Link Inactive)

LED2 and LED4 = Network Activity

  • On (Cyclic Phase--Tx and Rx are Active)
  • Off (Shutdown Phase--Idle State or network reset)
  • Blink (Discovery Phase--only Tx is Active)

CAN

The XMP-CAN controllers have two green LEDs. These LEDs give a visual representation of the activity on the CAN network. The locations of the LEDs vary depending on the type of XMP-CAN controller. The photos and table below show the locations and meanings of each LED.

T011-0004
XMP-SynqNet-CPCI-Dual

D9 = CAN 2
D10 = CAN 1

T014-0001
XMP-SynqNet-PCI-RJ-CAN

D8 = CAN 2
D9 = CAN 1

LED State Table: CAN
CAN1 | CAN2 | Code Executing | State
OFF | OFF | None | No power / No bootloader present
BLINK | ON | Bootloader | No firmware (waiting for firmware)
OFF | ON | Bootloader | Programming firmware
ON | ON | Firmware | No Configuration
ON | OFF |  | Bootloader present with valid firmware
ON | Fast Blinking (0.25/sec) | Firmware | CAN Bus Error
ON | Slow Blinking (1/sec) | Firmware | CAN Operational


Node LEDs

.

Node LEDs

See also Controller LEDs

SynqNet node LEDs will BLINK to indicate a fault (or undiscovered node). A node with no blinking LEDs is in normal cyclic operation without faults. Faults are reported by LEDs at two locations: the network connectors, and the FPGA.

Each SynqNet port has two LEDs. The LEDs specifically relate to the FPGA and network states. They function independently from the drive processors or other devices attached to the node. The normal state of the LEDs during normal operation is to be continuously lit. For the last node in a SynqNet string, the normal state of LED3 and LED4 is OFF, LED 5 and LED6 (when present) are ON.

for the RMB-10V2

  • LED1 - Link Activity
  • LED2 - Node State
  • LED3 - Link Activity
  • LED4 - Repeater
  • LED5 - FPGA Boot Status
RMB-10V

Each LED has a particular function which is described in further detail below.

Node LED Table
LED | Port | Meaning | Controlled by | Meaning
LED1 | IN | Link Activity | PHY | ON = Link active. Normal Operation.
 |  |  |  | OFF = Link inactive
LED2 | IN | Node State | MAC | ON = Tx and Rx are Active (Cyclic Phase) Normal Operation.
 |  |  |  | OFF = Unpowered, Reset, Inactive State. Network not cyclic.
 |  |  |  | Blink 2Hz = (Undiscovered State)
 |  |  |  | Blink 4Hz = (Discovered State)
 |  |  |  | Blink 8Hz = (SYNQ Recovery)
 |  |  |  | Blink 16Hz = (SYNQ Lost)
LED3 | OUT | Link Activity | PHY | ON = Link active. Normal Operation.
 |  |  |  | OFF = link inactive
LED4 | OUT | Repeater | MAC | ON = SYNQ operation is ON (Repeater ON). Normal Operation.
 |  |  |  | OFF = Unpowered, Reset, Inactive State (Repeater OFF).
 |  |  |  | Blink 4Hz = Tx and Rx are Active (Cyclic Phase)
 |  |  |  | Blink 8Hz = SYNQ Recovery
 |  |  |  | Blink 16Hz = SYNQ Lost
LED5 | FPGA Boot Status | Repeater | MAC (FPGA) | ON = no nodeAlarm. Normal Operation.
 |  |  |  | OFF = Unpowered or Reset
 |  |  |  | Blink = nodeAlarm. (node fault or network fault). See note below.
LED6* | FPGA Boot Status | FPGA Boot Status | Bowsprit CPLD | ON (bright) = runtime image has been loaded.
 |  |  |  | ON (dimmed) = boot image has been loaded.
* - LED6 is for Bowsprit design only (not on RMB-10V Rev 1 & 2).

The nodeAlarm Signal

Each SynqNet node has a configurable nodeAlarm signal. Normally, nodeAlarm is asserted when any of the following events occur:
- network not cyclic
- encoder fault
- drive fault (for SynqNet drives)
- ampFault (for analog motors)
When a nodeAlarm occurs, the FPGA LED will blink. On some nodes, the nodeAlarm signal is also brought to an external opto output.

NOTE: The nodeAlarm output is configured to indicate nodeAlarm, when the power is OFF.

Node State Table
Node State | LED2 | LED4*
 |  | Repeater OFF | Repeater ON
Unpowered | OFF | OFF | OFF
Reset | OFF | OFF | OFF
Undiscovered | BLINK .37Hz | OFF | OFF
Discovered | BLINK .75Hz | OFF | BLINK (same phase as LED2)
SYNQ operation | ON | OFF | ON
SYNQ lost | BLINK 1.5Hz | OFF | BLINK (opposite phase to LED2)
* - The repeater is OFF on all states when it is on the last node on the network.

Use Link LEDs to Find Cable Problems

SynqNet supports the industry standard LINK LED to assist in cabling systems. This is the same LINK functionality that is supported by the network card on a desktop workstation. Each 100BT receiver monitors the network for a valid receive signal, and turns ON the LINK LED when a valid signal is detected. Checking for a LINK LED ON at both ends of one cable confirms valid communication across the cable in both directions.

NOTE: The LINK LED does NOT need actual packet traffic to be turned ON. As long as there is a valid link connection, the LINK LED will be turned ON.

The LINK LEDs can also be used to check cables when a system is assembled. There will be two LEDs near each SynqNet connector. One is the LINK LED; the other is either CYCLIC or REPEATER. As each cable is attached, the LINK LEDs at both ends should go ON. When the nodes are undiscovered (for example, after power on), CYCLIC will be BLINKing, and REPEATER will be OFF. Therefore after installing a cable, there will be exactly one LED ON near each connector. If the LINK LED does not go ON, check that the cable connects an IN port to an OUT port. Check that the cable is NOT a crossover pinout. Check that both nodes are powered on.

The LINK LEDs can also be used to find a cable that has failed. First, perform a safe shutdown of the network. Then inspect the LEDs at the connectors. There should be exactly one LED ON near each cable connector (the second LED will be BLINKing or OFF as discussed above).


Micro D15 Connector

.

Micro D15 Connector

Pin | Signal
1 | OPTO_A
2 | OPTO_B
3 | OPTO_C
4 | OPTO_D
5 | OPTO_E
6 | OPTO_F
7 | XESTOP
8 | SFGND
9 | OPTO_A_Rtn
10 | OPTO_B_Rtn
11 | OPTO_C_Rtn
12 | OPTO_D_Rtn
13 | OPTO_E_Rtn
14 | OPTO_F_Rtn
15 | XESTOP_Rtn

Cable Accessory

MEI offers the following cable accessory: C001-0036


Micro D9 Connector

.

Micro D9 Connector

Pin | In | Out
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X)
1 | Transmit + | Receive +
2 | UUPI + | UUPI +
3 | SHLD | SHLD
4 | UUP2 + | UUP2 +
5 | Receive + | Transmit +
6 | Transmit - | Receive -
7 | UUPI - | UUPI -
8 | UUP2 - | UUP2 -
9 | Receive - | Transmit -

Cable Accessories

There are two types of Micro D Cables:

  • Micro D9 to Micro D (C005-0002)
  • Micro D9 to RJ-45 (C006-0001)

Depending on the type of SynqNet controller and SynqNet Motion Block being connected, one of the following two types of cables will be used.

Micro D9 to Micro D9
PN: C005-0002
Micro D9 to RJ-45
PN: C006-0001


XMP-SynqNet-PCI

.

SynqNet Motion Controller:
XMP-SynqNet-PCI

Variations | Features | Assembly Options | CAN

Variations

XMP-SynqNet-PCI-RJ
PN: T014-0002
XMP-SynqNet-PCI-RJ-CAN
PN: T014-0001
(includes A088-0001)
CAN-XCVR, D9, OPTO
PN: A088-0001
(Opto-Isolated)
CAN-XCVR, D9, NON-OPTO
PN: A088-0002
(NON Opto-Isolated)

Features

Feature | Parameter | Specification
Processor | DSP | Analog Devices SHARC 32-bit floating point
 | Speed | 40 MHz / 150 MFLOPS
Board Interface | Connectors | RJ-45, CAN D-9 (optional)
 | Host Bus | Universal Half-Size PCI Slot
 | Memory Interface | 32-bit direct memory map
User I/O | Connector | HD15
 | Lines | 6+ dedicated ESTOP
Servo Loop | Update Rate | User programmable
 | 4 Axes Update Rate | Max: 20 kHz
 | 8 Axes Update Rate | Max: 10 kHz
Kinematic Ranges | Position, Velocity, Acceleration, Jerk | 32-bit floating point
CAN Network User I/O (optional) | Protocol | CANopen - DS401
Environment | Operating Temp. | 0-50 degrees C
 | Storage Temp. | 0-50 degrees C
 | Humidity | 20-90% RH, non-condensing

Feature | Photo | Pinouts | PNs w/ Option
RJ-45 |  | pinouts | All
HD15 |  | pinouts | T014-0001, T014-0002

Assembly Options

The XMP-SynqNet-PCI can be also be shipped with Multiple DSP Synchronizations and CAN support. For more information, please contact us at sales@motioneng.com.

CAN

CAN-XCVR

Assembly Option | Photo | Pinouts | PNs w/ Option
CAN-XCVR |  | pinouts | A088-0001, A088-0002


XMP-SynqNet-PMC

.

SynqNet Motion Controller:
XMP-SynqNet-PMC

XMP-SynqNet-PMC
PN: T009-0001

Features

Feature | Parameter | Specification
Processor | DSP | Analog Devices SHARC 32-bit floating point
 | Speed | 40 MHz / 150 MFLOPS
Board Interface | Connectors | Micro D
 | Host Bus | Universal PMC Slot
 | Memory Interface | 32-bit direct memory map
User I/O | Lines | 6+ ESTOP
Servo Loop | Update Rate | User programmable
 | 4 Axes Update Rate | Max: 20 kHz
 | 8 Axes Update Rate | Max: 10 kHz
Kinematic Ranges | Position, Velocity, Acceleration, Jerk | 32-bit floating point
Environment | Operating Temp. | 0-50 degrees C
 | Storage Temp. | 0-50 degrees C
 | Humidity | 20-90% RH, non-condensing

Feature | Photo | Pinouts | PNs w/ Option
Micro-D |  | pinouts | All
Controller I/O |  | pinouts | All


Power Connector

.

Power Connector

Pin | Elect.
1 | Motor Power (+48 VDC)
2 | Motor Ground
3 | Motor Power (+48 VDC)
4 | Motor Ground
5 | N/C
6 | Chassis Ground
7 | Control Power (+48 VDC)
8 | Control Ground


Rear I/O Bus Connection

.

Rear I/O Bus Connection

For applications utilizing industry standard CPCI 6U, MEI can provide the following pinouts.

Pin | E | D | C | B | A | Pin
19 | No Connect | No Connect | Gnd | No Connect | No Connect | 19
18 | No Connect | No Connect | Gnd | No Connect | No Connect | 18
17 | No Connect | No Connect | Gnd | No Connect | No Connect | 17
16 | Opto_F_Rtn | Opto_F | Gnd | Opto_A_RTN | OPTO_A | 16
15 | UserIO_B3_RTN | UserIO_B3 | Gnd | UserIO_A3_Rtn | UserIO_A3 | 15
14 | Opto_E_RTN | Opto_E | Gnd | Reset_IN | XESTOP | 14
13 | Opto_C | Opto_C_RTN | Gnd | Opto_B_RTN | OPTO_B | 13
12 | No Connect | No Connect | Opto_D_RTN | No Connect | XESTOP_RTN | 12
11 | No Connect | No Connect | Opto_D | No Connect | No Connect | 11
10 | No Connect | No Connect | No Connect | No Connect | No Connect | 10
9 | No Connect | No Connect | No Connect | No Connect | No Connect | 9
8 | No Connect | No Connect | No Connect | No Connect | No Connect | 8
7 | No Connect | No Connect | No Connect | No Connect | No Connect | 7
6 | Gnd | Gnd | Gnd | Gnd | Gnd | 6
5 | SynqRec_OUT+ | SynqRec_OUT– | No Connect | SynqTrancs_OUT+ | SynqTrans_OUT– | 5
4 | 3_3V | 3_3V | 3_3V | Gnd | Gnd | 4
3 | SynqRec_IN+ | SynqRec_IN– | No Connect | SynqTrancs_IN+ | SynqTrans_IN– | 3
2 | Gnd | Gnd | Gnd | Gnd | Gnd | 2
1 | Can_Hrp | Can_LRP | No Connect | Can_Grp | Can_VRP | 1
Pin | E | D | C | B | A | Pin

Location of Rear I/O on XMP-SynqNet-CPCI-Rear I/O (T001-0005)


SynqNet RJ-45 Connector

.

SynqNet RJ-45 Connector

Pin | In | Out | Color
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X) | 100BaseT Cable
1 | Transmit + | Receive + | orange/white
2 | Transmit - | Receive - | orange
3 | Receive + | Transmit + | green/white
4 | UUPI + | UUPI + | blue
5 | UUPI - | UUPI - | blue/white
6 | Receive - | Transmit - | green
7 | UUP2 + | UUP2 + | brown/white
8 | UUP2 - | UUP2 - | brown
- | SHLD | SHLD |

UUP1 and UUP2 are "unused pair" 1 and 2. When using a standard CAT5 cable, these pairs are connected to the two unused pairs in the 4 pair (8 wire) cable.

NOTE: Standard CAT5 design practice is to terminate these pairs on the PCB to reduce noise. When using a 2 pair cable, these pins are left unconnected in the cable.

Cable Accessories

There are two types of RJ-45 Cables:

  • RJ-45 to RJ-45
  • RJ-45 to Micro D

Depending on the type of SynqNet controller and SynqNet Motion Block being connected, one of the following two type

RJ-45 to RJ-45
see Cables
Micro D to RJ-45
see Cables


VHDCI Connectors

.

VHDCI Connectors

Pin | Signal | Signal | Pin
1 | Analog_IN_0+ | Analog_IN_0- | 35
2 | Analog_IN_1+ | Analog_IN_1- | 36
3 | Gnd | AGnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

Pin | Signal | Signal | Pin
1 | EncA_A+ | EncA_A- | 35
2 | EncA_B+ | EncA_B- | 36
3 | EncA_I+ | EncA_I- | 37
4 | Enc2_A+ | Enc2_A- | 38
5 | Enc2_B+ | Enc2_B- | 39
6 | Enc2_I+ | Enc2_I- | 40
7 | Home2_IN | 5V_OUT | 41
8 | Pos_Lim2_IN | Gnd | 42
9 | Neg_Lim2_IN | HomeLim2_Rtn | 43
10 | Cmd_Dac_OUT_2+ | Cmd_Dac_OUT_2- | 44
11 | Aux_Dac_OUT_2+ | Aux_Dac_OUT_2- | 45
12 | Amp_Flt2_IN | Amp_Flt2_Rtn | 46
13 | Amp_En2_Collector | Amp_En2_Emitter | 47
14 | UserIO_A3 | UserIO_A3_Rtn | 48
15 | Xcvr2A+ | Xcvr2A- | 49
16 | Xcvr2B+ | Xcvr2B- | 50
17 | Xcvr2C+ | Xcvr2C- | 51
18 | Enc3_A+ | Enc3_A- | 52
19 | Enc3_B+ | Enc3_B- | 53
20 | Enc3_I+ | Enc3_I- | 54
21 | Home3_IN | Home3_OUT | 55
22 | Pos_Lim3_IN | Gnd | 56
23 | Neg_Lim3_IN | HomeLim3_Rtn | 57
24 | Cmd_Dac_OUT_3+ | Cmd_Dac_OUT_3- | 58
25 | Aux_Dac_OUT_3+ | Aux_Dac_OUT_3- | 59
26 | Amp_Flt3_IN | Amp_Flt3_Rtn | 60
27 | Amp_En3_Collector | Amp_En3_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr3A+ | Xcvr3A- | 63
30 | Xcvr3B+ | Xcvr3B- | 64
31 | Xcvr3C+ | Xcvr3C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_2+ | Analog_IN_2- | 67
34 | Analog_IN_3+ | Analog_IN_3- | 68


AMC DigiflexCQ Drive

.

AMC DigiflexCQ Drive

 Pinouts
Wiring Examples
Interface Schematic
Axis I/O
General Purpose and Dedicated I/O
Default Configuration
Error Codes

General Info

AMC DigiflexCRQ
Product Option ID | 0x00000001
Drive Interface | 1 (Parallel)
Uart Interface | 0
Motors | 1
Aux Encoders | 0

Motors (Axes)

Motor0 (Axis0) | Details | Comments
ADC Count | 1 | Currently not supported.
Encoder Count | 0 |
Capture Count | 1 |
Compare Count | 0 | Currently not supported.
DAC Count | 0 |
Feedback Count | 32bits |
Dedicated I/O | 16bits | Click here for details.
General Purpose I/O | 16bits | Click here for details.
Demand Configuration | Demand A | Demand B is currently not supported.
Monitor Configuration | Monitor A, B, C |
1/N Configuration | N/A |
1/T Configuration | N/A |
Step/Direction Configuration | N/A |
Pulse | N/A |

Environmental Requirements

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power Requirements

Below is shown a table of basic host computer electrical requirements for the Yaskawa DMD-4 Drive.

Voltage 1 | Current (Typ. amps) | Current (Max. amps)
+ 5 VDC | 0.90 | 1.40
+ 3.3 VDC | 1.00 | 1.60
+ 12 VDC | 0.03 | 0.05
- 12 VDC | 0.01 | 0.01

Physical Dimensions

<Put diagram here>


AMC DigiflexCQ: I/O Information

.

AMC DigiflexCQ Drive

I/O Information

General Purpose I/O

FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
GP0_00 | Out | Opto Output | User Output 0 |
GP0_01 | Out | Opto Output | User Output 1 |
GP0_02 | Out | Differential Output | User Output 2 |
GP0_03 | Out | Differential Output | User Output 3 |
GP0_04 | In | Opto Input | User Input 0 |
GP0_05 | not used |  |  |
GP0_06 | In | Opto Input | User Input 1 |
GP0_07 | In | Differential Intput | User Input 2 |
GP0_08 | In | Differential Intput | User Input 3 |
* if both, direction will default to input

Dedicated Motor I/O

Internal I/O
FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
NODE_DISABLE | In | Opto Input | Node Disable |
NODE_ALARM | Out | Opto Output | Node Alarm |

External I/O
FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
NEGLIM0 | In | Opto Input | Negative Limit |
POSLIM0 | In | Opto Input | Positive Limit |
HOME0 | In | Opto Input | Home |
BRK_APPD_0 | Out | Opto Output | Brake Output |


AMC DigiflexCRQ Drive

.

AMC DigiflexCRQ Drive

 Pinouts
Wiring Examples
Interface Schematic
Axis I/O
General Purpose and Dedicated I/O
Default Configuration
Error Codes

General Info

AMC DigiflexCRQ
Product Option ID | 0x00000000
Drive Interface | 1 (Parallel)
Uart Interface | 0
Motors | 1
Aux Encoders | 1

Motors (Axes)

Motor0 (Axis0) | Details | Comments
ADC Count | 1 | Currently not supported.
Encoder Count | 0 |
Capture Count | 1 |
Compare Count | 0 | Currently not supported.
DAC Count | 0 |
Feedback Count | 32bits |
Dedicated I/O | 16bits | Click here for details.
General Purpose I/O | 16bits | Click here for details.
Demand Configuration | Demand A | Demand B is currently not supported.
Monitor Configuration | Monitor A, B, C |
1/N Configuration | N/A |
1/T Configuration | N/A |
Step/Direction Configuration | N/A |
Pulse | N/A |

Aux0 (Axis1) | Details | Comments
ADC Count | 0 |
Encoder Count |  |
Capture Count | 1 |
Compare Count | 0 |
DAC Count | 0 |
Feedback Count | 32bits |
Dedicated I/O | 16bits |
General I/O | N/A |
Demand Configuration | N/A |
Monitor Configuration | N/A |
1/N Configuration | N/A |
1/T Configuration | N/A |
Step/Direction Configuration | N/A |
Pulse | N/A |

Environmental Requirements

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power Requirements

Below is shown a table of basic host computer electrical requirements for the Yaskawa DMD-4 Drive.

Voltage 1 | Current (Typ. amps) | Current (Max. amps)
+ 5 VDC | 0.90 | 1.40
+ 3.3 VDC | 1.00 | 1.60
+ 12 VDC | 0.03 | 0.05
- 12 VDC | 0.01 | 0.01

Physical Dimensions

<Put diagram here>


AMC DigiflexCRQ: I/O Information

.

AMC DigiflexCRQ Drive

I/O Information

General Purpose I/O

FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
GP0_00 | Out | Opto Output | User Output 0 |
GP0_01 | Out | Differential Output | User Output 1 |
GP0_02 | Out | Differential Output | User Output 2 |
GP0_03 | In | Opto Input | User Input 0 |
GP0_04 | In | Opto Input | User Input 1 |
GP0_05 | not used |  |  |
GP0_06 | In | Differential Input | User Input 2 |
GP0_07 | not used |  |  |
GP0_08 | not used |  |  |
* if both, direction will default to input

Dedicated Motor I/O

Internal I/O
FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
NODE_DISABLE | In | Opto Input | Node Disable |
NODE_ALARM | not used |  |  |

External I/O
FPGA Signal | Direction (in,out, both*) | Type | External Name | Comments
NEGLIM | In | Opto Input | Negative Limit |
POSLIM | In | Opto Input | Positive Limit |
HOME | In | Opto Input | Home |
BRK_APPD | Out | Opto Output | Brake Output |


DMD-4: Default Configuration

.

Yaskawa DMD-4 Drive

Default Configuration

Encoder

Feedback Source Select | Comments
0x01 | 00 - feedbackQuadrature module* 01 - driveMemory module 10 - feedbackSerial module 11 - Reserved Reset
* Currently only feedbackQuadrature is supported.

Capture

FPGA Signal | Direction (in,out, both*) | Open Drain? | External Name | Comments
GP0_00 | Both | No | XCVR A |
GP0_01 | Both | No | XCVR B |
GP0_02 | Both | No | XCVR C |
GP0_06 | In | No | USER 0 IN |


Yaskawa DMD-4 Drive

.

Yaskawa DMD-4 Drive

Pinouts
Wiring Examples
Interface Schematic
Axis I/O
General Purpose and Dedicated I/O
Default Configuration
Error Codes

General Info

Yaskawa DMD-4
Product Option ID | 0x00000000
Drive Interface | 4
Uart Interface | 0
Motors | 4
Aux Encoders | 1

Motors (Axes)

Motor0 (Axis0) | Details | Comments
ADC Count | 1 |
Encoder Count | 32bits |
Capture Count | 2 |
Compare Count | 0 |
DAC Count | 0 |
Feedback Count | 32bits |
Dedicated I/O | 16bits | Click here for details.
General Purpose I/O | 6bits | Click here for details.
Demand Configuration | 0x3 | Demand flags are set to Torque output
Monitor Configuration | N/A |
1/N Configuration | N/A |
1/T Configuration | N/A |
Step/Direction Configuration | N/A |
Pulse | N/A |

Environmental Requirements

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power Requirements

Below is shown a table of basic host computer electrical requirements for the Yaskawa DMD-4 Drive.

Voltage 1 | Current (Typ. amps) | Current (Max. amps)
+ 5 VDC | 0.90 | 1.40
+ 3.3 VDC | 1.00 | 1.60
+ 12 VDC | 0.03 | 0.05
- 12 VDC | 0.01 | 0.01

Physical Dimensions

<Put diagram here>


AMC DMD-4: I/O Information

.

Yaskawa DMD-4 Drive

I/O Information

General Purpose I/O

FPGA Signal | Direction (in,out, both*) | Open Drain? | External Name | Comments
GP0_00 | In | No | Opto A In |
GP0_01 | Both | Yes | Opto A Out |
GP0_02 | In | No | Opto B In |
GP0_03 | Out | Yes | Opto B Out |
GP0_04 | In | No | Opto C In |
GP0_05 | Out | Yes | Opto C Out |
* if both, direction will default to input

Dedicated Motor I/O

Internal I/O
FPGA Signal | Invert? | Open Drain? | Comments
AMP_ENABLE | No | No |
AMP_FAULT | No | No |

External I/O
FPGA Signal | External Name | Comments
NEGLIM | NEGLIMIT |
POSLIM | POSLIMIT |
HOME | HOME |
BRK_APPD | BRAKE |

Fault Status Register
Fault Status Bits | Supported | Comments
Amp Fault | Yes |
Drive Fault | Yes |
Drive Watchdog | Yes |
Drive Checksum | Yes |
Feedback Fault | No |


Glentek Omega Drive

.

Glentek Omega Drive

 Pinouts
Wiring Examples
Interface Schematic
Axis I/O
General Purpose and Dedicated I/O
Default Configuration
Error Codes

General Info

Glentek Omega
Product Option ID
Drive Interface
Uart Interface
Motors
Aux Encoders

Motors (Axes)

Motor0 (Axis0) | Details | Comments
ADC Count |  |
Encoder Count |  |
Capture Count |  |
Compare Count |  |
DAC Count |  |
Feedback Count |  |
Dedicated I/O |  |
General Purpose I/O |  |
Demand Configuration |  |
Monitor Configuration |  |
1/N Configuration |  |
1/T Configuration |  |
Step/Direction Configuration |  |
Pulse |  |

Aux0 (Axis1) | Details | Comments
ADC Count |  |
Encoder Count |  |
Capture Count |  |
Compare Count |  |
DAC Count |  |
Feedback Count |  |
Dedicated I/O |  |
General I/O |  |
Demand Configuration |  |
Monitor Configuration |  |
1/N Configuration |  |
1/T Configuration |  |
Step/Direction Configuration |  |
Pulse |  |

Environmental Requirements

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power Requirements

Below is shown a table of basic host computer electrical requirements for the Yaskawa DMD-4 Drive.

Voltage 1 | Current (Typ. amps) | Current (Max. amps)
+ 5 VDC | 0.90 | 1.40
+ 3.3 VDC | 1.00 | 1.60
+ 12 VDC | 0.03 | 0.05
- 12 VDC | 0.01 | 0.01

Physical Dimensions

<Put diagram here>


SynqNet-XMP Hardware Quick Start Guide

.

Safety Warnings
Install Controller
Connect Hardware
Install MDK (software)
Motion Console
Add New Controller
Download Controller Firmware
Check Network Information
Check Node Information
Download Node FPGAs
Check Node Configuration
Tune the Servo Control Loop(s)
Move a Motor


1. Safety Warnings

.

Quick Start Guide
SynqNet-XMP Controller

Safety Warnings

During installation, solid electrical contact must be ensured at connectors; otherwise, noise and power problems will develop. (Connections should be verified through inspection and testing.)

Standard safety rules prevail during installation of any hardware. Some are summarized below for the XMP. For more information, refer to local occupational safety regulations and the manufacturer of your motion drive.

Turn Off All Power Before Installing Equipment

Before installing any motion control equipment, including XMP controllers, power should be switched OFF. Unplug all power plugs from their sources of power.

Observe ESD Precautions

To prevent damage to controller and drive electronics due to electrostatic discharge (ESD), service personnel are cautioned to observe proper grounding during handling of components.

Grounding straps should be worn at all times when handling XMP-SynqNetTM electrical components and connection hardware.

Define and Clear a Safety Zone!

During installation and testing of motion control hardware-software, a safety zone should be defined around moving components and kept clear of personnel, hands, fingers and loose hardware. During repowering of the system, motion control components may behave erratically due to misconnected lines, or wrongly configured software settings. Sudden and unexpected moves by components can cause injury, property damage, or even death!

Under NO circumstances, should a motion system be tested or operated while personnel are within the safety zone.

Additionally, beware of flying debris from unsecured hardware operating at high speeds. The use of safety shielding is highly recommended.


2. Install Controller

.

Quick Start Guide
SynqNet-XMP Controller

Install Controller

Select the type of controller you are installing.

CPCI
PCI
PMC


3. XMP-SynqNet-CPCI Controller

.

Quick Start Guide
SynqNet-XMP Controller

CPCI

Compact PCI (CPCI) utilizes a card-type computer chassis, having a multi-pin backplane. The main advantage is smaller sizing and simplified access to electronics. There are two sizes of the CPCI: -6U and -3U. (CPCI-3U controllers are still pending from MEI.) The CPCI-6U is the larger of the two form factors and connects to the backplane bus via the jumper connector at J1. The installation of the CPCI-6U is described below.

There are currently three types of XMP-SynqNet-CPCI controllers:
XMP-SynqNet-CPCI-uD
PN: T011-0003
XMP-SynqNet-CPCI-RJ-CAN
PN: T011-0004
XMP-SynqNet-CPCI-Rear I/O
PN: T011-0005

Remove Black Caps

Each board has two screws which have been covered with black caps in order to ensure that the screw was not lost during shipment. Remove the black caps on the screws.

Install PCB into the host machine

Push the backplane bus connector at J1 into the mating connector on the host machine.

Use the locks on both ends of the bracket to fully secure the board to the host machine. Align the bracket with the machine's frame and push the connector inwards until it snaps in place. To unlock the connector, press the red lever and push out.

Locked Position

To unlock connector

Unlocked Position

For added security, use a Philips screwdriver and fasten the outer screw on each connector to the system's frame.

Here is a photo of a properly installed XMP-CPCI controller.


3. XMP-SynqNet-PCI Controller

.

Quick Start Guide
SynqNet-XMP Controller
PCI

PCI buses are found in many common desktop and tower-type computer systems. The standard XMP-SynqNet-PCI controller features a 120-pin edge connector which plugs directly into standard 5VDC PCI bus receptacles. A "universal" PCI that supports 3.3V or 5V signalling is pending from MEI. Please contact MEI for availability. All motion control I/O for the XMP-PCI controller is performed via the VHDCI connectors on the rear panel of the controller.

There are currently two types of XMP-SynqNet-PCI controllers:

XMP-SynqNet-PCI-RJ
PN: T014-0002
XMP-SynqNet-PCI-RJ-CAN
PN: T014-0001

Install PCB into the host machine

Push the 120-pin edge connector into the mating connector on the host machine.

Below is a photo of an installed XMP-SynqNet-PCI-RJ-CAN controller in a standard PCI slot on a CPU.


3. XMP-SynqNet-PMC Controller

.

Quick Start Guide
SynqNet-XMP Controller

PMC

PMC to PCI | PMC to CPCI | PMC to motherboard

PMC stands for PCI Mezzanine Card. It is an ultra-compact motion controller that provides a direct connection to SynqNet motion control networks and can be readily customized to fit the requirements of most applications. On the XMP-SynqNet-PMC controllers, the bussing occurs via the mezzanine connectors, which are mounted at one corner of the card (see photo below). PMC and CPCI adapter cards are also available, which allow the installation of the PMC card into a standard PCI or CPCI slot.

XMP-SynqNet-PMC
PN: T009-0001

PMC to PCI Adapter Card

PMC to PCI Adapter Card
MEI PN: 8001-0031

Dynamic Engineering
PN: PCI2PMC
www.dyneng.com

When mating a XMP-SynqNet-PMC card to a compatible PCI converter card, be sure that the mezzanine connectors and stand-offs all line-up correctly. Secure the two boards with the screws provided.

Below is a picture of a properly installed PMC card on a PCI adapter card. It can now be installed into any standard PCI slot.

PMC to CPCI Adapter Card

When mating a XMP-SynqNet-PMC card to a compatible CPCI converter card, be sure that the mezzanine connectors and stand-offs all line-up correctly. Secure the two boards with the screws provided.

PMC to CPCI Adapter Card
Catalyst Enterprises, Inc.
PN: 384-0040-001
www.catalyst-ent.com

Here is a properly installed PMC on a CPCI adapter card. It can now be installed into any standard CPCI slot.

PMC to Motherboard

You can also install the PMC card directly onto a motherboard that has mezzanine connectors.

Here is a picture of a properly installed PMC card on a motherboard.


4. Connect Hardware

.

Quick Start Guide
SynqNet-XMP Controller

Connect Hardware

Pick a Topology

The next step is to set up the hardware of the system based upon the selected topology. Currently, SynqNet supports the following three topologies:

For more information about the various topolgies, please see the Node Addressing section under the SynqNet Technology page.

Cable Connections: Controller to Node(s)

The type of cables needed to connect the controller to the node(s) will vary based upon the type of controller, the particular hardware features, and the type of nodes you are using in the SynqNet Network. However, regardless of these variables, the cables will be wired the same way. For example, you will always connect a cable from an OUT port and into an IN port. The following diagram will clearly illustrate this connection pattern. For more information about cables and connectors, see the SynqNet Hardware section.

Types of Connectors and Cables

Depending on the type of SynqNet ports (RJ45 or Micro D) on your Controller and Drive, you will need to use one of the corresponding cables to connect them to each other. Please see the Cables section for a list of the various cables.

The following table lists some of the common connectors and their matching cables

Feature | Connector | Cable
Controller I/O | Controller I/O | N/A
Micro-D | Micro-D | C005-0002, C006-0001
RJ-45 | RJ-45 | C007-0003, C006-0001
Rear I/O Bus | Rear I/O Bus | N/A
CAN | CAN | N/A

Power On Nodes and Check LEDs

After all of the nodes have been connected with the proper cables, power-up the system. To verify that the Nodes have been connected correctly and that each node is receiving a network and power signal, inspect the LEDs at each connector.

Each controller will have four green LEDs:

        • Two LEDs (3 and 4) at the IN port.
        • Two LEDs (1 and 2) at the OUT port.
        • For more information, please see the Controller LEDs section.

Each node will have four green LEDs:

        • Two LEDs (1 and 2) at the IN port.
        • Two LEDs (3 and 4) at the OUT port.
        • For more information, please see the Node LEDs section.

On the Controller:

LED 1 and 3 = Link Activity

  • On (Link Active)
  • Off (Link NOT Active)

LED 2 and 4 = Network Activity

  • On (Cyclic Phase--Tx and Rx are Active)
  • Off (Shutdown Phase--Idle State)
  • Blink (Discovery Phase--only Tx is Active)

On the Node:

RMB-10V-SynqNet

LED 1 and 3 = Link Activity

  • On (Link Active)
  • Off (Link NOT Active)

LED 2 = Node State

  • On (Cyclic Phase--Tx and Rx are Active)
  • Off (Unpowered, Reset, Inactive State)
  • Blink 2Hz (Undiscovered State)
  • Blink 4Hz (Discovered State)
  • Blink 8Hz (SYNQ Recovery)
  • Blink 16Hz (SYNQ Lost)

LED 4 = Repeater

  • On (SYNQ operation is ON)
  • Off (Unpowered, Reset, Inactive State)
  • Blink 4Hz (Cyclic Phase--Tx and Rx are Active)
  • Blink 8Hz (SYNQ Recovery)
  • Blink 16Hz (SYNQ Lost)


5. Install MDK (software)

.

Quick Start Guide
SynqNet-XMP Controller

Install the MDK (software)

The MDK (software) can be accessed from MEI's ftp site (ftp://ftp.motioneng.com) or from the MDK InstallShield CD-ROM. By default, all of the files are copied to the following directory: C:\MEI. The InstallShield will install the following features and libraries:
      • Motion Programming Interface (MPI)
      • Motion Console
      • Motion Scope
      • VM3
      • On-line Documentation

Installation Steps

Step 1
Click on the WinNTSetup.exe or Win32Setup.exe file.

Step 2
The InstallShield Wizard for Motion Engineering's MPI-XMP Motion Developer's Toolkit should appear. Click Next.

Step 3
If you are installing the MDK for the first time, select "Complete" and click Next. To change the default installation directory (C:\MEI), choose the "Custom" installation.

Step 4
The InstallShield is now ready to install all of the files and settings. Click Install.

Step 5
A series of windows will appear showing the progress of the installation.

The following confirmation window will appear if the installation was successful. Click Finish to exit the InstallShield.


6. Motion Console

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Open Motion Console

To open Motion Console, go Start > Programs > Motion Engineering > Motion Console. There should also be a shortcut to Motion Console and Motion Scope on the desktop.

Add New Controller

The first step is to add a new controller in Motion Console. Click on the Add New Controller icon on the toolbar. The window that pops-up will allow you to give the controller a unique identification in the Name field. For this example, we will use the default name, Controller 0.

The Controller Summary window will appear next.


7. Download New Firmware

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Download Controller Firmware

Motion Engineering's motion controllers are shipped with NULL firmware. Therefore, the next step is to download the proper firmware for the controller. Click on the FW Download button.

The "Download Firmware to Controller" window will ask you to browse for the firmware file. Choose the XMPxxxxx.bin ("xxxxx" represents the firmware version) firmware file from the mei\xmp\bin directory. The standard software release includes one XMP controller firmware file.

If you have installed custom software, there will be an additional firmware file in the same directory. Each custom firmware file is numbered: X1Pxxxxx.bin, X2Pxxxxx.bin, etc. If you are using custom firmware, select the proper custom XnPxxxxx.bin file from the same directory.

Select the proper firmware version and click OK.


8. Check Network Information

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Check Network Information

After the proper firmware has been downloaded for the controller, check the Network Information to make sure that the proper number of blocks were found. Click on the [image] button to open the SynqNet Summary Window. The SynqNet Summary window shows 1 node since the SynqNet Network that was used for this example had one RMB-10V installed.

A node refers to any SynqNet node, such as a SynqNet Drive or an RMB-10V (for analog) that is installed on a SynqNet network.


9. Check Node Information

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Check Node Information

Click on the [image] button to view the SqNode Summary window. This window provides specific information about the nodes installed on the system. SynqNet will find the nodes in the order that they are connected. The hardware setup used for this example had two nodes. Therefore, the SqNode Summary Window shows two nodes: SqNode 0 and SqNode 1. This window also shows the address information of each node.

TIP: Before proceeding on to Step 9, it is helpful to first minimize the Motion Console window.

Troubleshooting

Some of the Link LEDs on my node/drive are not ON...
If the Link LEDs are not turned ON, make sure that the drive has power. If the drive has power and Link LEDs are not ON, disconnect and reconnect the connector.

If the LEDs are not ON and the power has been verified, check to make sure that the cables are connected to the right ports.

If the Link LEDs still do not turn ON, the power has been verified, and the connections are correct, replace the cable. Another way of verifying if the cable is bad is to switch the cables. If the ports' LEDs light up with one cable and not with the other, then that cable is bad. Also, after the cables have been replaced, be sure to reset the controller in order to reinitialize the network.

For more information about the locations and meanings of LEDs please see the Controller LEDs and Node LEDs sections.

The RMB/SynqNet Node does not work straight from the box...
All RMB nodes are supplied without any FPGA image and will need to be programmed before being used. Please proceed to the next step, Download Node FPGAs.

A node is improperly ordered...
SynqNet will find the nodes in the order that they are connected. If a node is improperly ordered, retrace the wiring from the controller to the last node. Use the serial number and address information to determine if a node is not in the correct order. Or, use the drive identification information (model number, serial number, address, etc) to determine if a node is not in the correct order. If the same node types are improperly ordered, the problem can be found during motor feedback verification.

SynqNet initialized successfully, but all of the nodes were not found...
SynqNet will only tell you which nodes it found on the network. The most common cause of a node not being found is a result of a bad cable connection or a bad cable. The first step is to verify that the LEDs on the SynqNet In/Out ports are ON. If they are not on, disconnect and reconnect the connector. If the LEDs still do not turn ON, replace the cable.


10. Download Node FPGAs

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Download Node FPGAs

Motion Engineering's SynqNet nodes are shipped with boot FPGA images (*.sff). The boot image contains minimal functionality to allow the node to be accessed by the SynqNet controller. To use the node, you will first need to download the appropriate FPGA (runtime) image.

To find the appropriate FPGA (runtime) image that should be downloaded for your node, please refer to the Node Binary Files: Product Table.

There are two ways to download the Node FPGA:
- via Motion Console
- via Command Prompt

Motion Console Download

In the SynqNet Node Summary window, click on the Binary Download button.

Another window will appear that shows ... Click Browse.

Find the appropriate FPGA file and select Open. In this example, we are downloading the c0fe0029_000c.sff file for an RMB-10V.

Refresh Motion Console by maximizing the screen. The following screen should appear. Notice that the "FPGA Vendor/Device" now reflects the downloaded FPGA: 0xC0FE0029.

Command Prompt Download

Open a Command Prompt window and go to the following directory to download the proper *.sff file:

C:\MEI\XMP\bin\WinNT\sqNodeFlash -node 0 -file ..\c0fe0029_0206.sff

The selected FPGA file has been downloaded after all of the pages have been counted.

Refresh Motion Console by maximizing the screen. The following screen should appear. Notice that the "FPGA Vendor/Device" now reflects the downloaded FPGA: 0xC0FE0029.


11. Check Node Configuration

.

Quick Start Guide
SynqNet-XMP Controller

Motion Console

Check Node Configuration

After the proper drive firmware has been downloaded, click on the [image] button to check the SqNode Summary window to make sure that the proper number of drives were found.

This window provides the node configuration for each drive installed on the system. SynqNet will find the drives in the order that they are connected. The hardware setup used for this example had two drives.


12. Tune the Servo Control Loop

.

Quick Start Guide
SynqNet-XMP Controller

Tune the Servo Control Loop

After you have verified the hardware setup of the SynqNet Network using the various Motion Console summary windows, you can now tune the servo control loop in order to make a move.

Click on the [image] button to open the Motion Supervisor Summary window.

Verify that the Motion Type is set to Trapezoidal under the Config tab. Go to the Actions tab and click the Clear Fault Button.

Click on the [image] button to open the Filter Summary window.

Verify that the Algorithm is set to PID under the Config tab.

Go to the Coeffs tab and select PID from the Algorithm drop-down menu.

WARNING!
Before entering any tuning parameters, find out what are safe tuning parameters to use. Otherwise, you may damage your motors.

For our example we will use the following parameters:

(Example Parameters Only.
Not to be used for every system.)
  • 800 for Proportional Gain (Kp)
  • 8 for Integral Gain (Ki)
  • 1,200 for Derivative Gain (Kd)
  • 10,000 for Integrator Maximum at Rest (IMaxRest)

Click on the [image] button to open the Motor Summary window.

Verify that the motor Type is set to Servo under the Config tab.

Verify that the Amp Polarity is set to Inverted and check the Amp Enable checkbox to Enabled.

Click on the [image] button to open the Axis Summary window.

Under the Motion tab, enter the following parameters:

  • 10000 for Position 2
  • 0 for Position 1
  • 10000 for Velocity
  • 5000 for Acceleration
  • 5000 for Deceleration


13. Move a Motor

.

Quick Start Guide
SynqNet-XMP Controller

Move a Motor

The final step will be to execute a basic move on the motor.

Click on the [image] button to open the Motion Supervisor window and click the Actions tab. If the buttons are faded out (shown below), you will first need to map the Axes.

Click on the Config tab and Shift + Lt-Click on the Axis Map button. Then click Yes, to configure the default mapping.

Under the Actions tab, click the Zero Position button and click the Clear Fault Button. Be sure the State under the General Status tab shows Idle.

Click on the Move Pos. 2 button [image] , and the command will be executed on the motor (Axis 0) and move 10000 counts to Position 2.

Click on the Move Pos. 1 button [image], and the motor will move 10000 counts back to Position 1.

To continuously move back and forth from Position 1 to Position 2, check the Enabled check box.

Click the Move Pos. 2 button [image] , and the motor will move back and forth from Position 2 to Position 1.

Congratulations! You have successfully moved a motor using SynqNet.


SynqNet-RMB Home

.

Specifications
Overview
Variations of SynqNet-RMB

Power Requirements
Opto Input (I/O) Voltage
LEDs
COM DACs
Wiring Examples

Pinouts
VHDCI
Power
RJ-45

IMPORTANT
The RMB-10V2 only supports
SynqNet Phase 2 software.


RMB COM DACs

.

RMB COM DACs

The RMBs can be ordered with sinusoidal commutation for each axis. Models T010-0004 and T010-0005 have COM DACs and support sinusoidal commutation.

Fore more information about sinusoidal commutation, please see the Sinusoidal Commutation Application Note.


Opto Input (I/O) Voltage

.

Opto Input (I/O) Voltage

The RMB supports two types of Opto Input Voltages: 5V or 24V. To verify which type of voltage an RMB supports, check the I/O sticker.

See Also: General XMP I/O Specifications


SynqNet-RMB Overview

.

SynqNet-RMB Overview

MEI’s Remote Motion Block (RMB) is designed to connect conventional analog drives into a SynqNet™ system. Each Remote Motion Block can support up to four axes of high precision analog drives, including encoder feedback, DAC outputs, transceivers, and associated I/O.

The RMB is designed to support instances where a SynqNet drive is not available or suitable. Remote Motion Blocks are also perfect for rapid prototyping with existing machine installations.

Remote Motion Blocks allow for the integration of any drive or node on a SynqNet network. The RMB acts as the analog to digital conduit between the drive and the controller. For applications where a SynqNet node is unavailable, a RMB can easily be integrated on the network to accommodate a variety of applications and I/O.


RMB Power Connectors

.

RMB Power Connectors

Pin | Signal
1 | +24V
2 | GND


RMB Power Requirements

.

Power Requirements

Voltage | Current (Typical amps) | Current (Max amps)
+24 VDC ( [image] 6 VDC) | 0.50 | 1.00


RMB RJ-45 Connector

.

RMB RJ-45 Connector

Pin | In | Out
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X)
1 | Transmit + | Receive +
2 | Transmit - | Receive -
3 | Receive + | Transmit +
4 | (unused) | (unused)
5 | (unused) | (unused)
6 | Receive - | Transmit -
7 | (unused) | (unused)
8 | (unused) | (unused)
- | (unused) | (unused)


RMB-10V-SynqNet

.

SynqNet Block:
RMB-10V-SynqNet

Variations | Power Requirments | Connectors/Pinouts | Opto Input (I/O) Voltage |
Wiring Examples | Map of Hardware I/O to Software Signals

Variations

RMB-10V-SynqNet-4c-5v
PN: T010-0004
(5V I/O)
RMB-10V-SynqNet-4c-24v
PN: T010-0005
(24V I/O)

Power Requirements

Voltage | Current (Typical amps) | Current (Max amps)
+24 VDC ( [image] 6 VDC) | 0.50 | 1.00

Connectors/Pinouts

VHDCI | Power | RJ-45

VHDCI Connectors

Connector | Function
J0-1 | Axes 0 & 1
J2-3 | Axes 2 & 3

J0-1 VHDCI Connector

Pin | Signal | Signal | Pin
1 | Analog_IN_0+ | Analog_IN_0- | 35
2 | Analog_IN_1+ | Analog_IN_1- | 36
3 | Gnd | AGnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

J2-3 VHDCI Connector

Pin | Signal | Signal | Pin
1 | Analog_IN_0+ | Analog_IN_0- | 35
2 | Analog_IN_1+ | Analog_IN_1- | 36
3 | Gnd | AGnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

Power Connectors

Pin | Signal
1 | +24V
2 | GND

RJ-45 Connectors

Pin | In | Out
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X)
1 | Transmit + | Receive +
2 | Transmit - | Receive -
3 | Receive + | Transmit +
4 | (unused) | (unused)
5 | (unused) | (unused)
6 | Receive - | Transmit -
7 | (unused) | (unused)
8 | (unused) | (unused)
- | (unused) | (unused)

Opto Input (I/O) Voltage

The RMB Motion Blocks support two types of Opto Input Voltages: 5V or 24V. To verify which type the RMB supports, check the I/O sticker on the PCB.

See Also: General XMP I/O Specifications

Wiring Examples

A SynqNet-XMP contoller can be used with an RMB-10V to control analog motors. The wiring of motor I/O is the same as an Analog-XMP controller once the SynqNet controller has been connected to the RMB-10V.

For suggested wiring schemes, please see the Installing an XMP-Analog Motion System section in the XMP-Analog Hardware documentation. Below are examples of various hardware setups with an RMB-10V-SynqNet.

Here is an RMB-10V-SynqNet with a SynqNet controller and a test stand with four analog motors.

Here is an RMB-10V-SynqNet with a SynqNet controller, STC-136, amplifiers, and two analog motors.

Map of Hardware I/O to Software Signals

(coming soon)


Variations of SynqNet-RMB

.

Variations of SynqNet-RMB

IMPORTANT
The RMB-10V2 only supports
SynqNet Phase 2 software.

RMB-10V2-SynqNet-4c-5v
PN: T010-0004
(5V I/O)
RMB-10V2-SynqNet-4c-24v
PN: T010-0005
(24V I/O)
RMB-10V2-SynqNet-4-5v
PN: T010-0006
(5V I/O)
RMB-10V2-SynqNet-4-24v
PN: T010-0007
(24V I/O)

COM DACs

The RMBs can be ordered with sinusoidal commutation for each axis. Models T010-0004 and T010-0005 have COM DACs and support sinusoidal commutation.

Fore more information about sinusoidal commutation, please see the Sinusoidal Commutation Application Note.


RMB VHDCI Connectors

.

RMB VHDCI Connectors

Connector | Function
J0-1 | Axes 0 & 1
J2-3 | Axes 2 & 3

J0-1 VHDCI Connector

The wiring of motor I/O on an RMB-10V is the same as an Analog-XMP controller once the SynqNet controller has been connected to the RMB-10V. For suggested wiring schemes, please click on the reference link or see the Installing an XMP-Analog Motion System section in the XMP-Analog Hardware documentation.

Pin | Signal | Signal | Pin | Link
1 | Analog_IN_0+ | Analog_IN_0- | 35 | link
2 | Analog_IN_1+ | Analog_IN_1- | 36 | link
3 | Gnd | AGnd | 37 |
4 | Enc0_A+ | Enc0_A- | 38 | link
5 | Enc0_B+ | Enc0_B- | 39 | link
6 | Enc0_I+ | Enc0_I- | 40 | link
7 | Home0_IN | 5V_OUT | 41 | link
8 | Pos_Lim0_IN | Gnd | 42 | link
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43 | link
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44 | link
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45 | link
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46 | link
13 | Amp_En0_Collector | Amp_En0_Emitter | 47 | link
14 | UserIO_A0 | UserIO_A0_Rtn | 48 | link
15 | Xcvr0A+ | Xcvr0A- | 49 | link
16 | Xcvr0B+ | Xcvr0B- | 50 | link
17 | Xcvr0C+ | Xcvr0C- | 51 | link
18 | Enc1_A+ | Enc1_A- | 52 | link
19 | Enc1_B+ | Enc1_B- | 53 | link
20 | Enc1_I+ | Enc1_I- | 54 | link
21 | Home1_IN | 5V_OUT | 55 | link
22 | Pos_Lim1_IN | Gnd | 56 | link
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57 | link
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58 | link
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59 | link
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60 | link
27 | Amp_En1_Collector | Amp_En1_Emitter | 61 | link
28 | Gnd | Gnd | 62 |
29 | Xcvr1A+ | Xcvr1A- | 63 | link
30 | Xcvr1B+ | Xcvr1B- | 64 | link
31 | Xcvr1C+ | Xcvr1C- | 65 | link
32 | UserIO_A1 | UserIO_A1_Rtn | 66 | link
33 | no connect | UserIO_A2 | 67 | link
34 | NODE_DISABLE | UserIO_A2_Rtn | 68 | link

J2-3 VHDCI Connector

The wiring of motor I/O on an RMB-10V is the same as an Analog-XMP controller once the SynqNet controller has been connected to the RMB-10V. For suggested wiring schemes, please click on the reference link or see the Installing an XMP-Analog Motion System section in the XMP-Analog Hardware documentation.

Pin | Signal | Signal | Pin | Link
1 | Analog_IN_0+ | Analog_IN_0- | 35 | link
2 | Analog_IN_1+ | Analog_IN_1- | 36 | link
3 | Gnd | AGnd | 37 |
4 | Enc0_A+ | Enc0_A- | 38 | link
5 | Enc0_B+ | Enc0_B- | 39 | link
6 | Enc0_I+ | Enc0_I- | 40 | link
7 | Home0_IN | 5V_OUT | 41 | link
8 | Pos_Lim0_IN | Gnd | 42 | link
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43 | link
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44 | link
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45 | link
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46 | link
13 | Amp_En0_Collector | Amp_En0_Emitter | 47 | link
14 | UserIO_A0 | UserIO_A0_Rtn | 48 | link
15 | Xcvr0A+ | Xcvr0A- | 49 | link
16 | Xcvr0B+ | Xcvr0B- | 50 | link
17 | Xcvr0C+ | Xcvr0C- | 51 | link
18 | Enc1_A+ | Enc1_A- | 52 | link
19 | Enc1_B+ | Enc1_B- | 53 | link
20 | Enc1_I+ | Enc1_I- | 54 | link
21 | Home1_IN | 5V_OUT | 55 | link
22 | Pos_Lim1_IN | Gnd | 56 | link
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57 | link
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58 | link
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59 | link
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60 | link
27 | Amp_En1_Collector | Amp_En1_Emitter | 61 | link
28 | Gnd | Gnd | 62 |
29 | Xcvr1A+ | Xcvr1A- | 63 | link
30 | Xcvr1B+ | Xcvr1B- | 64 | link
31 | Xcvr1C+ | Xcvr1C- | 65 | link
32 | UserIO_A1 | UserIO_A1_Rtn | 66 | link
33 | no connect | UserIO_A2 | 67 | link
34 | NODE_DISABLE | UserIO_A2_Rtn | 68 | link

See Also: General XMP I/O Specifications


RMB Wiring Examples

.

Wiring Examples

A SynqNet-XMP contoller can be used with an RMB-10V to control analog motors. The wiring of motor I/O is the same as an Analog-XMP controller once the SynqNet controller has been connected to the RMB-10V.

For suggested wiring schemes, please see the Installing an XMP-Analog Motion System section in the XMP-Analog Hardware documentation. Below are examples of various hardware setups with an RMB-10V-SynqNet.

Here is an RMB-10V-SynqNet with a SynqNet controller and a test stand with four analog motors.

Here is an RMB-10V-SynqNet with a SynqNet controller, STC-136, amplifiers, and two analog motors.


SynqNet Drives Home

.

Digiflex | Digiflex | Contact Info
Omega | SQ | Contact Info
CD | DASA | Contact Info
Minas B |  | Contact Info
Q Series |  | Contact Info
SGDS | DMD-4 | Contact Info


Drive Partners: Contact Info

.

Drive Partners: Contact Info

3805 Calle Tecate Camarillo, CA 93012 Tel: 805-389-1935 Fax: 805-389-1165 | www.a-m-c.com
208 Standard Street El Segundo, CA 90245 Tel: 310-322-3026 Fax: 310-322-7709 | www.glentek.com
501 West Main Street Radford, VA 24141 1-800-77-SERVO | www.kollmorgen.com
Two Panasonic Way Secaucus, NJ 07094 Tel: 201-348-5257 Fax: 201-392-4652 | www.panasonic.com
1500 Wyatt Dr. Suite 10 Santa Clara, CA 95054 Tel: 408 988-1700 Fax: 408 982-1700 | www.sanyodenki.com
1879 Ohyasumi, Iida City, Nagano Prefecture, 395-8515, Japan Tel.265(21)1840 Fax.265(21)1865 | www.tamagawa-seiki.co.jp/english/index.html
2121 Norman Drive South Waukegan, IL 60085 Tel: 1-800-YASKAWA | www.yaskawa.com


AMC Digiflex Drive

.

AMC Digiflex Drive

Variations

Digiflex Digital Servo Drives
Model: DRQ110EE25A20NAC

 AMC Specification Sheet DRQ110EE25A20NAC
Digiflex Digital Servo Drives
Model: DRQ110EE15A8BDC

AMC Specification Sheet DRQ110EE15A8BDC

For more information, please go to http://www.synqnet.org/drives.html.


AMC Digiflex Drive: DRQ110EE15A8BDC

.

AMC Digiflex Drive: DRQ110EE15A8BDC

AMC Specification Sheet DRQ110EE15A8BDC

For more information, please go to http://www.synqnet.org/drives.html.


AMC Digiflex Drive: DRQ110EE25A20NAC

.

AMC Digiflex Drive: DRQ110EE25A20NAC

AMC Specification Sheet DRQ110EE25A20NAC

For more information, please go to http://www.synqnet.org/drives.html.


Glentek Omega Drive

.

Glentek Omega Drive

For more information, please go to http://www.synqnet.org/drives.html.


Glentek SQ Drive

.

Glentek SQ Drive

Model SMA9915
SynqNet Digital PWM Servo Amplifier

Glentek’s Omega-SynqNet Digital PWM Servo Amplifiers offer the latest in DSP control of rotary and linear, brush and brushless, servo motors combined with the power and flexibility of the SynqNet Network. The Omega-SynqNet amplifiers feature one of the industry’s highest PWM update rates (24kHz) for superior bandwidth and are designed for high performance OEM applications. These amplifiers are available in a variety of power ranges and can be configured to operate from 24-370 VDC or directly from 110-130 VAC or 208-240 VAC main lines. They accept a wide range of incremental encoder inputs including inexpensive, low-resolution encoders, reduced wire encoders, and fine-pitch linear scales and all models include dedicated optically isolated I/O (limits, enable, home and fault), general purpose controller configured optically isolated I/O, and high speed, general purpose, differential receivers and transmitters for use as input captures and output compares. Initial configuration and tuning can be performed through an RS232 port using Glentek’s Windows based MotionMaestro software or directly by the SynqNet controller. These amplifiers include extensive fault detection with associated 7-segment display diagnostics.

Links
Description
Technical Specification
Features

For more information, please go to http://www.synqnet.org/drives.html.


Kollmorgen CD Drive

.

Kollmorgen CD Drive

For more information, please go to http://www.synqnet.org/drives.html.


Kollmorgen DASA Drive

.

Kollmorgen DASA Drive

For more information, please go to http://www.synqnet.org/drives.html.


Panasonic Minas B Drive

.

Panasonic Minas B Drive

Panasonic Reference Specification MINAS-B Series-SynqNet Interface

For more information, please go to http://www.synqnet.org/drives.html.


SynqNet Drive Partners

.

SynqNet Drive Partners

3805 Calle Tecate Camarillo, CA 93012 Tel: 805-389-1935 Fax: 805-389-1165 | www.a-m-c.com
2121 Norman Drive South Waukegan, IL 60085 Tel: 1-800-YASKAWA | www.yaskawa.com
Two Panasonic Way Secaucus, NJ 07094 Tel: 201-348-5257 Fax: 201-392-4652 | www.panasonic.com
208 Standard Street El Segundo, CA 90245 Tel: 310-322-3026 Fax: 310-322-7709 | www.glentek.com
1500 Wyatt Dr. Suite 10 Santa Clara, CA 95054 Tel: 408 988-1700 Fax: 408 982-1700 | www.sanyodenki.com
501 West Main Street Radford, VA 24141 1-800-77-SERVO | www.kollmorgen.com
1879 Ohyasumi, Iida City, Nagano Prefecture, 395-8515, Japan Tel.265(21)1840 Fax.265(21)1865 | www.tamagawa-seiki.co.jp/english/index.html


Sanyo Denki Q Series Drive

.

Sanyo Denki Q Series Drive

For more information, please go to http://www.synqnet.org/drives.html.


Yaskawa DMD-4 Drive

.

Yaskawa DMD-4 Drive

SynqNet DMD Preliminary Data Sheet

For more information, please go to http://www.synqnet.org/drives.html.


Yaskawa SGDS Drive

.

Yaskawa SGDS Drive

SynqNet SGDS Preliminary Data Sheet

For more information, please go to http://www.synqnet.org/drives.html.


XMP-Analog Hardware

.

XMP Hardware Overview
XMP Hardware
Controller Configurations
Expansions and Add-ons
Host Controller Electrical Requirements
XMP Controller Installation

Specifications
XMP Bus Interface
 Introduction
PCI
CPCI-6U
CPCI-3U
PMC

XMP Analog I/O
 Introduction
Transceiver (XCVR) and User I/O Details
General XMP I/O Specifications

Pinouts
PCI Main (0-7)
PCI Expansion (8-15)
CPCI-6U Main (0-7) Front I/O
CPCI-6U Main (0-7) Rear I/O
CPCI-6U Expansion (8-15) Front I/O
CPCI-6U Expansion (8-15) Rear I/O
CPCI-3U

Analog-XMP Quick Start Guide

Installing an XMP-Analog Motion System
Introduction
Connect to Analog Servo Amplifiers
Drive Enable Wiring
Connect Digital Quadrature Encoders
Connect System I/O
Analog Inputs
Connect XMP Transceiver I/O as a Capture Input
Connect 2 XMP Boards (12-16 Axes)
Configuring Analog Connections


Analog Inputs

.

Analog Inputs

There are eight (8) analog inputs per XMP system.

Connect analog inputs.


XMP-CPCI-3U Bus

.

XMP-CPCI-3U Bus

The four-axis CPCI-3U is a smaller version of the -6U board. It connects to the backplane via two connectors: J1 and J2 (see figure above). Motion drive I/O is conveyed via J2. For more information, click here. Connector J1 is reserved as a computer bus, and is described in this section.

Backplane connector pins are referred to by numbered rows and lettered columns as shown below:

CPCI-3U Main Board, Rear Panel Connector J1: User I/O

NOTE: the CPCI XMP does not use the 64-bit extension.

CPCI backplane connector (main and expansion boards).
Pin | E | D | C | B | A
25 | 5V | 3.3V | ENUM# | REQ64# | 5V
24 | ACK64# | AD[00] | V(I/O) | 5V | AD[01]
23 | AD[02] | 5V | AD[03] | AD[04] | 3.3V
22 | AD[05] | AD[06] | 3.3V | GND | AD[07]
21 | C/BE[0]# | M66EN | AD[08] | AD[09] | 3.3V
20 | AD[10] | AD[11] | V(I/O) | GND | AD[12]
19 | AD[13] | GND | AD[14] | AD[15] | 3.3V
18 | C/BE[1]# | PAR | 3.3V | GND | SERR#
17 | PERR# | GND | SBO# | SDONE | 3.3V
16 | LOCK# | STOP# | V(I/O) | GND | DEVSEL#
15 | TRDY# | GND | IRDY# | FRAME# | 3.3V
12 - 14 | Key Area | Key Area | Key Area | Key Area | Key Area
11 | C/BE[2]# | GND | AD[16] | AD[17] | AD[18]
10 | AD[19] | AD[20] | 3.3V | GND | AD[21]
9 | AD[22] | GND | AD[23] | IDSEL | C/BE[3]#
8 | AD[24] | AD[25] | V(I/O) | GND | AD[26]
7 | AD[27] | GND | AD[28] | AD[29] | AD[30]
6 | AD[31] | CLK | 3.3V | GND | REQ#
5 | GNT# | GND | RST# | BRSVP1B5 | BRSVP1A5
4 | INTS | INTP | V(I/O) | GND | BRSVP1A4
3 | INTD# | 5V | INTC# | INTB# | INTA#
2 | TDI | TDO | TMS | 5V | TCK
1 | 5V | +12V | TRST# | -12V | 5V


XMP-CPCI-6U Bus

.

XMP-CPCI-6U Bus

Compact PCI (CPCI) utilizes a card-type computer chassis, having a multi-pin backplane. The main advantage is smaller sizing and simplified access to electronics. There are two sizes of CPCI: -6U and -3U. The CPCI-6U is the larger of the two form factors and connects to the backplane bus via jumper connector J1. The CPCI-6U is described in this section.

For bus information of the CPCI-3U, click here.

CPCI-6U Main Board, Rear Panel Connector J1

NOTE: the CPCI XMP does not use the 64-bit extension.

CPCI backplane connector (main and expansion boards).
Pin | E | D | C | B | A
25 | 5V | 3.3V | ENUM# | REQ64# | 5V
24 | ACK64# | AD[00] | V(I/O) | 5V | AD[01]
23 | AD[02] | 5V | AD[03] | AD[04] | 3.3V
22 | AD[05] | AD[06] | 3.3V | GND | AD[07]
21 | C/BE[0]# | M66EN | AD[08] | AD[09] | 3.3V
20 | AD[10] | AD[11] | V(I/O) | GND | AD[12]
19 | AD[13] | GND | AD[14] | AD[15] | 3.3V
18 | C/BE[1]# | PAR | 3.3V | GND | SERR#
17 | PERR# | GND | SBO# | SDONE | 3.3V
16 | LOCK# | STOP# | V(I/O) | GND | DEVSEL#
15 | TRDY# | GND | IRDY# | FRAME# | 3.3V
12 - 14 | Key Area | Key Area | Key Area | Key Area | Key Area
11 | C/BE[2]# | GND | AD[16] | AD[17] | AD[18]
10 | AD[19] | AD[20] | 3.3V | GND | AD[21]
9 | AD[22] | GND | AD[23] | IDSEL | C/BE[3]#
8 | AD[24] | AD[25] | V(I/O) | GND | AD[26]
7 | AD[27] | GND | AD[28] | AD[29] | AD[30]
6 | AD[31] | CLK | 3.3V | GND | REQ#
5 | GNT# | GND | RST# | BRSVP1B5 | BRSVP1A5
4 | INTS | INTP | V(I/O) | GND | BRSVP1A4
3 | INTD# | 5V | INTC# | INTB# | INTA#
2 | TDI | TDO | TMS | 5V | TCK
1 | 5V | +12V | TRST# | -12V | 5V

CPCI-6U Expansion Board

Special Note: On CPCI-6U motion control systems having an expansion board, all computer bus data is conveyed via the main board's J1 connector, then relayed via the ribbon cable connector. Expansion boards also utilize a J1 backplane connector; however, it provides only power and ground to the expansion board.


XMP-PCI Bus

.

XMP-PCI Bus

PCI buses are found in many common desktop and tower-type computer systems. The standard XMP-PCI controller features a 120-pin edge connector which plugs directly into standard 5VDC PCI bus receptacles. (Refer to figure above.) A "universal" PCI that supports 3.3V or 5V signalling is pending from MEI. Please contact MEI for availability. All motion control I/O for the XMP-PCI controller is performed via the VHDCI connectors on the rear panel of the controller. For more information on I/O, click here.

PCI Connector (Bus)

PCI bus connector (main & expansion boards).
5 V System |  |  |  | Universal System (5 or 3.3 V) |  |  |  |
Side B |  | Side A |  | Side B |  | Side A
Pin | Function | Pin | Function | Pin | Function | Pin | Function | Comments
01B | -12V | 01A | TRST# | 01B | -12V | 01A | TRST# | 32-bit Connector Start
02B | TCK | 02A | +12V | 02B | TCK | 02A | +12V |
03B | GND | 03A | TMS | 03B | GND | 03A | TMS |
04B | TDO | 04A | TDI | 04B | TDO | 04A | TDI |
05B | +5V | 05A | +5V | 05B | +5V | 05A | +5V |
06B | +5V | 06A | INTA# | 06B | +5V | 06A | INTA# |
07B | INTB# | 07A | INTC# | 07B | INTB# | 07A | INTC# |
08B | INTD# | 08A | +5V | 08B | INTD# | 08A | +5V |
09B | PRSNT1# | 09A | Reserved | 09B | PRSNT1# | 09A | Reserved |
10B | Reserved | 10A | +5V (I/O) | 10B | Reserved | 10A | +5V (I/O) |
11B | PRSNT2# | 11A | Reserved | 11B | PRSNT2# | 11A | Reserved |
12 B | Ground | 12A | Ground | 12B | KEY SLOT | 12A | KEY SLOT |
13B | Ground | 13A | Ground | 13B |  | 13A |  |
14B | Reserved | 14A | Reserved | 14B | Reserved | 14A | Reserved |
15B | Ground | 15A | RST# | 15B | Ground | 15A | RST# |
16B | CLK | 16A | +5V (I/O) | 16B | CLK | 16A | +5V (I/O) |
17B | Ground | 17A | GNT# | 17B | Ground | 17A | GNT# |
18B | REQ# | 18A | Ground | 18B | REQ# | 18A | Ground |
19B | +5V (I/O) | 19A | Reserved | 19B | +V (I/O) | 19A | Reserved |
20B | AD[31] | 20A | AD[30] | 20B | AD[31] | 20A | AD[30] |
21B | AD[29] | 21A | +3.3V | 21B | AD[29] | 21A | +3.3V |
22B | Ground | 22A | AD[28] | 22B | Ground | 22A | AD[28] |
23B | AD[27] | 23A | AD[26] | 23B | AD[27] | 23A | AD[26] |
24B | AD[25] | 24A | Ground | 24B | AD[25] | 24A | Ground |
25B | +3.3V | 25A | AD[24] | 25B | +3.3V | 25A | AD[24] |
26B | C/BE[3]# | 26A | IDSEL | 26B | C/BE[3]# | 26A | IDSEL |
27B | AD[23] | 27A | +3.3V | 27B | AD[23] | 27A | +3.3V |
28B | Ground | 28A | AD[22] | 28B | Ground | 28A | AD[22] |
29B | AD[21] | 29A | AD[20] | 29B | AD[21] | 29A | AD[20] |
30B | AD[19] | 30A | Ground | 30B | AD[19] | 30A | Ground |
31B | +3.3V | 31A | AD[18] | 31B | +3.3V | 31A | AD[18] |
32B | AD[17] | 32A | AD[16] | 32B | AD[17] | 32A | AD[16] |
33B | C/BE[2]# | 33A | +3.3V | 33B | C/BE[2]# | 33A | +3.3V |
34B | Ground | 34A | FRAME# | 34B | Ground | 34A | FRAME# |
35B | IRDY# | 35A | Ground | 35B | IRDY# | 35A | Ground |
36B | +3.3V | 36A | TRDY# | 36B | +3.3V | 36A | TRDY# |
37B | DEVSEL# | 37A | Ground | 37B | DEVSEL# | 37A | Ground |
38B | Ground | 38A | STOP# | 38B | Ground | 38A | STOP# |
39B | LOCK# | 39A | +3.3V | 39B | LOCK# | 39A | +3.3V |
40B | PERR# | 40A | SDONE | 40B | PERR# | 40A | SDONE |
41B | +3.3V | 41A | SBO# | 41B | +3.3V | 41A | SBO# |
42B | SERR# | 42A | Ground | 42B | SERR# | 42A | Ground |
43B | +3.3V | 43A | PAR | 43B | +3.3V | 43A | PAR |
44B | C/BE[1]# | 44A | AD[15] | 44B | C/BE[1]# | 44A | AD[15] |
45B | AD[14] | 45A | +3.3V | 45B | AD[14] | 45A | +3.3V |
46B | Ground | 46A | AD[13] | 46B | Ground | 46A | AD[13] |
47B | AD[12] | 47A | AD[11] | 47B | AD[12] | 47A | AD[11] |
48B | AD[10] | 48A | Ground | 48B | AD[10] | 48A | Ground |
49B | Ground | 49A | AD[09] | 49B | M66EN | 49A | AD[09] | 66 MHz / Gnd
50B | KEY SLOT | 50A | KEY SLOT | 50B | KEY SLOT | 50A | KEY SLOT | 5 Volt Key
51B |  | 51A |  | 51B |  | 51A |  | 5 Volt Key
52B | AD[08] | 52A | C/BE[0]# | 52B | AD[08] | 52A | C/BE[0]# |
53B | AD[07] | 53A | +3.3V | 53B | AD[07] | 53A | +3.3V |
54B | +3.3V | 54A | AD[06] | 54B | +3.3V | 54A | AD[06] |
55B | AD[05] | 55A | AD[04] | 55B | AD[05] | 55A | AD[04] |
56B | AD[03] | 56A | Ground | 56B | AD[03] | 56A | Ground |
57B | Ground | 57A | AD[02] | 57B | Ground | 57A | AD[02] |
58B | AD[01] | 58A | AD[00] | 58B | AD[01] | 58A | AD[00] |
59B | +5V (I/O) | 59A | +5V (I/O) | 59B | +V (I/O) | 59A | +5V (I/O) |
60B | ACK64# | 60A | REQ64# | 60B | ACK64# | 60A | REQ64# |
61B | +5V | 61A | +5V | 61B | +5V | 61A | +5V |
62B | +5V | 62A | +5V | 62B | +5V | 62A | +5V | 32-bit Connector End


XMP-PMC Bus

.

XMP-PMC Bus

PMC stands for PCI Mezzanine Card. On XMP controllers, PMC bussing is via a "mezzanine" connector, mounted at one corner of the card.

P12
Pin # | Signal Name | Signal Name | Pin #
2 | TRST# | +12V | 1
4 | TDO | TMS | 3
6 | Ground | TDI | 5
8 | PCI-RSVD* | Ground | 7
10 | PCI-RSVD* | PCI-RSVD* | 9
12 | +3.3V | BUSMODE2# | 11
14 | BUSMODE3# | RST# | 13
16 | BUSMODE4# | +3.3V | 15
18 | Ground | PCI-RSVD* | 17
20 | AD[29] | AD[30] | 19
22 | AD[26] | Ground | 21
24 | +3.3V | AD[24] | 23
26 | AD[23] | IDSEL | 25
28 | AD[20] | +3.3V | 27
30 | Ground | AD[18] | 29
32 | C/BE[2]# | AD[16] | 31
34 | PMC-RSVD | Ground | 33
36 | +3.3V | TRDY# | 35
38 | STOP# | Ground | 37
40 | Ground | PERR# | 39
42 | SERR# | +3.3V | 41
44 | Ground | C/BE[1]# | 43
46 | AD[13] | AD[14] | 45
48 | AD[10] | Ground | 47
50 | +3.3V | AD[08] | 49
52 | PMC-RSVD | AD[07] | 51
54 | PMC-RSVD | +3.3V | 53
56 | Ground | PMC-RSVD | 55
58 | PMC-RSVD | PMC-RSVD | 57
60 | PMC-RSVD | Ground | 59
62 | +3.3V | ACK64# | 61
64 | PMC-RSVD | Ground | 63

P11
Pin # | Signal Name | Signal Name | Pin #
2 | -12V | TCK | 1
4 | INTA# | Ground | 3
6 | INTC# | INTB# | 5
8 | +5V | BUSMODE1# | 7
10 | PCI-RSVD* | INTD# | 9
12 | PCI-RSVD# | Ground | 11
14 | Ground | CLK | 13
16 | GNT# | Ground | 15
18 | +5V | REQ# | 17
20 | AD[31] | V (I/O) | 19
22 | AD[27] | AD[28] | 21
24 | Ground | AD[25] | 23
26 | C/BE[3]# | Ground | 25
28 | AD[21] | AD[22] | 27
30 | +5V | AD[19] | 29
32 | AD[17] | V (I/O) | 31
34 | Ground | FRAME# | 33
36 | IRDY# | Ground | 35
38 | +5V | DEVSEL# | 37
40 | LOCK# | Ground | 39
42 | SBO# | SDONE# | 41
44 | Ground | PAR | 43
46 | AD[15] | V (I/O) | 45
48 | AD[11] | AD[12] | 47
50 | +5V | AD[09] | 49
52 | C/BE[0]# | Ground | 51
54 | AD[05] | AD[06] | 53
56 | Ground | AD[04] | 55
58 | AD[03] | V (I/O) | 57
60 | AD[01] | AD[02] | 59
62 | +5V | AD[00] | 61
64 | RE064# | Ground | 63


Configuring Analog Connections

.

Configuring Analog Connections

This section provides more general guidance for configuring analog controllers with various hardware (servo amps; encoders, etc.).

XMP-PCI, XMP-CPCI

Connections to Servo Motors

XMP-series controllers can control brush servo motors, brushless servo motors, or linear brush/brushless motors. Basic connections require an analog output signal (from the controller to the amplifier) and an encoder input (from the motor to the controller).

Most amplifiers support either Velocity mode (voltage control) Torque mode (current control) or both. The XMP controller can be used with either servo motor/amplifier package.

XMP-series controllers accept RS-422 compatible (0V to +5V, 40mA max) encoder input from either differential or single-ended encoders. Differential encoders are preferred due to their excellent noise immunity. The connections for a single-ended encoder are identical to a differential encoder except that references must be connected to channel A- and channel B-.

The controller reads the index pulse (either single-ended or differential ended). Typically, there is one index pulse per revolution of the encoder (rotary type), which can be used for homing. Encoder signals are read in quadrature. Every line on the encoder will produce a rising edge and a falling edge on channels A+ and B+ which is interpreted by the XMP controller as four encoder counts.

Brush Servo Motors

The minimum required connections to brush-type servo are: Analog signal ( ± 10V), +5V, Signal Ground, Encoder Channel A+, Encoder Channel B+. Typical connections for a brush servo motor with a differential encoder follow.

Typical brush servo motor connections.

Note

Any unused lines should be left unconnected.

Brushless Servo Motors

Typical connections for a brushless servo motor with a differential encoder are:

Typical brushless servo motor connections.

Typical brushless servo motor drives of this configuration are "intelligent." If single ended encoders are used, external references will need to be supplied.

Step-and-Direction Controlled Servo Motors

Some brushless servos are controlled by step-and-direction pulses. With this scheme, the position information is communicated by step pulses, and the PID loop is handled internally by the drive itself.

Connections to Step Motors

Open-loop Step Motors

XMP controllers can control step motors in open-loop (no feedback) configurations. The XMP can also be configured for STEP LOOPBACK. When this is enabled, the motor Position Error Limit and Axis Settling will depend on the output steps being read back into the actual position register. If STEP LOOPBACK is disabled, an external feedback device (e.g. encoder) will be needed for determining position error limits and axis settling. In either case, the output is generated regardless of actual position.

Typical open-loop step motor connections for step drives triggering on the rising edge.

For stepper drives that trigger on the falling edge, invert the step output transceiver. This can be done from Motion Console by enabling the XCVR A: Invert (or XCVR B: Invert, etc.) parameter in the Motor Summary / I/O page.

Note

To determine whether your drive triggers on the rising or falling step edge, consult the drive manufacturer's manual.

Connections for Dual-loop Control

XMP-series controllers can be configured for dual-loop control. In dual-loop control, the velocity information for the PID derivative term (Kd) is derived from a rotary encoder on the motor shaft, and the position information for the PID proportional and integral terms is derived from an encoder on the load itself.

The axis that will be used for the rotary encoder is configurable through software and can be any axis that is not controlling a motor. For example, if axis 0 is configured for velocity feedback and axis 1 is configured for positional feedback, your system would be connected as shown in the next figure.

Dual-loop encoder connections with differential encoders.

MPI Support for Steppers

Support for stepper motor control is included within the MPI (Motion Programming Interface).

Transceivers

All transceiver and user I/O are part of the "Motor" object. Each hardware axis has three (3) transceivers dedicated to it, labeled XCVRA, XCVRB, and XCVRC. The XCVRA, XCVRB, and XCVRC transceivers support:

All three transceivers support input/output, normal/inverted.
Transceiver | Input or Output? | Normal or Inverted?
XCVRA | Yes | Yes
XCVRB | Yes | Yes
XCVRC | Yes | Yes

A and B transceivers support more features.
Transceiver | Step or Dir? | CW or CCW? | Quad A or Quad B? | Normal or Inverted? | Compare?
XCVRA | Yes | Yes | Yes | Yes | No
XCVRB | Yes | Yes | Yes | Yes | No
XCVRC | No | No | No | Yes | Yes

Note that only sensible XCVRA/XCVRB configurations are permitted. For example, if XCVRA is configured for Step, then XCVRB should be configured for Dir. If XCVRA is configured for Dir, then XCVRB should be configured for Step. Refer to the next table.

Transceiver configurations that are supported.
XCVRA | XCVRB | XCVRC
Step | Dir |
Dir | Step |
CW | CCW |
CCW | CW |
QuadA | QuadB |
QuadB | QuadA |

Step/Dir & CW/CCW Specifications

Step/dir and CW/CCW specifications.
Pulse width range for Step, CW & CCW | 100 nsec to 25.5 microsec
Maximum duty cycle must be less than | 50% (or 25.5 microsec)
Minimum separation between Dir edge and rising Step edge (or between CW and CCW edges) | 125 nanosec
Maximum step output rate | 2.5 MHz

The maximum separation between the Dir edge and the rising Step edge depends upon the sample rate and the commanded motion. A rule of thumb is that the Dir edge occurs at the start of the DSP's trajectory calculator (when the command velocity is non-zero), and the first Step occurs when the command position increments the first whole count. The time separation can be estimated from the commanded acceleration (Accel):

For example, if acceleration is 100,000 cts/sec2, then the separation between the Dir edge and the first Step edge is

which computes to Time = 4.5 milliseconds

The minimum separation between the Dir edge and the first Step edge is 125 nanoseconds. Note that the XMP increments its counter on each rising edge of the Step or CW signal.

Step/dir (and CW/CCW) and motor motion.

Step/dir and velocity.

Stepper Loopback

When the Loopback feature is enabled, the Step/Dir (or CW/CCW) logic is routed back into the encoder inputs. Note that the DSP doesn't use the feedback for control. There are two to three samples of latency between when the DSP's command position is updated and when the actual position (loopback) is updated. Also, loopback is not affected by "inverted" configurations.

The position error limit is still valid for loopback operations. If Loopback is not enabled, you can connect the encoder inputs to actual encoders.

HELPFUL TIP: Stepper loopback is very useful for motor simulation. When real servo motors are not available, the controller's stepper motor and loopback configurations make it possible to develop software.

Closed Loop Steppers

Currently, there is no explicit support for closed loop stepper configurations. But, it is possible to correct the final position based on the actual position via application software, since the encoder inputs are valid with Step/Dir and CW/CCW configurations.

Stepper Configuration using Motion Console

To configure a Stepper using Motion Console, you must set the following parameters:

Parameters used to configure a stepper in Motion Console.
Object | Motion Console Parameter | Setting
Motor | Type | Stepper
 | Stepper pulse width | 2.55 (10-5)
 | Stepper loopback | Yes
 | Transceiver A config | Step or CW
 | Transceiver B config | Dir or CCW
Filter | Algorithm | None


Connect to Digital Quadrature Encoders

.

Connect to Digital Quadrature Encoders

Encoder Wiring

Note

The 100 ohm terminations to the receivers are software-selectable. If you use the Scale Interpolation Module (SIM), you must program the 100 ohm terminations off, i.e., remove them from the circuit. To learn more about encoder termination, please refer to Application Note 206.

Connect to Differential Encoders

Connect to differential encoders (digital).

Connect to Single-ended Encoders

Note

To connect the XMP's differential line receivers to single-ended encoders, you must add a pair of resistors (R1, R2) in the configuration shown, to bias the negative end to the middle of the encoder's output voltage range.

Connect to single-ended encoders (digital).

Broken Wire and Illegal State Detection
The encoder inputs (channel A+, A-, B+, B-) are monitored by the FPGA (an on-board logic component). The encoder inputs are sampled at 20mHz. By default, a digital filter is applied to each encoder input. This digital filter requires that an encoder input (channel A+, A-, B+, B-) be stable for 4 clock cycles (200 nanoseconds) before a transition is recognized, i.e., encoder input states lasting less than 4 clock cycles are filtered out.


Connect Two XMP Boards (12-16 Axes)

.

Connect Two XMP Boards (12-16 Axes)

To create systems with more than eight (8) axes, use two XMP boards, with one board configured as the main, and the other board configured as the expansion.

Typical Connections

Main/Expansion Axis Assignments: CPCI.

Main/expansion axis assignments: PCI.


Connect to Analog Servo Amplifiers

.

Connect to Analog Servo Amplifiers

Opto-Isolation of Outputs

A number of controller outputs are optically isolated to protect both the controller and the drive amplifier, such as HOME LIMIT and AMP FAULT. The XMP's internal logic only controls current to the opto-transistor, thus presenting a "conducting" state between the collector and emitter (of the opto-transistor). Your external wiring determines whether an active low or an active high is presented at the input to your drive.

Note

To maintain electrical isolation between the XMP and external I/O, the power and ground connections should be from an external power source, and should not be tied to the XMP's power or ground connections.

Command Outputs (DAC) Wiring

Connections for command outputs.


Connect System I/O

.

Connect System I/O

Connect System I/O includes:

Dedicated inputs per axis:

  • Positive and Negative Limit inputs
  • Home input

Global system inputs (one per XMP system):

  • System E-Stop input
  • System Reset input

User I/O (opto-isolated)

  • Individually configurable as input or output
  • There are four user I/Os per 4-axis Motion Block, (or eight user I/Os per board). Each user I/O is individually configurable as input or output.

Limit and Home Sensors

Common Ground Logic

Connect home and limit sensors (common ground logic).

Common Vcc Logic

Connect home and limit sensors (common Vcc logic).

System E-Stop Input

To Pull-up Logic

Connect E-stop input to pull-up logic.

To Pull-down Logic

Connect E-stop input to pull-down logic.

System Reset Input

To Pull-up Logic

Connect system reset input to pull-up logic.

To Pull-down Logic

Connect system reset input to pull-down logic.

Opto-isolated User I/O

There are four (4) user I/Os per 4-axis motion block, and each user I/O is individually configurable as input or output.

Connect user I/O input to pull-up logic.

Connect user I/O input to pull-down logic.

As User I/O Outputs

Connect user I/O as outputs to pull-up logic.

Connect user I/O as outputs to pull-down logic.


Connecting XMP Transceiver I/O as a Capture Input

.

Connecting XMP Transceiver I/O as a Capture Input

There are twelve (12) I/Os for each 4-axis motion block.

Connect Transceiver as Differential Capture Input

Connect transceiver as differential input.

Connect Transceiver as Single-ended Capture Input

Connect transceiver as single-ended input.

Transceiver as a Compare Output

Connect Transceiver as Differential Compare Output

Connect transceiver as differential compare output.


XMP-CPCI-3U

.

XMP-CPCI-3U

VHDCI (front) | Backplane (rear)

The XMP-CPCI-3U boards have two hardware stuff options for bringing out Motor I/O: VHDCI connectors on the front panel or Backplane connectors on the rear panel. The I/O for these connectors is decribed below.

XMP-CPCI-3U, VHDCI Connectors, Front Panel J0-3: Axes 0-3

Axis 0-1, VHDCI Connector (CPCI)

Connector for axes 0 and 1.
Pin | Signal | Signal | Pin
1 | No Connect | No Connect | 35
2 | No Connect | No Connect | 36
3 | Gnd | Gnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | No Connect | Gnd | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | No Connect | Gnd | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

Axis 2-3, VHDCI Connector (CPCI)

Connector for axes 2 and 3.
Pin | Signal | Signal | Pin
1 | EncA_A+ | EncA_A- | 35
2 | EncA_B+ | EncA_B- | 36
3 | EncA_I+ | EncA_I- | 37
4 | Enc2_A+ | Enc2_A- | 38
5 | Enc2_B+ | Enc2_B- | 39
6 | Enc2_I+ | Enc2_I- | 40
7 | Home2_IN | 5V_OUT | 41
8 | Pos_Lim2_IN | Gnd | 42
9 | Neg_Lim2_IN | HomeLim2_Rtn | 43
10 | Cmd_Dac_OUT_2+ | Cmd_Dac_OUT_2- | 44
11 | No Connect | Gnd | 45
12 | Amp_Flt2_IN | Amp_Flt2_Rtn | 46
13 | Amp_En2_Collector | Amp_En2_Emitter | 47
14 | UserIO_A3 | UserIO_A3_Rtn | 48
15 | Xcvr2A+ | Xcvr2A- | 49
16 | Xcvr2B+ | Xcvr2B- | 50
17 | Xcvr2C+ | Xcvr2C- | 51
18 | Enc3_A+ | Enc3_A- | 52
19 | Enc3_B+ | Enc3_B- | 53
20 | Enc3_I+ | Enc3_I- | 54
21 | Home3_IN | 5V_OUT | 55
22 | Pos_Lim3_IN | Gnd | 56
23 | Neg_Lim3_IN | HomeLim3_Rtn | 57
24 | Cmd_Dac_OUT_3+ | Cmd_Dac_OUT_3- | 58
25 | No Connect | Gnd | 59
26 | Amp_Flt3_IN | Amp_Flt3_Rtn | 60
27 | Amp_En3_Collector | Amp_En3_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr3A+ | Xcvr3A- | 63
30 | Xcvr3B+ | Xcvr3B- | 64
31 | Xcvr3C+ | Xcvr3C- | 65
32 | Gnd | Gnd | 66
33 | No Connect | No Connect | 67
34 | No Connect | No Connect | 68

XMP-CPCI-3U, Backplane Connectors, Rear Panel J2: Motor I/O

On CPCI-3U controllers using backplane I/O, Motor I/O is controlled through connector J2. Connector J1 is reserved for computer data bussing. For more information about computer data bussing, click here.

CPCI-3U boards do not use expansion boards.

Backplane connector pins are referred to by numbered rows and lettered columns as shown below.

Axis 0-1, Backplane Connector (CPCI)

NOTE: the CPCI XMP does not use the 64 bit extension.

CPCI backplane connector.
Pin | F | E | D | C | B | A
22 | GND | Reserved | Reserved | Reserved | Reserved | Reserved
21 | GND | DAC_3+ | DAC_2+ | XCVR0A+ | DAC_1+ | DAC_0+
20 | GND | DAC_3_RTN | DAC_2_RTN | XCVR0A- | DAC_1_RTN | DAC_0_RTN
19 | GND | ENC2_A- | ENC2_A+ | XCVR0B+ | ENC0_A- | ENC0_A+
18 | GND | ENC2_B- | ENC2_B+ | XCVR0B- | ENC0_B- | ENC0_B+
17 | GND | ENC2_I- | ENC2_I+ | XCVR1A+ | ENC0_I- | ENC0_I+
16 | GND | ENC3_A- | ENC3_A+ | XCVR1A- | ENC1_A- | ENC1_A+
15 | GND | ENC3_B- | ENC3_B+ | XCVR1B+ | ENC1_B- | ENC1_B+
14 | GND | ENC3_I- | ENC3_I+ | XCVR1B- | ENC1_I- | ENC1_I+
13 | GND | P2_E13 | P2_D13 | XCVR2A+ | P2_B13 | P2_A13
12 | GND | P2_E12 | P2_D12 | XCVR2A- | P2_B12 | P2_A12
11 | GND | P2_E11 | P2_D11 | XCVR2B+ | P2_B11 | P2_A11
10 | GND | DIR3- | DIR3+ | XCVR2B- | P2_B10 | P2_A10
9 | GND | HOMELIM_2_RTN | HOME_2_IN | XCVR3A+ | HOMELIM_0_RTN | HOME_0_IN
8 | GND | HOMELIM_3_RTN | HOME_3_IN | XCVR3A- | HOMELIM_1_RTN | HOME_1_IN
7 | GND | AMP_FLT_2_RTN | AMP_FLT_2_IN | XCVR3B+ | AMP_FLT_0_RTN | AMP_FLT_0_IN
6 | GND | P2_E6 | P2_D6 | XCVR3B- | P2_B6 | P2_A6
5 | GND | USERIO_A2_RTN | USERIO_A2 | XCVR0C+ | USERIO_A0_RTN | USERIO_A0
4 | GND | USERIO_A3_RTN | USERIO_A3 | XCVR0C- | USERIO_A1_RTN | USERIO_A1
3 | GND | AMP_EN_2_EMIT | AMP_EN_2_COLL | P2_C3 | AMP_EN_0_EMIT | AMP_EN_0_COLL
2 | GND | P2_E2 | P2_D2 | P2_C2 | P2_B2 | P2_A2
1 | GND | Reserved | Reserved | Reserved | Reserved | Reserved


XMP-CPCI-6U Expansion Board, Front I/O

.

XMP-CPCI-6U Expansion Board, Front I/O

VHDCI Connectors

CPCI-6U Expansion Board
Location | Axes | Pinouts
J8-9 | 8-9 | pinouts
J10-11 | 10-11 | pinouts
J12-13 | 12-13 | pinouts
J14-15 | 14-15 | pinouts

Many XMP-CPCI-6U boards (main and expansion) feature VHDCI connectors on their front panels. I/O for these connectors is identical to those for XMP-PCI controllers.

NOTE: The pinouts for the CPCI-6U are the same as the pinouts for the PCI.

XMP-CPCI-6U, VHDCI Connectors, Expansion Board

Axes 8-9, (J8-9) VHDCI Connector (CPCI-6U)

Connector for Axes 8 and 9 (CPCI-6U expansion board).
Pin | Signal | Signal | Pin
1 | Not Connected | Not Connected | 35
2 | Not Connected | Not Connected | 36
3 | Gnd | AGnd | 37
4 | Enc8_A+ | Enc8_A- | 38
5 | Enc8_B+ | Enc8_B- | 39
6 | Enc8_I+ | Enc8_I- | 40
7 | Home8_IN | 5V_OUT | 41
8 | Pos_Lim8_IN | Gnd | 42
9 | Neg_Lim8_IN | HomeLim8_Rtn | 43
10 | Cmd_Dac_OUT_8+ | Cmd_Dac_OUT_8- | 44
11 | Aux_Dac_OUT_8+ | Aux_Dac_OUT_8- | 45
12 | Amp_Flt8_IN | Amp_Flt8_Rtn | 46
13 | Amp_En8_Collector | Amp_En8_Emitter | 47
14 | UserIO_C0 | UserIO_C0_Rtn | 48
15 | Xcvr8A+ | Xcvr8A- | 49
16 | Xcvr8B+ | Xcvr8B- | 50
17 | Xcvr8C+ | Xcvr8C- | 51
18 | Enc9_A+ | Enc9_A- | 52
19 | Enc9_B+ | Enc9_B- | 53
20 | Enc9_I+ | Enc9_I- | 54
21 | Home9_IN | 5V_OUT | 55
22 | Pos_Lim9_IN | Gnd | 56
23 | Neg_Lim9_IN | HomeLim9_Rtn | 57
24 | Cmd_Dac_OUT_9+ | Cmd_Dac_OUT_9- | 58
25 | Aux_Dac_OUT_9+ | Aux_Dac_OUT_9- | 59
26 | Amp_Flt9_IN | Amp_Flt9_Rtn | 60
27 | Amp_En9_Collector | Amp_En9_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr9A+ | Xcvr9A- | 63
30 | Xcvr9B+ | Xcvr9B- | 64
31 | Xcvr9C+ | Xcvr9C- | 65
32 | UserIO_C1 | UserIO_C1_Rtn | 66
33 | Not Connected | UserIO_C2 | 67
34 | Not Connected | UserIO_C2_Rtn | 68

Axes 10-11, (J10-11) VHDCI Connector (CPCI-6U)

Connector for Axes 10 and 11 (CPCI-6U expansion board).
Pin | Signal | Signal | Pin
1 | EncC_A+ | EncC_A- | 35
2 | EncC_B+ | EncC_B- | 36
3 | EncC_I+ | EncC_I- | 37
4 | Enc10_A+ | Enc10_A- | 38
5 | Enc10_B+ | Enc10_B- | 39
6 | Enc10_I+ | Enc10_I- | 40
7 | Home10_IN | 5V_OUT | 41
8 | Pos_Lim10_IN | Gnd | 42
9 | Neg_Lim10_IN | HomeLim10_Rtn | 43
10 | Cmd_Dac_OUT_10+ | Cmd_Dac_OUT_10- | 44
11 | Aux_Dac_OUT_10+ | Aux_Dac_OUT_10- | 45
12 | Amp_Flt10_IN | Amp_Flt10_Rtn | 46
13 | Amp_En10_Collector | Amp_En10_Emitter | 47
14 | UserIO_C3 | UserIO_C3_Rtn | 48
15 | Xcvr10A+ | Xcvr10A- | 49
16 | Xcvr10B+ | Xcvr10B- | 50
17 | Xcvr10C+ | Xcvr10C- | 51
18 | Enc11_A+ | Enc11_A- | 52
19 | Enc11_B+ | Enc11_B- | 53
20 | Enc11_I+ | Enc11_I- | 54
21 | Home11_IN | 5V_OUT | 55
22 | Pos_Lim11_IN | Gnd | 56
23 | Neg_Lim11_IN | HomeLim11_Rtn | 57
24 | Cmd_Dac_OUT_11+ | Cmd_Dac_OUT_11- | 58
25 | Aux_Dac_OUT_11+ | Aux_Dac_OUT_11- | 59
26 | Amp_Flt11_IN | Amp_Flt11_Rtn | 60
27 | Amp_En11_Collector | Amp_En11_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr11A+ | Xcvr11A- | 63
30 | Xcvr11B+ | Xcvr11B- | 64
31 | Xcvr11C+ | Xcvr11C- | 65
32 | Gnd | AGnd | 66
33 | Not Connected | Not Connected | 67
34 | Not Connected | Not Connected | 68

Axes 12-13, (J12-13) VHDCI Connector (CPCI-6U)

Connector for Axes 12 and 13 (CPCI-6U expansion board).
Pin | Signal | Signal | Pin
1 | UserIO_D0 | UserIO_D0_Rtn | 35
2 | UserIO_D1 | UserIO_D1_Rtn | 36
3 | Gnd | Gnd | 37
4 | Enc12_A+ | Enc12_A- | 38
5 | Enc12_B+ | Enc12_B- | 39
6 | Enc12_I+ | Enc12_I- | 40
7 | Home12_IN | 5V_OUT | 41
8 | Pos_Lim12_IN | Gnd | 42
9 | Neg_Lim12_IN | HomeLim12_Rtn | 43
10 | Cmd_Dac_OUT_12+ | Cmd_Dac_OUT_12- | 44
11 | Aux_Dac_OUT_12+ | Aux_Dac_OUT_12- | 45
12 | Amp_Flt12_IN | Amp_Flt12_Rtn | 46
13 | Amp_En12_Collector | Amp_En12_Emitter | 47
14 | UserIO_D2 | UserIO_D2_Rtn | 48
15 | Xcvr12A+ | Xcvr12A- | 49
16 | Xcvr12B+ | Xcvr12B- | 50
17 | Xcvr12C+ | Xcvr12C- | 51
18 | Enc13_A+ | Enc13_A- | 52
19 | Enc13_B+ | Enc13_B- | 53
20 | Enc13_I+ | Enc13_I- | 54
21 | Home13_IN | 5V_OUT | 55
22 | Pos_Lim13_IN | Gnd | 56
23 | Neg_Lim13_IN | HomeLim13_Rtn | 57
24 | Cmd_Dac_OUT_13+ | Cmd_Dac_OUT_13- | 58
25 | Aux_Dac_OUT_13+ | Aux_Dac_OUT_13- | 59
26 | Amp_Flt13_IN | Amp_Flt13_Rtn | 60
27 | Amp_En13_Collector | Amp_En13_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr13A+ | Xcvr13A- | 63
30 | Xcvr13B+ | Xcvr13B- | 64
31 | Xcvr13C+ | Xcvr13C- | 65
32 | Gnd | AGnd | 66
33 | Not Connected | Not Connected | 67
34 | Not Connected | Not Connected | 68

Axes 14-15, (J14-15) VHDCI Connector (CPCI-6U)

Connector for Axes 14 and 15 (CPCI-6U expansion board).
Pin | Signal | Signal | Pin
1 | Not Connected | Not Connected | 35
2 | Not Connected | Not Connected | 36
3 | Gnd | AGnd | 37
4 | Enc14_A+ | Enc14_A- | 38
5 | Enc14_B+ | Enc14_B- | 39
6 | Enc14_I+ | Enc14_I- | 40
7 | Home6_IN | 5V_OUT | 41
8 | Pos_Lim14_IN | Gnd | 42
9 | Neg_Lim14_IN | HomeLim14_Rtn | 43
10 | Cmd_Dac_OUT_14+ | Cmd_Dac_OUT_14- | 44
11 | Aux_Dac_OUT_14+ | Aux_Dac_OUT_14- | 45
12 | Amp_Flt14_IN | Amp_Flt14_Rtn | 46
13 | Amp_En14_Collector | Amp_En14_Emitter | 47
14 | UserIO_D3 | UserIO_D3_Rtn | 48
15 | Xcvr14A+ | Xcvr14A- | 49
16 | Xcvr14B+ | Xcvr14B- | 50
17 | Xcvr14C+ | Xcvr14C- | 51
18 | Enc15_A+ | Enc15_A- | 52
19 | Enc15_B+ | Enc15_B- | 53
20 | Enc15_I+ | Enc15_I- | 54
21 | Home15_IN | 5V_OUT | 55
22 | Pos_Lim15_IN | Gnd | 56
23 | Neg_Lim15_IN | HomeLim15_Rtn | 57
24 | Cmd_Dac_OUT_15+ | Cmd_Dac_OUT_15- | 58
25 | Aux_Dac_OUT_15+ | Aux_Dac_OUT_15- | 59
26 | Amp_Flt15_IN | Amp_Flt15_Rtn | 60
27 | Amp_En15_Collector | Amp_En15_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr15A+ | Xcvr15A- | 63
30 | Xcvr15B+ | Xcvr15B- | 64
31 | Xcvr15C+ | Xcvr15C- | 65
32 | EncD_A+ | EncD_A- | 66
33 | EncD_B+ | EncD_B- | 67
34 | EncD_I+ | EncD_I- | 68


XMP-CPCI-6U Expansion Board, Rear I/O

.

XMP-CPCI-6U Expansion Board, Rear I/O

Backplane Connectors

CPCI-6U Expansion Board
Location | Function | Pinouts
J5 | Axes 8-11 | pinouts
J4 | Axes 12-15 | pinouts
J3 | User I/O | pinouts
J1 | Bus | pinouts

On CPCI-6U controllers using backplane I/O, drive signals are conveyed through connectors J3, J4 and J5.

For main boards, axes 0-3 are controlled through connector J5. Axes 4-7 are controlled through connector J4. User I/O is provided through connector J3.

On expansion boards, axes 8-11 are controlled through connector J5. Axes 12-15 are controlled through connector J4. User I/O is provided through connector J3.

On both main and expansion boards, connector J1 is reserved for computer data bussing. For more information on the CPCI-6U data bussing, click here.

CPCI-6U Expansion Board, CPCI Backplane Connector J5: Axes 8 - 11

J5 backplane connector for Axes 8-11 (CPCI expansion board).
Pin | F | E | D | C | B | A
22 | Gnd | Enc10_A- | Enc10_A+ | 5V_OUT | Xcvr9C- | Xcvr9C+
21 | Gnd | Enc10_B- | Enc10_B+ | Gnd | Xcvr9B- | Xcvr9B+
20 | Gnd | Enc10_I- | Xcvr9A+ | Home10_IN | Xcvr9A- | Enc10_I+
19 | Gnd | Aux_Dac_OUT_10- | Amp_En9_Collector | Pos_Lim10_IN | Amp_En9_Emitter | Aux_Dac_OUT_10+
18 | Gnd | Cmd_Dac_OUT_10- | Amp_Flt9_IN | Neg_Lim10_IN | Amp_Flt9_Rtn | Cmd_Dac_OUT_10+
17 | Gnd | Amp_Flt10_Rtn | Aux_Dac_OUT_9+ | HomeLim10_Rtn | Aux_Dac_OUT_9- | Amp_Flt10_IN
16 | Gnd | Amp_En10_Emitter | Amp_En10_Collector | HomeLim9_Rtn | Cmd_Dac_OUT_9- | Cmd_Dac_OUT_9+
15 | Gnd | Xcvr10A- | Xcvr10A+ | Neg_Lim9_IN | Enc9_I- | Enc9_I+
14 | Gnd | Xcvr10B- | Xcvr10B+ | Pos_Lim9_IN | Enc9_B- | Enc9_B+
13 | Gnd | Xcvr10C- | Xcvr10C+ | Home9_IN | Enc9_A- | Enc9_A+
12 | Gnd | Enc11_A- | Enc11_A+ | 5V_OUT | Xcvr8C- | Xcvr8C+
11 | Gnd | Enc11_B- | Enc11_B+ | Not Connected | Xcvr8B- | Xcvr8B+
10 | Gnd | Enc11_I- | Enc11_I+ | Home11_IN | Xcvr8A- | Xcvr8A+
9 | Gnd | Aux_Dac_OUT_11- | Aux_Dac_OUT_11+ | Pos_Lim11_IN | Amp_En8_Emitter | Amp_En8_Collector
8 | Gnd | Cmd_Dac_OUT_11- | Cmd_Dac_OUT_11+ | Neg_Lim11_IN | Amp_Flt8_Rtn | Amp_Flt8_IN
7 | Gnd | Amp_Flt11_Rtn | Amp_Flt11_IN | HomeLim11_Rtn | Aux_Dac_OUT_8- | Aux_Dac_OUT_8+
6 | Gnd | Amp_En11_Emitter | Amp_En11_Collector | HomeLim8_Rtn | Cmd_Dac_OUT_8- | Cmd_Dac_OUT_8+
5 | Gnd | Xcvr11A- | Xcvr11A+ | Neg_Lim8_IN | Enc8_I- | Enc8_I+
4 | Gnd | Xcvr11B- | Xcvr11B+ | Pos_Lim8_IN | Enc8_B- | Enc8_B+
3 | Gnd | Xcvr11C- | Xcvr11C+ | Home8_IN | Enc8_A- | Enc8_A+
2 | Gnd |  |  | Gnd |  |
1 | Gnd |  |  | AGnd |  |
Pin | F | E | D | C | B | A

CPCI-6U Expansion Board, Rear Panel Connector J4: Axes 12 - 15

J4 backplane connector for Axes 12-15 (CPCI expansion board).
Pin | F | E | D | C | B | A
25 | Gnd |  |  | AGnd |  |
24 | Gnd |  |  | Gnd |  |
23 | Gnd | Enc14_A- | Enc14_A+ | Home14_IN | Xcvr13C- | Xcvr13C+
22 | Gnd | Enc14_B- | Enc14_B+ | Pos_Lim14_IN | Xcvr13B- | Xcvr13B+
21 | Gnd | Enc14_I- | Enc14_I+ | Neg_Lim14_IN | Xcvr13A | Xcvr13A+
20 | Gnd | Cmd_Dac_OUT_14- | Cmd_Dac_OUT_14+ | HomeLim14_Rtn | Amp_En13_Emitter | Amp_En13_Collector
19 | Gnd | Aux_Dac_OUT_14- | Aux_Dac_OUT_14+ | HomeLim13_Rtn | Amp_Flt13_Rtn | Amp_Flt13_IN
18 | Gnd | Amp_Flt14_Rtn | Amp_Flt14_IN | Neg_Lim13_IN | Aux_Dac_OUT_5- | Aux_Dac_OUT_13+
17 | Gnd | Amp_En14_Emitter | Amp_En14_Collector | Pos_Lim13_IN | Cmd_Dac_OUT_5- | Cmd_Dac_OUT_13+
16 | Gnd | Xcvr14A- | Xcvr14A+ | Home13_IN | Enc13_I- | Enc13_I+
15 | Gnd | Xcvr14B- | Xcvr14B+ | Not Connected | Enc13_B- | Enc13_B+
14 | Gnd | Not Connected | Not Connected |  | Not Connected | Not Connected
13 | Gnd
12 | Gnd
11 | Gnd | Xcvr14C- | Xcvr14C+ | 5V_OUT | Enc13_A- | Enc13_A+
10 | Gnd | Enc15_A- | Enc15_A+ | Home15_IN | Xcvr12C- | Xcvr12C+
9 | Gnd | Enc15_B- | Enc15_B+ | Pos_Lim15_IN | Xcvr12B- | Xcvr12B+
8 | Gnd | Enc15_I- | Enc15_I+ | Neg_Lim15_IN | Xcvr12A- | Xcvr12A+
7 | Gnd | Cmd_Dac_OUT_15- | Cmd_Dac_OUT_15+ | HomeLim15_Rtn | Amp_En12_Emitter | Amp_En12_Collector
6 | Gnd | Aux_Dac_OUT_15- | Aux_Dac_OUT_15+ | HomeLim12_Rtn | Amp_Flt12_Rtn | Amp_Flt12_IN
5 | Gnd | Amp_Flt15_Rtn | Amp_Flt15_IN | Neg_Lim12_IN | Aux_Dac_OUT_12- | Aux_Dac_OUT_12+
4 | Gnd | Amp_En15_Emitter | Amp_En15_Collector | Pos_Lim12_IN | Cmd_Dac_OUT_12- | Cmd_Dac_OUT_12+
3 | Gnd | Xcvr15A- | Xcvr15A+ | Home12_IN | Enc12_I- | Enc12_I+
2 | Gnd | Xcvr15B- | Xcvr15B+ | Gnd | Enc12_B- | Enc12_B+
1 | Gnd | Xcvr15C- | Xcvr15C+ | 5V_OUT | Enc12_A- | Enc12_A+
Pin | F | E | D | C | B | A

CPCI-6U Expansion Board, Rear Panel Connector J3: User I/O

J3 backplane connector for User I/O (CPCI expansion board).
Pin | F | E | D | C | B | A
19 | Gnd | EncD_A- | EncD_A+ | Gnd | EncC_A- | EncC_A+
18 | Gnd | EncD_B- | EncD_B+ | Gnd | EncC_B- | EncC_B+
17 | Gnd | EncD_I- | EncD_I+ | Gnd | EncC_I- | EncC_I+
16 | Gnd | UserIO_D3_Rtn | UserIO_D3 | Gnd | UserIO_A0_Rtn | UserIO_C0
15 | Gnd | UserIO_D4_Rtn | UserIO_D4 | Gnd | UserIO_C3_Rtn | UserIO_C3
14 | Gnd | UserIO_D2_Rtn | UserIO_D2 | Gnd | Not Used | Not Used
13 | Gnd | UserIO_C2 | UserIO_C2_Rtn | Gnd | UserIO_C1_Rtn | UserIO_C1
12 | Gnd | Not Connected | Not Connected | UserIO_D1_Rtn | Not Connected | Not Connected
11 | Gnd |  |  | UserIO_D14
10 | Gnd |  |  | Not Connected
9 | Gnd
8 | Gnd
7 | Gnd
6 | Gnd
5 | Gnd |  |  | Gnd
4 | Gnd |  |  | Not Connected
3 | Gnd |  |  | Gnd
2 | Gnd |  |  | Not Connected
1 | Gnd |  |  | Gnd
Pin | F | E | D | C | B | A


XMP-CPCI-6U Main Board, Front I/O

.

XMP-CPCI-6U Main Board, Front I/O

VHDCI Connectors

CPCI-6U Main Board
Location | Axes | Pinouts
J0-1 | 0-1 | pinouts
J2-3 | 2-3 | pinouts
J4-5 | 4-5 | pinouts
J6-7 | 6-7 | pinouts

Many XMP-CPCI-6U boards (main and expansion) feature VHDCI connectors on their front panels. I/O for these connectors is identical to those for XMP-PCI controllers.

NOTE: The pinouts for the CPCI-6U are the same as the pinouts for the PCI.

XMP-CPCI, VHDCI Connectors, Main Board

Axes 0-1, (J0-1) VHDCI Connector (XMP-CPCI-6U)

Connector for Axes 0 and 1 (PCI main board).
Pin | Signal | Signal | Pin
1 | Analog_IN_0+ | Analog_IN_0- | 35
2 | Analog_IN_1+ | Analog_IN_1- | 36
3 | Gnd | AGnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

Axes 2-3, (J2-3) VHDCI Connector (XMP-CPCI-6U))

Connector for Axes 2 and 3 (PCI main board).
Pin | Signal | Signal | Pin
1 | EncA_A+ | EncA_A- | 35
2 | EncA_B+ | EncA_B- | 36
3 | EncA_I+ | EncA_I- | 37
4 | Enc2_A+ | Enc2_A- | 38
5 | Enc2_B+ | Enc2_B- | 39
6 | Enc2_I+ | Enc2_I- | 40
7 | Home2_IN | 5V_OUT | 41
8 | Pos_Lim2_IN | Gnd | 42
9 | Neg_Lim2_IN | HomeLim2_Rtn | 43
10 | Cmd_Dac_OUT_2+ | Cmd_Dac_OUT_2- | 44
11 | Aux_Dac_OUT_2+ | Aux_Dac_OUT_2- | 45
12 | Amp_Flt2_IN | Amp_Flt2_Rtn | 46
13 | Amp_En2_Collector | Amp_En2_Emitter | 47
14 | UserIO_A3 | UserIO_A3_Rtn | 48
15 | Xcvr2A+ | Xcvr2A- | 49
16 | Xcvr2B+ | Xcvr2B- | 50
17 | Xcvr2C+ | Xcvr2C- | 51
18 | Enc3_A+ | Enc3_A- | 52
19 | Enc3_B+ | Enc3_B- | 53
20 | Enc3_I+ | Enc3_I- | 54
21 | Home3_IN | 5V_OUT | 55
22 | Pos_Lim3_IN | Gnd | 56
23 | Neg_Lim3_IN | HomeLim3_Rtn | 57
24 | Cmd_Dac_OUT_3+ | Cmd_Dac_OUT_3- | 58
25 | Aux_Dac_OUT_3+ | Aux_Dac_OUT_3- | 59
26 | Amp_Flt3_IN | Amp_Flt3_Rtn | 60
27 | Amp_En3_Collector | Amp_En3_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr3A+ | Xcvr3A- | 63
30 | Xcvr3B+ | Xcvr3B- | 64
31 | Xcvr3C+ | Xcvr3C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_2+ | Analog_IN_2- | 67
34 | Analog_IN_3+ | Analog_IN_3- | 68

Axes 4-5, (J4-5) VHDCI Connector (XMP-CPCI-6U))

Connector for Axes 4 and 5 (PCI main board).
Pin | Signal | Signal | Pin
1 | UserIO_B0 | UserIO_B0_Rtn | 35
2 | UserIO_B1 | UserIO_B1_Rtn | 36
3 | Gnd | Gnd | 37
4 | Enc4_A+ | Enc4_A- | 38
5 | Enc4_B+ | Enc4_B- | 39
6 | Enc4_I+ | Enc4_I- | 40
7 | Home4_IN | 5V_OUT | 41
8 | Pos_Lim4_IN | Gnd | 42
9 | Neg_Lim4_IN | HomeLim4_Rtn | 43
10 | Cmd_Dac_OUT_4+ | Cmd_Dac_OUT_4- | 44
11 | Aux_Dac_OUT_4+ | Aux_Dac_OUT_4- | 45
12 | Amp_Flt4_IN | Amp_Flt4_Rtn | 46
13 | Amp_En4_Collector | Amp_En4_Emitter | 47
14 | UserIO_B2 | UserIO_B2_Rtn | 48
15 | Xcvr4A+ | Xcvr4A- | 49
16 | Xcvr4B+ | Xcvr4B- | 50
17 | Xcvr4C+ | Xcvr4C- | 51
18 | Enc5_A+ | Enc5_A- | 52
19 | Enc5_B+ | Enc5_B- | 53
20 | Enc5_I+ | Enc5_I- | 54
21 | Home5_IN | 5V_OUT | 55
22 | Pos_Lim5_IN | Gnd | 56
23 | Neg_Lim5_IN | HomeLim5_Rtn | 57
24 | Cmd_Dac_OUT_5+ | Cmd_Dac_OUT_5- | 58
25 | Aux_Dac_OUT_5+ | Aux_Dac_OUT_5- | 59
26 | Amp_Flt5_IN | Amp_Flt5_Rtn | 60
27 | Amp_En5_Collector | Amp_En5_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr5A+ | Xcvr5A- | 63
30 | Xcvr5B+ | Xcvr5B- | 64
31 | Xcvr5C+ | Xcvr5C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_4+ | Analog_IN_4- | 67
34 | Analog_IN_5+ | Analog_IN_5- | 68

Axes 6-7, (J6-7) VHDCI Connector (XMP-CPCI-6U))

Connector for Axes 6 and 7 (PCI main board).
Pin | Signal | Signal | Pin
1 | Analog_IN_6+ | Analog_IN_6- | 35
2 | Analog_IN_7+ | Analog_IN_7- | 36
3 | Gnd | AGnd | 37
4 | Enc6_A+ | Enc6_A- | 38
5 | Enc6_B+ | Enc6_B- | 39
6 | Enc6_I+ | Enc6_I- | 40
7 | Home6_IN | 5V_OUT | 41
8 | Pos_Lim6_IN | Gnd | 42
9 | Neg_Lim6_IN | HomeLim6_Rtn | 43
10 | Cmd_Dac_OUT_6+ | Cmd_Dac_OUT_6- | 44
11 | Aux_Dac_OUT_6+ | Aux_Dac_OUT_6- | 45
12 | Amp_Flt6_IN | Amp_Flt6_Rtn | 46
13 | Amp_En6_Collector | Amp_En6_Emitter | 47
14 | UserIO_B3 | UserIO_B3_Rtn | 48
15 | Xcvr6A+ | Xcvr6A- | 49
16 | Xcvr6B+ | Xcvr6B- | 50
17 | Xcvr6C+ | Xcvr6C- | 51
18 | Enc7_A+ | Enc7_A- | 52
19 | Enc7_B+ | Enc7_B- | 53
20 | Enc7_I+ | Enc7_I- | 54
21 | Home7_IN | 5V_OUT | 55
22 | Pos_Lim7_IN | Gnd | 56
23 | Neg_Lim7_IN | HomeLim7_Rtn | 57
24 | Cmd_Dac_OUT_7+ | Cmd_Dac_OUT_7- | 58
25 | Aux_Dac_OUT_7+ | Aux_Dac_OUT_7- | 59
26 | Amp_Flt7_IN | Amp_Flt7_Rtn | 60
27 | Amp_En7_Collector | Amp_En7_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr7A+ | Xcvr7A- | 63
30 | Xcvr7B+ | Xcvr7B- | 64
31 | Xcvr7C+ | Xcvr7C- | 65
32 | EncB_A+ | EncB_A- | 66
33 | EncB_B+ | EncB_B- | 67
34 | EncB_I+ | EncB_I- | 68


XMP-CPCI-6U Main Board, Rear I/O

.

XMP-CPCI-6U Main Board, Rear I/O

Backplane Connectors

CPCI-6U Main Board
Location | Function | Pinouts
J5 | Axes 0-3 | pinouts
J4 | Axes 4-7 | pinouts
J3 | User I/O | pinouts
J1 | Bus | pinouts

On CPCI-6U controllers using backplane I/O, drive signals are conveyed through connectors J3, J4 and J5.

For main boards, axes 0-3 are controlled through connector J5. Axes 4-7 are controlled through connector J4. User I/O is provided through connector J3.

On expansion boards, axes 8-11 are controlled through connector J5. Axes 12-15 are controlled through connector J4. User I/O is provided through connector J3.

On both main and expansion boards, connector J1 is reserved for computer data bussing. For more information on the CPCI-6U data bussing, click here.

CPCI-6U Main Board, CPCI Backplane Connector J5: Axes 0-3

J5 backplane connector for Axes 0-3 (CPCI main board).
Pin | F | E | D | C | B | A
22 | Gnd | Enc2_A- | Enc2_A+ | 5V_OUT | Xcvr1C- | Xcvr1C+
21 | Gnd | Enc2_B- | Enc2_B+ | Gnd | Xcvr1B- | Xcvr1B+
20 | Gnd | Enc2_I- | Enc2_I+ | Home2_IN | Xcvr1A- | Xcvr1A+
19 | Gnd | Aux_Dac_OUT_2- | Aux_Dac_OUT_2+ | Pos_Lim2_IN | Amp_En1_Emitter | Amp_En1_Collector
18 | Gnd | Cmd_Dac_OUT_2- | Cmd_Dac_OUT_2+ | Neg_Lim2_IN | Amp_Flt1_Rtn | Amp_Flt1_IN
17 | Gnd | Amp_Flt2_Rtn | Amp_Flt2_IN | HomeLim2_Rtn | Aux_Dac_OUT_1- | Aux_Dac_OUT_1+
16 | Gnd | Amp_En2_Emitter | Amp_En2_Collector | HomeLim1_Rtn | Cmd_Dac_OUT_1- | Cmd_Dac_OUT_1+
15 | Gnd | Xcvr2A- | Xcvr2A+ | Neg_Lim1_IN | Enc1_I- | Enc1_I+
14 | Gnd | Xcvr2B- | Xcvr2B+ | Pos_Lim1_IN | Enc1_B- | Enc1_B+
13 | Gnd | Xcvr2C- | Xcvr2C+ | Home1_IN | Enc1_A- | Enc1_A+
12 | Gnd | Enc3_A- | Enc3_A+ | 5V_OUT | Xcvr0C- | Xcvr0C+
11 | Gnd | Enc3_B- | Enc3_B+ | Not Connected | Xcvr0B- | Xcvr0B+
10 | Gnd | Enc3_I- | Enc3_I+ | Home3_IN | Xcvr0A- | Xcvr0A+
9 | Gnd | Aux_Dac_OUT_3- | Aux_Dac_OUT_3+ | Pos_Lim3_IN | Amp_En0_Emitter | Amp_En0_Collector
8 | Gnd | Cmd_Dac_OUT_3- | Cmd_Dac_OUT_3+ | Neg_Lim3_IN | Amp_Flt0_Rtn | Amp_Flt0_IN
7 | Gnd | Amp_Flt3_Rtn | Amp_Flt3_IN | HomeLim3_Rtn | Aux_Dac_OUT_0- | Aux_Dac_OUT_0+
6 | Gnd | Amp_En3_Emitter | Amp_En3_Collector | HomeLim0_Rtn | Cmd_Dac_OUT_0- | Cmd_Dac_OUT_0+
5 | Gnd | Xcvr3A- | Xcvr3A+ | Neg_Lim0_IN | Enc0_I- | Enc0_I+
4 | Gnd | Xcvr3B- | Xcvr3B+ | Pos_Lim0_IN | Enc0_B- | Enc0_B+
3 | Gnd | Xcvr3C- | Xcvr3C+ | Home0_IN | Enc0_A- | Enc0_A+
2 | Gnd | Analog_IN_2- | Analog_IN_2+ | Gnd | Analog_IN_1- | Analog_IN_1+
1 | Gnd | Analog_IN_3- | Analog_IN_3+ | AGnd | Analog_IN_0- | Analog_IN_0+
Pin | F | E | D | C | B | A

CPCI-6U Main Board, CPCI Backplane Connector J4: Axes 4-7

J4 backplane connector for Axes 4-7 (CPCI main board).
Pin | F | E | D | C | B | A
25 | Gnd | Analog_IN_6- | Analog_IN_6+ | AGnd | Analog_IN_5- | Analog_IN_5+
24 | Gnd | Analog_IN_7- | Analog_IN_7+ | Gnd | Analog_IN_4- | Analog_IN_4+
23 | Gnd | Enc6_A- | Enc6_A+ | Home6_IN | Xcvr5C- | Xcvr5C+
22 | Gnd | Enc6_B- | Enc6_B+ | Pos_Lim6_IN | Xcvr5B- | Xcvr5B+
21 | Gnd | Enc6_I- | Enc6_I+ | Neg_Lim6_IN | Xcvr5A- | Xcvr5A+
20 | Gnd | Cmd_Dac_OUT_6- | Cmd_Dac_OUT_6+ | HomeLim6_Rtn | Amp_En5_Emitter | Amp_En5_Collector
19 | Gnd | Aux_Dac_OUT_6- | Aux_Dac_OUT_6+ | HomeLim5_Rtn | Amp_Flt5_Rtn | Amp_Flt5_IN
18 | Gnd | Amp_Flt6_Rtn | Amp_Flt6_IN | Neg_Lim5_IN | Aux_Dac_OUT_5- | Aux_Dac_OUT_5+
17 | Gnd | Amp_En6_Emitter | Amp_En6_Collector | Pos_Lim5_IN | Cmd_Dac_OUT_5- | Cmd_Dac_OUT_5+
16 | Gnd | Xcvr6A- | Xcvr6A+ | Home5_IN | Enc5_I- | Enc5_I+
15 | Gnd | Xcvr6B- | Xcvr6B+ | Not Connected | Enc5_B- | Enc5_B+
14 | Gnd | Not Connected | Not Connected |  | Not Connected | Not Connected
13 | Gnd
12 | Gnd
11 | Gnd | Xcvr6C- | Xcvr6C+ | 5V_OUT | Enc5_A- | Enc5_A+
10 | Gnd | Enc7_A- | Enc7_A+ | Home7_IN | Xcvr4C- | Xcvr4C+
9 | Gnd | Enc7_B- | Enc7_B+ | Pos_Lim7_IN | Xcvr4B- | Xcvr4B+
8 | Gnd | Enc7_I- | Enc7_I+ | Neg_Lim7_IN | Xcvr4A- | Xcvr4A+
7 | Gnd | Cmd_Dac_OUT_7- | Cmd_Dac_OUT_7+ | HomeLim7_Rtn | Amp_En4_Emitter | Amp_En4_Collector
6 | Gnd | Aux_Dac_OUT_7- | Aux_Dac_OUT_7+ | HomeLim4_Rtn | Amp_Flt4_Rtn | Amp_Flt4_IN
5 | Gnd | Amp_Flt7_Rtn | Amp_Flt7_IN | Neg_Lim4_IN | Aux_Dac_OUT_4- | Aux_Dac_OUT_4+
4 | Gnd | Amp_En7_Emitter | Amp_En7_Collector | Pos_Lim4_IN | Cmd_Dac_OUT_4- | Cmd_Dac_OUT_4+
3 | Gnd | Xcvr7A- | Xcvr7A+ | Home4_IN | Enc4_I- | Enc4_I+
2 | Gnd | Xcvr7B- | Xcvr7B+ | Gnd | Enc4_B- | Enc4_B+
1 | Gnd | Xcvr7C- | Xcvr7C+ | 5V_OUT | Enc4_A- | Enc4_A+
Pin | F | E | D | C | B | A

CPCI-6U Main Board, CPCI Backplane Connector J3: User I/O

J3 backplane connector for User I/O (CPCI main board).
Pin | F | E | D | C | B | A
19 | Gnd | EncB_A- | EncB_A+ | Gnd | EncA_A- | EncA_A+
18 | Gnd | EncB_B- | EncB_B+ | Gnd | EncA_B- | EncA_B+
17 | Gnd | EncB_I- | EncB_I+ | Gnd | EncA_I- | EncA_I+
16 | Gnd | UserIO_B2_Rtn | UserIO_B2 | Gnd | UserIO_A0_Rtn | UserIO_A0
15 | Gnd | UserIO_B3_Rtn | UserIO_B3 | Gnd | UserIO_A3_Rtn | UserIO_A3
14 | Gnd | UserIO_B1_Rtn | UserIO_B1 | Gnd | RESET_IN | ESTOP_IN
13 | Gnd | UserIO_A2 | UserIO_A2_Rtn | Gnd | UserIO_A1_Rtn | UserIO_A1
12 | Gnd | Not Connected | Not Connected | UserIO_B0_Rtn | Not Connected | Not Connected
11 | Gnd |  |  | UserIO_B0
10 | Gnd |  |  | Not Connected
9 | Gnd
8 | Gnd
7 | Gnd
6 | Gnd
5 | Gnd |  |  | Gnd
4 | Gnd |  |  | Not Connected
3 | Gnd |  |  | Gnd
2 | Gnd |  |  | Not Connected
1 | Gnd |  |  | Gnd
Pin | F | E | D | C | B | A


XMP Controller Configurations

.

XMP Controller Configurations

As demonstrated in the "XMP Hardware Overview" above, XMP controllers come from MEI with a variety of configurable options; however, not all options apply. (For example, SERCOS controllers have no voltage options because they function optically.) MEI organizes its XMP controllers by form factor, bus, axes, and voltage. Several common controllers are listed in the table below.

Common XMP controllers.
Data Type | Form Factor | Opto Input Voltage | No. of Axes 1 | No. of Rings 2 | Description | Part No.
XMP-analog | PCI | 5 | 4 |  | XMP-PCI-4-5V | T003-0006
 | PCI |  | 8 |  | XMP-PCI-8-5V | T003-0001
 | PCI |  | 16 |  | XMP-PCI-16-5V | T003-0003
 | PCI | 24 | 4 |  | XMP-PCI-4-24V | T003-0005
 | PCI |  | 8 |  | XMP-PCI-8-24V | T003-0002
 | PCI |  | 16 |  | XMP-PCI-16-24V | T003-0004
 | CPCI-3U | 5 | 4 |  | XMP-CPCI-3U-4-5V | T001-0010
 | CPCI-6U | 5 | 4 |  | XMP-CPCI-4-5V | T001-0016
 | CPCI-6U |  | 8 |  | XMP-CPCI-8-5V | T001-0003
 | CPCI-6U | 24 | 4 |  | XMP-CPCI-4-24V | T001-0017
 | CPCI-6U |  | 8 |  | XMP-CPCI-8-24V | T001-0004
 | CPCI-6U |  | 12 |  | XMP-CPCI-12-24V | T001-0015
 | CPCI-6U |  | 16 |  | XMP-CPCI-16-24V | T001-0006
Network (XMP-SERCOS) | PCI | N/A | 8 | 1 | XMP-SERCOS-PCI-S1 | T004-0005
 | PCI | N/A | 16 | 2 | XMP-SERCOS-PCI-S2 | T004-0004
 | CPCI-6U | N/A | 24 | 3 | XMP-SERCOS-CPCI-S3 | T004-0001
 | PMC | N/A | 8 | 1 | XMP-SERCOS-PMC-S1 | T004-0002

IMPORTANT NOTE: When ordering parts or service from MEI, please refer to its part number (e.g., "T003-0005").

1. Most basic ("main") XMP analog controllers come configured for 8 axes. Additional axes are configured by adding an expansion board to the controller, boosting the total number to either 12 or 16 axes per controller. (Expansion is not available in XMP-CPCI-3U or PMC form factors.)

2. SERCOS controllers are configured for either 1 or 3 rings, with each ring handling a maximum of 8 SERCOS devices.


XMP Controller Installation

.

XMP Controller Installation

Depending upon form factor, installation of your XMP controller will vary. However, in all cases, good electrical contact must be ensured at connectors; otherwise, noise and power problems will develop. (Connections should be verified through inspection and testing.)

Standard safety rules prevail during installation of any hardware. Some are summarized below for the XMP. For more information, refer to local occupational safety regulations and the manufacturer of your motion drive.

Turn Off All Power Before Installing Equipment

Before installing any motion control equipment, including XMP controllers, power should be switched OFF. Unplug all power plugs from their sources of power.

Observe ESD Precautions

To prevent damage to controller and drive electronics due to electrostatic discharge (ESD), service personnel are cautioned to observe proper grounding during handling of components.

Grounding straps should be worn at all times when handling XMP controller boards and connection hardware.

Define and Clear a Safety Zone!

During installation and testing of motion control hardware-software, a safety zone should be defined around moving components and kept clear of personnel, hands, fingers, and loose hardware. During repowering of the system, motion control components may behave erratically due to misconnected lines, or wrongly configured software settings. Sudden and unexpected moves by components can cause injury, property damage or even death! Under NO circumstances, should a motion system be tested or operated while personnel are within the safety zone. Additionally, beware of flying debris from unsecured hardware operating at high speeds. The use of safety shielding is highly recommended.

Install Controller

XMP controllers are designed to fit standard industry buses and card cages (e.g., PCI, CPCI). When installing and removing controllers, verify that good electrical contact is made between the controller and receptacle.

PCI
XMP-PCI controllers are installed into the PCI buses of their host computer's mother boards. During installation, verify the controller is seated firmly in its assigned PCI slot by firmly pressing downward. The I/O bracket should be screwed securely to the expansion bay chassis.

XMP-CPCI-6U and XMP-SERCOS-CPCI-6U
XMP-CPCI-6U controllers are installed in industry standard CPCI slots. They are secured with ejectors. To install, first verify that both ejectors are in the open (rotated outward) position. Align the PC board with the card slot in the CPCI chassis, then press home. To secure, rotate each ejector until claws engage holes in the top-bottom chassis rails and lock the controller into place. To remove an XMP-CPCI-6U controller from its slot, first loosen the captive screws located at the top and bottom chassis rails. Next, simultaneously pinch each ejector at its flex point to unlock, then rotate outward. The controller should eject.

XMP-CPCI-3U
XMP-CPCI-3U controllers feature one locking ejector at the base of the front panel and a captive screw at the top. The XMP-CPCI-3U chassis has an ejector rail along its bottom and a threaded hole on its top rail to match the captive screw. To install, first verify that the bottom ejector is in the open (rotated outward) position. Align the PC board with the card slot in the CPCI chassis, then press home.

To secure, apply gentle pressure to the edge of the card while rotating the bottom ejector inward. The ejector's claws will engage holes in the bottom chassis rail and lock the controller into place. Secure the captive screw in the chassis at the top of the controller by rotating clockwise.

To remove an XMP-CPCI-3U controller from its slot, first loosen the captive screw by rotating counterclockwise. Pull the red ejector tab outward, then rotate the ejector downward. The controller should eject.

XMP-SERCOS-PMC
XMP-PMC controllers are connected directly to motherboards via mezzanine connectors. The boards are secured to the motherboard using two (2) screws and stand-offs. To prevent damage to the motherboard, do not overtighten the screws.


Drive Enable Wiring

.

Drive Enable Wiring

Definition of Fail Safe Wiring
One of the first questions motion system designers must address is how to wire the AmpEnable to a drive for fail safe operation. A fail safe drive enable circuit is one that is disabled when either the controller loses power or control lines are cut. MEI strongly recommends avoiding any configuration where loss of power leads to a runaway axis. In many cases, the use of automatic, dynamic braking is recommended for high-mass, high-speed loads.

Wiring and Drive Behavior
The actual behavior of a drive enable circuit depends upon two factors:

  • The drive's internal configuration.
  • How the Amp Enable line is wired between the XMP controller and the drive.

Two examples of fail safe wiring are shown below. They do not represent the only correct way to configure drives, but they can be used as guides.

Example 1: Active High

In the case of an active high drive enable input, the drive is "enabled" when the Amp Enable signal is high. The diagram below shows how to connect a fail-safe circuit. Normally, the controller's output transistor is inactive. When the transistor is inactive (OFF), the resistor pulls Amp Enable Input to ground, disabling the drive. When the transistor is active (ON), the Amp Enable Input is pulled up to +5V or +24V, enabling the drive.

Active high wiring.

Example 2: Active Low

In the case of an active low drive enable input, the drive is "enabled" when the Amp Enable signal is low. The diagram below shows how to connect a fail-safe circuit. Normally, the controller's output transistor is inactive. When the transistor is inactive (OFF), the resistor pulls the Amp Enable Input up to +5V or +24V, disabling the drive. When the transistor is active (ON), the Amp Enable Input is pulled to ground, enabling the drive.

Active low wiring.

Setting Amp Enable and Polarity from Motion Console
When operating drive amplifiers with Motion Console, you must indicate the following:

  • the state of the amplifier: Enabled or Disabled (unchecked)
  • the polarity of the amplifier: Inverted or Normal (unchecked)

This is done using the Amp Enable and Amp Polarity parameters within the Motor Summary / Config tab page:

The Amp Enable parameter is for use with drives equipped with enable lines. On such drives, the amplifier responds to commands only when the Amp Enable parameter is set to Enabled. If Amp Enable is not enabled, the amplifier will not respond to commands. For fail-safe operation, the Amp Enable logic is determined by the wiring between the controller and drive. In this case, the Amp Polarity should be set to Inverted. The Amp Polarity parameter tells the XMP controller whether the output transistor should be normally inactive, to disable the drive (Inverted) or normally active, to disable the drive (Normal). Only the "Inverted" Amp Polarity setting supports fail-safe wiring, and is strongly recommended.

Amp Enable Output

The optically-isolated Amp_Enable outputs provide control of the servo amplifier, allowing the XMP to disable the amplifier under fault conditions.

Active LOW Drive Enable Wiring

Connect Amp Enable output to drive (active LOW).

Active HIGH Drive Enable Wiring

Connect Amp Enable output to drive (+5/24V, active HIGH).

Amplifier Enabling from the MPI
Amplifier enabling is a crucial safety issue in the design of your application. Your system should be designed to anticipate the possibility of a sudden loss of power and/or connectivity to the controller and/or drive.

To make a full accounting of your motion system's safety features, you must also address the system's mecahnical dynamics with a disabled drive. (A disabled drive does NOT necessarily mean that all motion will be stopped!) In many cases, the use of automatic, dynamic braking is recommended for high-mass, high-speed loads. Determining whether an amplifier remains enabled or disabled with the controller powered OFF depends upon several factors:

  • Does the drive have an Amp Enable line? (Not all drives do. Check this!) Is the drive's Amp Enable line internally configured as active-high or active low?
  • How is the Amp Enable line wired between the controller and the drive? With power OFF to the controller, does wiring pull the drive's Amp Enable line HIGH or LOW?
  • How is the Amp Enable line configured on the controller when it is powered? Is the Amp Enable output transceiver normally ON or OFF? Is the Amp Enable output inverted?
  • Does the application software maintain the Amp Enable line in an enabled state when running? Is the controller's position error limit configured for Abort (disables the drive)? Does the application respond to states, disabling or enabling the drive?

State logic for active high and active low drives.
DRIVE | WIRING | STATE
How is the drive's Amp Enable line internally configured? | With power to the controller OFF, current to the drive's Amp Enable line is... | When power to the controller is OFF, the drive is...
Active High | High | Enabled
 | Low | Disabled*
Active Low | High | Disabled*
 | Low | Enabled
* Recommended configuration.

Amp Fault Input

To Pull-up Logic

Connect Amp Fault input to amplifier (pull-up logic).

To Pull-down Logic

Connect Amp Fault input to amplifier (pull-down logic).


Host Computer Electrical Requirements

.

Host Computer Electrical Requirements

Below is shown a table of basic host computer electrical requirements for XMP controllers. XMP voltage and current specifications.

XMP voltage and current specifications.
Controller | Voltage 1 | Current 2 (Typ. amps) | Current (Max. amps)
XMP-PCI (analog) | +5 VDC ± 5% | 1.70 (main) 1.20 (expansion) | 3.20 (main) 2.20 (expansion)
 | +12 VDC ± 10% | 0.03 (main) 0.01 (expansion) | 0.05 (main) 0.01 (expansion)
 | -12 VDC ± 10% | 0.01 (main) 0.01 (expansion) | 0.01 (main) 0.01 (expansion)
SIM4 Module on XMP-PCI | +5 VDC ± 5% | 0.18 | 0.40
 | +12 VDC ± 10% | 0.01 | 0.01
 | -12 VDC ± 10% | 0.03 | 0.05
XMP-CPCI-6U (analog) | +3.3 VDC ± 10% | 0.90 (main) 0.70 (expansion) | 1.40 (main) 1.00 (expansion)
 | +5 VDC ± 5% | 0.90 (main) 0.90 (expansion) | 1.90 (main) 1.90 (expansion)
 | +12 VDC ± 10% | 0.03 (main) 0.01 (expansion) | 0.05 (main) 0.01 (expansion)
 | -12 VDC ± 10% | 0.01 (main) 0.01 (expansion) | 0.01 (main) 0.01 (expansion)
SIM4 Module on XMP-CPCI | +3.3 VDC ± 10% | 0.08 | 0.20
 | +5 VDC ± 5% | 0.12 | 0.20
 | +12 VDC ± 10% | 0.01 | 0.01
 | -12 VDC ± 10% | 0.03 | 0.05
XMP-SERCOS-CPCI-6U | +3.3 VDC ± 10% | 0.50 | 0.75
 | +5 VDC ± 5% | 0.50 | 0.75
XMP-CPCI-3U (analog) | +3.3 VDC ± 10% | 0.50 | 0.90
 | +5 VDC ± 5% | 0.45 | 1.15
XMP-SERCOS-PMC | +3.3 VDC ± 10% | 0.375 | 0.50
 | +5 VDC ± 5% | 0.375 | 0.50
XMP-SERCOS-PCI-S2 | +5 VDC ± 5% | 0.60 | 1.00

1. Controller voltage required at computer or card cage.

2. Installed SIM4 modules and encoders also contribute to current demands.

Using the XMP controller to power encoders?

Then make sure that voltage drops in your cabling are NOT a problem. If voltage drops are a problem, power the encoders using an external supply. For every 100 mA of current drawn, the 5V_OUT voltage may drop 0.2 volts or more (due to cable resistance). For example, if two encoders each draw 150 mA, then 5V_OUT may drop to 4.4 volt at the encoders. This could cause your encoder to fail!

SERCOS Drives

SERCOS is a standardized industrial format utilizing fiber-optic technology. The optical power demands of drives vary widely, depending upon the drive itself, length of cables, etc. For more information regarding SERCOS motion drive power demands, please see your drive's manufacturer.

XMP-analog Controllers

XMP-analog systems rely upon traditional copper wiring to pass analog signals between the drive and controller. Two voltages are available for opto-inputs on XMP controllers: 5VDC and 24VDC. To determine whether your controller supports 5V or 24V, look for a sticker on the XMP circuit board. The sticker will say either "5V" or "24V."

For more detailed information regarding configuration of analog I/O click here. Specifications for transceiver components used in the XMP-Analog controller's I/O are provided in tables below.

RS422 receiver.
Description | Specification
Input High Threshold | VDIFF > 0.2V
Input Low Threshold | VDIFF < -0.2V
Input Current | IIN < 1.0mA @ VIN = 12V IIN < -0.8mA @ VIN = -7V NOTE: In addition, encoder inputs have 100 [image] differential termination.
Propagation Delay | Tp < 200 ns
Absolute Maximums 1 | ESD Protection ± 15kV -8V < VIN < +12.8V (input to GND)

RS422 transmitter.
Description | Specification
Differential Output Voltage | VDIFF < 5V @ I = 0mA VDIFF > 2V @ I = 20mA
Common Mode Output Voltage | VOUT (common mode) < 3V (100 [image] load)
Propagation Delay | Tp < 60ns
Absolute Maximums 2 | IOUT < 50mA

Dedicated opto-inputs.
Description | Specification
Active Input Guaranteed | IIN > 2mA 5V input (820 [image] current limit resistor): VIN < 3V @ IIN = 2mA 24V input (6.8k [image] current limit resistor): VIN < 15V @ IIN = 2mA
Inactive Input Guaranteed | VIN < 0.1mA
Propagation Delay | Tp < 20µs
Absolute Maximums 3 | 5V input (820 [image] current limit resistor): VIN < 10V VIN < 10mA 24V input (6.8k [image] current limit resistor): VIN < 30V VIN < 5mA VISOLATION < 40V

Dedicated opto-outputs.
Description | Specification
Active Output Guaranteed | VOUT < 0.3V @ IOUT < 2mA VOUT < 1.1V @ IOUT < 10mA
Inactive Output Guaranteed | IOUT < 0.01mA
Propagation Delay | Tp < 100µs (load < 10 k [image] )
Absolute Maximums 4 | IOUT < 50mA VOUT < 30V IREVERSE < 100mA @ VREVERSE 0.4V (protection diode) VISOLATION < 40V

Bi-directional opto-inputs.
Description | Specification
Active Input Guaranteed | IIN > 2mA VIN < 1.7V @ IIN = 2mA
Inactive Input Guaranteed | IIN < 0.1mA
Propagation Delay | Tp < 20µs
Absolute Maximums 5 | IIN < 50mA IREVERSE < 30V VISOLATION < 40V

Bi-directional opto-outputs.
Description | Specification
Active Output Guaranteed | VOUT < 0.3V @ IOUT < 2mA VOUT < 1.1V @ IOUT < 10mA
Inactive Input Guaranteed | IOUT < 0.01mA
Propagation Delay | Tp < 100µs (load < 10 k [image] )
Absolute Maximums 6 | IOUT < 50mA VOUT < 30V IREVERSE < 50mA @ VREVERSE 1.7V (input circuit) VISOLATION < 40V
1. Exceeding absolute maximums may damage components.
2. Exceeding absolute maximums may damage components.
3. Exceeding absolute maximums may damage components.
4. Exceeding absolute maximums may damage components.
5. Exceeding absolute maximums may damage components.
6. Exceeding absolute maximums may damage components.


Expansions and Add-ons

.

Expansions and Add-ons

Some XMP controllers may be enhanced with additional hardware. These include:

Expansion boards
These expand the number of axes run by a controller by adding up to two motion blocks for a total of 16 axes. Unlike main boards, expansion boards do not contain SHARC DSP processors. They are available for XMP-PCI and XMP-CPCI-6U form factors only (not available for XMP-CPCI-3U and XMP-SERCOS-PMC controllers). An expanded XMP-CPCI-6U controller is shown below.

SIM4 modules
Scale Interpolation Modules (SIMs) are mounted mezzanine-style to motion controllers that use encoders with sinusoidal outputs. These enhance positional resolution significantly and are available for XMP-PCI and XMP-CPCI-6U controllers only. A maximum of two SIM4 modules may be added to each main or expansion board. A SIM4 module is shown below with an XMP-PCI controller.

For detailed information regarding SIM4 modules, please refer to Application Note 206 from Motion Engineering.


General XMP I/O Specifications

.

General XMP I/O Specifications

Opto Inputs

Positive Limit In
Negative Limit In
Amp Fault In
Estop In
Reset In
User Limit In

Specifications:
Min On Current: 2 mA @ 25 °C
In Line Resistence: 5V model – 820 ohms, 24V model – 6.87 kohms
Forward Voltage (If = 5mA) – 1.1 V typ, 1.4 max
Absolute maximum ratings:
Forward Current: 50 mA

Opto Outputs

Amp Enable
User IO Out

Specifications:
Min On Current: 5mA @ 25 °C
Max Off Current: (Vce = 40 V) – 400 nA
Rise time < 10us
Fall time < 100us

RS 422 Transceiver Inputs

Encoder A, B, C
Index

Specifications:
Max Common Mode Voltage: – 7/12 V
Logic Threshold +/– 14V

NOTE: XCVRs have no termination resistors

XCVR A, B, C

Specifications:
Max Common Mode Voltage: – 8/12.5 V
Logical Threshold +/– 0.2 V differential

Absolute Maximum Ratings:
Input Voltage Differential: –10V
Input Voltage: +/– 14V

Axis 0-7 Encoder inputs have software configurable 100 ohm termination
Aux Encoders have 100 ohm termination
Unterminated input resistance 12 kOhm
15kV ESD protection

RS 422 Transciever Outputs

XCVR A, B, C

Specifications:
Short circuit protected: (35 - 250 mA short circuit current)
ESD Protected: +/– 15 kV
Output into 50 Ohms: 2V Min
Output into no load: 5V Max

DAC Outputs

DAC Outputs

Specifications:
DAC ground reference connected directly to DAC grounds.
16 bit resolution
+/– 10V range
Short circuit current 25 mA typ.
Rout = 0.3 ohm typ.

ADC Inputs

ADC Inputs

Specifications:
Input range: +/– 1.25V, 2.5V, 5V, 10V software selectable
16 bit resolution

Absolute maximum ratings:
Continuous Current: +/– 30mA
Input Voltage: +/– 25 V
Differential Input Resistance > 2 MOhm


Introduction

.

Introduction

This chapter describes XMP controller-computer bussing, and is organized by form factor. The reader should note that both XMP-analog and XMP-SERCOS controllers utilize identical bus connections for each respective form factor. (For example, a CPCI controller may have the same bus connections, whether the I/O is configured for XMP-analog or -SERCOS.)

"Main" versus "Expansion" Boards (XMP-analog only)

XMP-analog controllers may be configured for varying numbers of axes. Up to 8 axes are controlled by a single "main" controller board. Where more than 8 axes are required, it is necessary to add an "expansion" board.

Expansion boards consist of separate electronics, very similar in appearance and function to main boards. Typically, an expansion board is located on the bus or backplane immediately adjacent to a main board. Both boards (main and expansion) are connected via a short ribbon cable. When connected together, one main and one expansion board constitute a single, unified "controller." Expansion boards are not available for XMP-SERCOS controllers.

XMP-CPCI-6U main and expansion boards. Connection is via ribbon cable. To release ribbon cable, press clip 1 while disconnecting connector 2 XMP-PCI connection is similar.


XMP Analog I/O Introduction

.

Introduction

This chapter describes analog I/O pin-outs for the XMP-PCI, XMP-CPCI-6U, and XMP-CPCI-3U controllers. The first section of this chapter describes connector hardware. The second section of this chapter describes the actual I/O configuration, including pin-outs, organized by form factor.

Identifying Analog I/O Hardware

Your analog XMP controller's I/O hardware type can be easily identified by examining the connection between the XMP controller and drive:

VHDCI Cabling and Terminal Block

XMP-PCI and XMP-CPCI use the same 68-pin cable for all front panel (VHDCI) I/O connections.

STC-136 Terminal Connector Blocks

All VHDCI connectors used with XMP controllers are 68-pin types. Corresponding to this, terminal blocks having 68 terminals per side are preferred. MEI recommends the STC-136, which can accommodate up to two cables. These use screw terminals for analog wiring.

WARNING! Many "controller problems" can be traced to faulty wiring. As with all analog wiring, it is the user's responsibility to verify that wiring is correctly connected per specifications BEFORE applying power. Verify the following when wiring terminal blocks:

At the Terminal Block

  • Verify all wiring is clearly and correctly labeled and color-coded for easy identification. Assembly personnel should have clear and concise wiring diagrams available when wiring.
  • Connect wires to terminal blocks by referencing terminal numbers, NOT by a wire's placement relative to another wire.
  • Strip wires appropriately: removing too much insulation will leave bare wires exposed and susceptible to short-circuits; removing too little insulation will prevent electrical contact inside the lug. Do not pinch or crimp wires when stripping--they will break!
  • Do not insert wire above a terminal block's lug. When the lug is tightened, it will not close on the wire, failing to make contact.
  • Verify that debris does not enter the lug with the bare wire; it may prevent complete closure of the lug. Verify that lugs are tight. Remove all loose wire strands.
  • Discard all terminal blocks with damaged traces.

At the Connectors

  • Verify that connector pins are straight BEFORE attempting to connect cables. Bent pins can short-circuit, or ruin a connector! If connectors resist, do not force them. Check for problems first.
  • Observe electrostatic discharge (ESD) precautions while handling connectors and terminal blocks. High-level ESD can damage circuitry over cables.


Introduction to Configuring an XMP-Analog Motion Control System

.

Introduction

This chapter describes basic encoder, amplifier, and limit signal connectivity via 68-pin VHDCI (Very High Density Cable Interconnect, also known as SCSI-5) receptacles for the XMP-PCI, XMP-CPCI-6U and XMP-CPCI-3U controllers. The XMP-CPCI-6U and XMP-CPCI-3U are also offer a rear I/O backplane connection option. For more information, click here.

I/O via VHDCI Receptacles

STC-136 Terminal Blocks MEI offers STC-136 terminal blocks to assist in connecting controllers to drives via VHDCI. STC-136 terminal blocks utilize preconfigured cables from VHDCI receptacles. Each cable services one 68-pin VHDCI connector; each STC-136 can service two cables. The STC-136 terminal block provides a simple method for connecting hardware to your controllers using conventional screw terminals. Wires are connected to the terminal by inserting them into slots on the terminal block and tightening lug screws. For ease of use, numbering is identical between VHDCI receptacle pins and STC-136 terminals. Some users prefer alternatives to the STC-136 for connecting to the XMP controller's VHDCI receptacles. If only a subset of lines are being used, more compact hardware may be preferred. Regardless how your connection scheme is configured, you may use the VHDCI pin-out information in this chapter to design your system.

I/O via Backplane Connection

Some CPCI-6U and -3U controllers perform input-output (I/O) via their backplane connectors. For more information regarding backplane analog I/O on CPCI form factors, click here.

+5 and +24 Volt I/O XMP controllers accomodate +5VDC or +24VDC optoisolated inputs. Resistors installed on each controller determine which I/O voltage it is configured for; otherwise, they are electronically identical. To determine which voltage your controller is configured for, look for the small, white label.

XMP configurations: +5V and +24V.

CAUTION! Under most conditions, motor axes are NOT freely interchangeable with each other! Always check the compatibility of wiring BEFORE plugging an axis into the connector of a different axis. Otherwise, damage to components and/or the controller may result.

Pay attention to the use of power and ground returns. AGnd should be used for the analog inputs. Digital system grounds (Gnd) are provided for use as a system ground reference. These grounds (AGnd, Gnd) are all tied to a single point on the XMP board. In-line, fused 5 VDC power is provided for external encoders. Be careful to estimate the additional 5 VDC current required, and the voltage drop across the cables.

Using STC-136 Terminal Blocks

Terminal blocks organize your system wiring, making them especially helpful for lab development. The STC-136 terminal blocks route each CBL-68 pin to a screw terminal on a DIN rail, (Phoenix Contact base). Each STC-136 provides connection to four (4) axes of I/O (a full motion block), and works with both 24 VDC and 5 VDC systems.

Each STC-136 provides connectivity for two (2) axes.

Please note that terminal numbers for the STC-136 are matched one-to-one with VHDCI connector pins. (For example, Pin #1 on the VHDCI is the same as Terminal #1 on the STC-136, and so on.) Therefore, even if you choose not to use STC-136 terminal blocks for connection, you may still use the pin-out information in these chapters to configure your own connectors.

For full STC-136 wiring and pinout diagrams, click here.


XMP-PCI Expansion Board

.

XMP-PCI Expansion Board

VHDCI Connectors

PCI Expansion Board
Location | Axes | Pinouts
J8-9 | 8-9 | pinouts
J10-11 | 10-11 | pinouts
J12-13 | 12-13 | pinouts
J14-15 | 14-15 | pinouts

XMP-PCI, VHDCI Connectors, Expansion Board

Axes 8-9 VHDCI Connector (PCI)

Connector for Axes 8 and 9 (PCI expansion board).
Pin | Signal | Signal | Pin
1 | Not Connected | Not Connected | 35
2 | Not Connected | Not Connected | 36
3 | Gnd | AGnd | 37
4 | Enc8_A+ | Enc8_A- | 38
5 | Enc8_B+ | Enc8_B- | 39
6 | Enc8_I+ | Enc8_I- | 40
7 | Home8_IN | 5V_OUT | 41
8 | Pos_Lim8_IN | Gnd | 42
9 | Neg_Lim8_IN | HomeLim8_Rtn | 43
10 | Cmd_Dac_OUT_8+ | Cmd_Dac_OUT_8- | 44
11 | Aux_Dac_OUT_8+ | Aux_Dac_OUT_8- | 45
12 | Amp_Flt8_IN | Amp_Flt8_Rtn | 46
13 | Amp_En8_Collector | Amp_En8_Emitter | 47
14 | UserIO_C0 | UserIO_C0_Rtn | 48
15 | Xcvr8A+ | Xcvr8A- | 49
16 | Xcvr8B+ | Xcvr8B- | 50
17 | Xcvr8C+ | Xcvr8C- | 51
18 | Enc9_A+ | Enc9_A- | 52
19 | Enc9_B+ | Enc9_B- | 53
20 | Enc9_I+ | Enc9_I- | 54
21 | Home9_IN | 5V_OUT | 55
22 | Pos_Lim9_IN | Gnd | 56
23 | Neg_Lim9_IN | HomeLim9_Rtn | 57
24 | Cmd_Dac_OUT_9+ | Cmd_Dac_OUT_9- | 58
25 | Aux_Dac_OUT_9+ | Aux_Dac_OUT_9- | 59
26 | Amp_Flt9_IN | Amp_Flt9_Rtn | 60
27 | Amp_En9_Collector | Amp_En9_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr9A+ | Xcvr9A- | 63
30 | Xcvr9B+ | Xcvr9B- | 64
31 | Xcvr9C+ | Xcvr9C- | 65
32 | UserIO_C1 | UserIO_C1_Rtn | 66
33 | Not Connected | UserIO_C2 | 67
34 | Not Connected | UserIO_C2_Rtn | 68

Axes 10-11 VHDCI Connector (PCI)

Connector for Axes 10 and 11 (PCI expansion board).
Pin | Signal | Signal | Pin
1 | EncC_A+ | EncC_A- | 35
2 | EncC_B+ | EncC_B- | 36
3 | EncC_I+ | EncC_I- | 37
4 | Enc10_A+ | Enc10_A- | 38
5 | Enc10_B+ | Enc10_B- | 39
6 | Enc10_I+ | Enc10_I- | 40
7 | Home10_IN | 5V_OUT | 41
8 | Pos_Lim10_IN | Gnd | 42
9 | Neg_Lim10_IN | HomeLim10_Rtn | 43
10 | Cmd_Dac_OUT_10+ | Cmd_Dac_OUT_10- | 44
11 | Aux_Dac_OUT_10+ | Aux_Dac_OUT_10- | 45
12 | Amp_Flt10_IN | Amp_Flt10_Rtn | 46
13 | Amp_En10_Collector | Amp_En10_Emitter | 47
14 | UserIO_C3 | UserIO_C3_Rtn | 48
15 | Xcvr10A+ | Xcvr10A- | 49
16 | Xcvr10B+ | Xcvr10B- | 50
17 | Xcvr10C+ | Xcvr10C- | 51
18 | Enc11_A+ | Enc11_A- | 52
19 | Enc11_B+ | Enc11_B- | 53
20 | Enc11_I+ | Enc11_I- | 54
21 | Home11_IN | 5V_OUT | 55
22 | Pos_Lim11_IN | Gnd | 56
23 | Neg_Lim11_IN | HomeLim11_Rtn | 57
24 | Cmd_Dac_OUT_11+ | Cmd_Dac_OUT_11- | 58
25 | Aux_Dac_OUT_11+ | Aux_Dac_OUT_11- | 59
26 | Amp_Flt11_IN | Amp_Flt11_Rtn | 60
27 | Amp_En11_Collector | Amp_En11_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr11A+ | Xcvr11A- | 63
30 | Xcvr11B+ | Xcvr11B- | 64
31 | Xcvr11C+ | Xcvr11C- | 65
32 | Gnd | AGnd | 66
33 | Not Connected | Not Connected | 67
34 | Not Connected | Not Connected | 68

Axes 12-13 VHDCI Connector (PCI)

Connector for Axes 12 and 13 (PCI expansion board).
Pin | Signal | Signal | Pin
1 | UserIO_D0 | UserIO_D0_Rtn | 35
2 | UserIO_D1 | UserIO_D1_Rtn | 36
3 | Gnd | Gnd | 37
4 | Enc12_A+ | Enc12_A- | 38
5 | Enc12_B+ | Enc12_B- | 39
6 | Enc12_I+ | Enc12_I- | 40
7 | Home12_IN | 5V_OUT | 41
8 | Pos_Lim12_IN | Gnd | 42
9 | Neg_Lim12_IN | HomeLim12_Rtn | 43
10 | Cmd_Dac_OUT_12+ | Cmd_Dac_OUT_12- | 44
11 | Aux_Dac_OUT_12+ | Aux_Dac_OUT_12- | 45
12 | Amp_Flt12_IN | Amp_Flt12_Rtn | 46
13 | Amp_En12_Collector | Amp_En12_Emitter | 47
14 | UserIO_D2 | UserIO_D2_Rtn | 48
15 | Xcvr12A+ | Xcvr12A- | 49
16 | Xcvr12B+ | Xcvr12B- | 50
17 | Xcvr12C+ | Xcvr12C- | 51
18 | Enc13_A+ | Enc13_A- | 52
19 | Enc13_B+ | Enc13_B- | 53
20 | Enc13_I+ | Enc13_I- | 54
21 | Home13_IN | 5V_OUT | 55
22 | Pos_Lim13_IN | Gnd | 56
23 | Neg_Lim13_IN | HomeLim13_Rtn | 57
24 | Cmd_Dac_OUT_13+ | Cmd_Dac_OUT_13- | 58
25 | Aux_Dac_OUT_13+ | Aux_Dac_OUT_13- | 59
26 | Amp_Flt13_IN | Amp_Flt13_Rtn | 60
27 | Amp_En13_Collector | Amp_En13_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr13A+ | Xcvr13A- | 63
30 | Xcvr13B+ | Xcvr13B- | 64
31 | Xcvr13C+ | Xcvr13C- | 65
32 | Gnd | AGnd | 66
33 | Not Connected | Not Connected | 67
34 | Not Connected | Not Connected | 68

Axes 14-15 VHDCI Connector (PCI)

Connector for Axes 14 and 15 (PCI expansion board).
Pin | Signal | Signal | Pin
1 | Not Connected | Not Connected | 35
2 | Not Connected | Not Connected | 36
3 | Gnd | AGnd | 37
4 | Enc14_A+ | Enc14_A- | 38
5 | Enc14_B+ | Enc14_B- | 39
6 | Enc14_I+ | Enc14_I- | 40
7 | Home6_IN | 5V_OUT | 41
8 | Pos_Lim14_IN | Gnd | 42
9 | Neg_Lim14_IN | HomeLim14_Rtn | 43
10 | Cmd_Dac_OUT_14+ | Cmd_Dac_OUT_14- | 44
11 | Aux_Dac_OUT_14+ | Aux_Dac_OUT_14- | 45
12 | Amp_Flt14_IN | Amp_Flt14_Rtn | 46
13 | Amp_En14_Collector | Amp_En14_Emitter | 47
14 | UserIO_D3 | UserIO_D3_Rtn | 48
15 | Xcvr14A+ | Xcvr14A- | 49
16 | Xcvr14B+ | Xcvr14B- | 50
17 | Xcvr14C+ | Xcvr14C- | 51
18 | Enc15_A+ | Enc15_A- | 52
19 | Enc15_B+ | Enc15_B- | 53
20 | Enc15_I+ | Enc15_I- | 54
21 | Home15_IN | 5V_OUT | 55
22 | Pos_Lim15_IN | Gnd | 56
23 | Neg_Lim15_IN | HomeLim15_Rtn | 57
24 | Cmd_Dac_OUT_15+ | Cmd_Dac_OUT_15- | 58
25 | Aux_Dac_OUT_15+ | Aux_Dac_OUT_15- | 59
26 | Amp_Flt15_IN | Amp_Flt15_Rtn | 60
27 | Amp_En15_Collector | Amp_En15_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr15A+ | Xcvr15A- | 63
30 | Xcvr15B+ | Xcvr15B- | 64
31 | Xcvr15C+ | Xcvr15C- | 65
32 | EncD_A+ | EncD_A- | 66
33 | EncD_B+ | EncD_B- | 67
34 | EncD_I+ | EncD_I- | 68


XMP-PCI Main Board

.

XMP-PCI Main Board

VHDCI Connectors

PCI Main Board
Location | Axes | Pinouts
J0-1 | 0-1 | pinouts
J2-3 | 2-3 | pinouts
J4-5 | 4-5 | pinouts
J6-7 | 6-7 | pinouts

All motion drive I/O for XMP-PCI controllers is performed via VHDCI connectors on the rear end panel of the controller. Each VHDCI connector is connected to a motion drive via cable. Pin-outs are described below:

XMP-PCI, VHDCI Connectors, Main Board

Axes 0-1, VHDCI Connector (XMP-PCI)

Connector for Axes 0 and 1 (PCI main board).
Pin | Signal | Signal | Pin
1 | Analog_IN_0+ | Analog_IN_0- | 35
2 | Analog_IN_1+ | Analog_IN_1- | 36
3 | Gnd | AGnd | 37
4 | Enc0_A+ | Enc0_A- | 38
5 | Enc0_B+ | Enc0_B- | 39
6 | Enc0_I+ | Enc0_I- | 40
7 | Home0_IN | 5V_OUT | 41
8 | Pos_Lim0_IN | Gnd | 42
9 | Neg_Lim0_IN | HomeLim0_Rtn | 43
10 | Cmd_Dac_OUT_0+ | Cmd_Dac_OUT_0- | 44
11 | Aux_Dac_OUT_0+ | Aux_Dac_OUT_0- | 45
12 | Amp_Flt0_IN | Amp_Flt0_Rtn | 46
13 | Amp_En0_Collector | Amp_En0_Emitter | 47
14 | UserIO_A0 | UserIO_A0_Rtn | 48
15 | Xcvr0A+ | Xcvr0A- | 49
16 | Xcvr0B+ | Xcvr0B- | 50
17 | Xcvr0C+ | Xcvr0C- | 51
18 | Enc1_A+ | Enc1_A- | 52
19 | Enc1_B+ | Enc1_B- | 53
20 | Enc1_I+ | Enc1_I- | 54
21 | Home1_IN | 5V_OUT | 55
22 | Pos_Lim1_IN | Gnd | 56
23 | Neg_Lim1_IN | HomeLim1_Rtn | 57
24 | Cmd_Dac_OUT_1+ | Cmd_Dac_OUT_1- | 58
25 | Aux_Dac_OUT_1+ | Aux_Dac_OUT_1- | 59
26 | Amp_Flt1_IN | Amp_Flt1_Rtn | 60
27 | Amp_En1_Collector | Amp_En1_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr1A+ | Xcvr1A- | 63
30 | Xcvr1B+ | Xcvr1B- | 64
31 | Xcvr1C+ | Xcvr1C- | 65
32 | UserIO_A1 | UserIO_A1_Rtn | 66
33 | RESET_IN | UserIO_A2 | 67
34 | ESTOP_IN | UserIO_A2_Rtn | 68

Axes 2-3 VHDCI Connector (PCI)

Connector for Axes 2 and 3 (PCI main board).
Pin | Signal | Signal | Pin
1 | EncA_A+ | EncA_A- | 35
2 | EncA_B+ | EncA_B- | 36
3 | EncA_I+ | EncA_I- | 37
4 | Enc2_A+ | Enc2_A- | 38
5 | Enc2_B+ | Enc2_B- | 39
6 | Enc2_I+ | Enc2_I- | 40
7 | Home2_IN | 5V_OUT | 41
8 | Pos_Lim2_IN | Gnd | 42
9 | Neg_Lim2_IN | HomeLim2_Rtn | 43
10 | Cmd_Dac_OUT_2+ | Cmd_Dac_OUT_2- | 44
11 | Aux_Dac_OUT_2+ | Aux_Dac_OUT_2- | 45
12 | Amp_Flt2_IN | Amp_Flt2_Rtn | 46
13 | Amp_En2_Collector | Amp_En2_Emitter | 47
14 | UserIO_A3 | UserIO_A3_Rtn | 48
15 | Xcvr2A+ | Xcvr2A- | 49
16 | Xcvr2B+ | Xcvr2B- | 50
17 | Xcvr2C+ | Xcvr2C- | 51
18 | Enc3_A+ | Enc3_A- | 52
19 | Enc3_B+ | Enc3_B- | 53
20 | Enc3_I+ | Enc3_I- | 54
21 | Home3_IN | 5V_OUT | 55
22 | Pos_Lim3_IN | Gnd | 56
23 | Neg_Lim3_IN | HomeLim3_Rtn | 57
24 | Cmd_Dac_OUT_3+ | Cmd_Dac_OUT_3- | 58
25 | Aux_Dac_OUT_3+ | Aux_Dac_OUT_3- | 59
26 | Amp_Flt3_IN | Amp_Flt3_Rtn | 60
27 | Amp_En3_Collector | Amp_En3_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr3A+ | Xcvr3A- | 63
30 | Xcvr3B+ | Xcvr3B- | 64
31 | Xcvr3C+ | Xcvr3C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_2+ | Analog_IN_2- | 67
34 | Analog_IN_3+ | Analog_IN_3- | 68

Axes 4-5 VHDCI Connector (PCI)

Connector for Axes 4 and 5 (PCI main board).
Pin | Signal | Signal | Pin
1 | UserIO_B0 | UserIO_B0_Rtn | 35
2 | UserIO_B1 | UserIO_B1_Rtn | 36
3 | Gnd | Gnd | 37
4 | Enc4_A+ | Enc4_A- | 38
5 | Enc4_B+ | Enc4_B- | 39
6 | Enc4_I+ | Enc4_I- | 40
7 | Home4_IN | 5V_OUT | 41
8 | Pos_Lim4_IN | Gnd | 42
9 | Neg_Lim4_IN | HomeLim4_Rtn | 43
10 | Cmd_Dac_OUT_4+ | Cmd_Dac_OUT_4- | 44
11 | Aux_Dac_OUT_4+ | Aux_Dac_OUT_4- | 45
12 | Amp_Flt4_IN | Amp_Flt4_Rtn | 46
13 | Amp_En4_Collector | Amp_En4_Emitter | 47
14 | UserIO_B2 | UserIO_B2_Rtn | 48
15 | Xcvr4A+ | Xcvr4A- | 49
16 | Xcvr4B+ | Xcvr4B- | 50
17 | Xcvr4C+ | Xcvr4C- | 51
18 | Enc5_A+ | Enc5_A- | 52
19 | Enc5_B+ | Enc5_B- | 53
20 | Enc5_I+ | Enc5_I- | 54
21 | Home5_IN | 5V_OUT | 55
22 | Pos_Lim5_IN | Gnd | 56
23 | Neg_Lim5_IN | HomeLim5_Rtn | 57
24 | Cmd_Dac_OUT_5+ | Cmd_Dac_OUT_5- | 58
25 | Aux_Dac_OUT_5+ | Aux_Dac_OUT_5- | 59
26 | Amp_Flt5_IN | Amp_Flt5_Rtn | 60
27 | Amp_En5_Collector | Amp_En5_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr5A+ | Xcvr5A- | 63
30 | Xcvr5B+ | Xcvr5B- | 64
31 | Xcvr5C+ | Xcvr5C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_4+ | Analog_IN_4- | 67
34 | Analog_IN_5+ | Analog_IN_5- | 68

Axes 6-7 VHDCI Connector (PCI)

Connector for Axes 6 and 7 (PCI main board).
Pin | Signal | Signal | Pin
1 | Analog_IN_6+ | Analog_IN_6- | 35
2 | Analog_IN_7+ | Analog_IN_7- | 36
3 | Gnd | AGnd | 37
4 | Enc6_A+ | Enc6_A- | 38
5 | Enc6_B+ | Enc6_B- | 39
6 | Enc6_I+ | Enc6_I- | 40
7 | Home6_IN | 5V_OUT | 41
8 | Pos_Lim6_IN | Gnd | 42
9 | Neg_Lim6_IN | HomeLim6_Rtn | 43
10 | Cmd_Dac_OUT_6+ | Cmd_Dac_OUT_6- | 44
11 | Aux_Dac_OUT_6+ | Aux_Dac_OUT_6- | 45
12 | Amp_Flt6_IN | Amp_Flt6_Rtn | 46
13 | Amp_En6_Collector | Amp_En6_Emitter | 47
14 | UserIO_B3 | UserIO_B3_Rtn | 48
15 | Xcvr6A+ | Xcvr6A- | 49
16 | Xcvr6B+ | Xcvr6B- | 50
17 | Xcvr6C+ | Xcvr6C- | 51
18 | Enc7_A+ | Enc7_A- | 52
19 | Enc7_B+ | Enc7_B- | 53
20 | Enc7_I+ | Enc7_I- | 54
21 | Home7_IN | 5V_OUT | 55
22 | Pos_Lim7_IN | Gnd | 56
23 | Neg_Lim7_IN | HomeLim7_Rtn | 57
24 | Cmd_Dac_OUT_7+ | Cmd_Dac_OUT_7- | 58
25 | Aux_Dac_OUT_7+ | Aux_Dac_OUT_7- | 59
26 | Amp_Flt7_IN | Amp_Flt7_Rtn | 60
27 | Amp_En7_Collector | Amp_En7_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr7A+ | Xcvr7A- | 63
30 | Xcvr7B+ | Xcvr7B- | 64
31 | Xcvr7C+ | Xcvr7C- | 65
32 | EncB_A+ | EncB_A- | 66
33 | EncB_B+ | EncB_B- | 67
34 | EncB_I+ | EncB_I- | 68


XMP-PCI Main Board

.

XMP-PCI Main Board

VHDCI Connectors

PCI Main Board
Location | Axes | Pinouts
J0-1 | 0-1 | pinouts
J2-3 | 2-3 | pinouts
J4-5 | 4-5 | pinouts
J6-7 | 6-7 | pinouts

All motion drive I/O for XMP-PCI controllers is performed via VHDCI connectors on the rear end panel of the controller. Each VHDCI connector is connected to a motion drive via cable. Pin-outs are described below:

XMP-PCI, VHDCI Connectors, Main Board

Axes 0-1, VHDCI Connector (XMP-PCI)

Connector for Axes 0 and 1 (PCI main board).
Pin | Signal | Signal | Pin
68 | UserIO_A2_Rtn | ESTOP_IN | 34
67 | UserIO_A2 | RESET_IN | 33
66 | UserIO_A1_Rtn | UserIO_A1 | 32
65 | Xcvr1C- | Xcvr1C+ | 31
64 | Xcvr1B- | Xcvr1B+ | 30
63 | Xcvr1A- | Xcvr1A+ | 29
62 | Gnd | Gnd | 28
61 | Amp_En1_Emitter | Amp_En1_Collector | 27
60 | Amp_Flt1_Rtn | Amp_Flt1_IN | 26
59 | Aux_Dac_OUT_1- | Aux_Dac_OUT_1+ | 25
58 | Cmd_Dac_OUT_1- | Cmd_Dac_OUT_1+ | 24
57 | HomeLim1_Rtn | Neg_Lim1_IN | 23
56 | Gnd | Pos_Lim1_IN | 22
55 | 5V_OUT | Home1_IN | 21
54 | Enc1_I- | Enc1_I+ | 20
53 | Enc1_B- | Enc1_B+ | 19
52 | Enc1_A- | Enc1_A+ | 18
51 | Xcvr0C- | Xcvr0C+ | 17
50 | Xcvr0B- | Xcvr0B+ | 16
49 | Xcvr0A- | Xcvr0A+ | 15
48 | UserIO_A0_Rtn | UserIO_A0 | 14
47 | Amp_En0_Emitter | Amp_En0_Collector | 13
46 | Amp_Flt0_Rtn | Amp_Flt0_IN | 12
45 | Aux_Dac_OUT_0- | Aux_Dac_OUT_0+ | 11
44 | Cmd_Dac_OUT_0- | Cmd_Dac_OUT_0+ | 10
43 | HomeLim0_Rtn | Neg_Lim0_IN | 9
42 | Gnd | Pos_Lim0_IN | 8
41 | 5V_OUT | Home0_IN | 7
40 | Enc0_I- | Enc0_I+ | 6
39 | Enc0_B- | Enc0_B+ | 5
38 | Enc0_A- | Enc0_A+ | 4
37 | AGnd | Gnd | 3
36 | Analog_IN_1- | Analog_IN_1+ | 2
35 | Analog_IN_0- | Analog_IN_0+ | 1

Axes 2-3 VHDCI Connector (PCI)

Connector for Axes 2 and 3 (PCI main board).
Pin | Signal | Signal | Pin
1 | EncA_A+ | EncA_A- | 35
2 | EncA_B+ | EncA_B- | 36
3 | EncA_I+ | EncA_I- | 37
4 | Enc2_A+ | Enc2_A- | 38
5 | Enc2_B+ | Enc2_B- | 39
6 | Enc2_I+ | Enc2_I- | 40
7 | Home2_IN | 5V_OUT | 41
8 | Pos_Lim2_IN | Gnd | 42
9 | Neg_Lim2_IN | HomeLim2_Rtn | 43
10 | Cmd_Dac_OUT_2+ | Cmd_Dac_OUT_2- | 44
11 | Aux_Dac_OUT_2+ | Aux_Dac_OUT_2- | 45
12 | Amp_Flt2_IN | Amp_Flt2_Rtn | 46
13 | Amp_En2_Collector | Amp_En2_Emitter | 47
14 | UserIO_A3 | UserIO_A3_Rtn | 48
15 | Xcvr2A+ | Xcvr2A- | 49
16 | Xcvr2B+ | Xcvr2B- | 50
17 | Xcvr2C+ | Xcvr2C- | 51
18 | Enc3_A+ | Enc3_A- | 52
19 | Enc3_B+ | Enc3_B- | 53
20 | Enc3_I+ | Enc3_I- | 54
21 | Home3_IN | 5V_OUT | 55
22 | Pos_Lim3_IN | Gnd | 56
23 | Neg_Lim3_IN | HomeLim3_Rtn | 57
24 | Cmd_Dac_OUT_3+ | Cmd_Dac_OUT_3- | 58
25 | Aux_Dac_OUT_3+ | Aux_Dac_OUT_3- | 59
26 | Amp_Flt3_IN | Amp_Flt3_Rtn | 60
27 | Amp_En3_Collector | Amp_En3_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr3A+ | Xcvr3A- | 63
30 | Xcvr3B+ | Xcvr3B- | 64
31 | Xcvr3C+ | Xcvr3C- | 65
32 | Gnd | AGnd | 66
33 | Analog_IN_2+ | Analog_IN_2- | 67
34 | Analog_IN_3+ | Analog_IN_3- | 68

Axes 4-5 VHDCI Connector (PCI)

Connector for Axes 4 and 5 (PCI main board).
Pin | Signal | Signal | Pin
68 | Analog_IN_5- | Analog_IN_5+ | 34
67 | Analog_IN_4- | Analog_IN_4+ | 33
66 | AGnd | Gnd | 32
65 | Xcvr5C- | Xcvr5C+ | 31
64 | Xcvr5B- | Xcvr5B+ | 30
63 | Xcvr5A- | Xcvr5A+ | 29
62 | Gnd | Gnd | 28
61 | Amp_En5_Emitter | Amp_En5_Collector | 27
60 | Amp_Flt5_Rtn | Amp_Flt5_IN | 26
59 | Aux_Dac_OUT_5- | Aux_Dac_OUT_5+ | 25
58 | Cmd_Dac_OUT_5- | Cmd_Dac_OUT_5+ | 24
57 | HomeLim5_Rtn | Neg_Lim5_IN | 23
56 | Gnd | Pos_Lim5_IN | 22
55 | 5V_OUT | Home5_IN | 21
54 | Enc5_I- | Enc5_I+ | 20
53 | Enc5_B- | Enc5_B+ | 19
52 | Enc5_A- | Enc5_A+ | 18
51 | Xcvr4C- | Xcvr4C+ | 17
50 | Xcvr4B- | Xcvr4B+ | 16
49 | Xcvr4A- | Xcvr4A+ | 15
48 | UserIO_B2_Rtn | UserIO_B2 | 14
47 | Amp_En4_Emitter | Amp_En4_Collector | 13
46 | Amp_Flt4_Rtn | Amp_Flt4_IN | 12
45 | Aux_Dac_OUT_4- | Aux_Dac_OUT_4+ | 11
44 | Cmd_Dac_OUT_4- | Cmd_Dac_OUT_4+ | 10
43 | HomeLim4_Rtn | Neg_Lim4_IN | 9
42 | Gnd | Pos_Lim4_IN | 8
41 | 5V_OUT | Home4_IN | 7
40 | Enc4_I- | Enc4_I+ | 6
39 | Enc4_B- | Enc4_B+ | 5
38 | Enc4_A- | Enc4_A+ | 4
37 | Gnd | Gnd | 3
36 | UserIO_B1_Rtn | UserIO_B1 | 2
35 | UserIO_B0_Rtn | UserIO_B0 | 1

Axes 6-7 VHDCI Connector (PCI)

Connector for Axes 6 and 7 (PCI main board).
Pin | Signal | Signal | Pin
1 | Analog_IN_6+ | Analog_IN_6- | 35
2 | Analog_IN_7+ | Analog_IN_7- | 36
3 | Gnd | AGnd | 37
4 | Enc6_A+ | Enc6_A- | 38
5 | Enc6_B+ | Enc6_B- | 39
6 | Enc6_I+ | Enc6_I- | 40
7 | Home6_IN | 5V_OUT | 41
8 | Pos_Lim6_IN | Gnd | 42
9 | Neg_Lim6_IN | HomeLim6_Rtn | 43
10 | Cmd_Dac_OUT_6+ | Cmd_Dac_OUT_6- | 44
11 | Aux_Dac_OUT_6+ | Aux_Dac_OUT_6- | 45
12 | Amp_Flt6_IN | Amp_Flt6_Rtn | 46
13 | Amp_En6_Collector | Amp_En6_Emitter | 47
14 | UserIO_B3 | UserIO_B3_Rtn | 48
15 | Xcvr6A+ | Xcvr6A- | 49
16 | Xcvr6B+ | Xcvr6B- | 50
17 | Xcvr6C+ | Xcvr6C- | 51
18 | Enc7_A+ | Enc7_A- | 52
19 | Enc7_B+ | Enc7_B- | 53
20 | Enc7_I+ | Enc7_I- | 54
21 | Home7_IN | 5V_OUT | 55
22 | Pos_Lim7_IN | Gnd | 56
23 | Neg_Lim7_IN | HomeLim7_Rtn | 57
24 | Cmd_Dac_OUT_7+ | Cmd_Dac_OUT_7- | 58
25 | Aux_Dac_OUT_7+ | Aux_Dac_OUT_7- | 59
26 | Amp_Flt7_IN | Amp_Flt7_Rtn | 60
27 | Amp_En7_Collector | Amp_En7_Emitter | 61
28 | Gnd | Gnd | 62
29 | Xcvr7A+ | Xcvr7A- | 63
30 | Xcvr7B+ | Xcvr7B- | 64
31 | Xcvr7C+ | Xcvr7C- | 65
32 | EncB_A+ | EncB_A- | 66
33 | EncB_B+ | EncB_B- | 67
34 | EncB_I+ | EncB_I- | 68


Transceiver (XCVR) and User I/O Details

.

Transceiver (XCVR) and User I/O Details

| XCVR Functions: A, B, C, D, E, F |
| User I/O |

This section lists the signal names (at the connector pins) and the Motion Block FPGA functions associated with each.

XCVR Functions

The XCVR signals are used for many different functions. The XMP-PCI and XMP-CPCI each offer three XCVRs (A,B,C) per motor, while the XMP-CPCI-3U offers six XCVRs (A,B,C,D,E,F) per motor. The various XMP boards and XCVR combinations are listed in (See XCVRs for various XMP products below).

XCVRs for various XMP products.
Product | Boards | Motion Blocks | Motors | XCVRs per Motor | XCVRs per Block | XCVRs Total
XMP-PCI | 2 | 4 | 16 | 3 (A-C) | 12 | 48
XMP-CPCI | 2 | 4 | 16 | 3 (A-C) | 12 | 48
XMP-CPCI-3U (non-standard) | 1 | 1 | 4 | 6 (A-F)1 | 23 | 23
XMP-CPCI-3U (standard) | 1 | 1 | 4 | 3 (A-C) | 12 | 12

1. On non-standard XMP-CPCI-3U controller, Axis 2 XCVR D is not connected to rear I/O, giving a total of 23 XCVRs. Standard -3U controller has 12 XCVRs.

These multi-purpose XCVR signals may be configured for several different input or output functions. The available XCVR functions for one motor are detailed below; the XCVRs for all other motors are the same.

Note

an option to invert any output function is also available.

XCVR A Functions

XCVR A functions.
MOTOR 0 XCVR A Functions (connector signal pair XCVR0A+ and XCVR0A-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
STEP | OUTPUT | STEP signal for MOTOR 0 stepper
DIR | OUTPUT | DIRECTION signal for MOTOR 0 stepper
CW | OUTPUT | CLOCKWISE signal for MOTOR 0 stepper
CCW | OUTPUT | COUNTER-CLOCKWISE signal for MOTOR 0 stepper
QUADA | OUTPUT | QUADRATURE A signal for MOTOR 0 stepper
QUADB | OUTPUT | QUADRATURE B signal for MOTOR 0 stepper
INPUT | INPUT | General purpose input -or- To CAPTURE EVENT 0 input lookup table

XCVR B Functions

XCVR B functions.
MOTOR 0 XCVR B Functions (connector signal pair XCVR0B+ and XCVR0B-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
STEP | OUTPUT | STEP signal for MOTOR 0 stepper
DIR | OUTPUT | DIRECTION signal for MOTOR 0 stepper
CW | OUTPUT | CLOCKWISE signal for MOTOR 0 stepper
CCW | OUTPUT | COUNTER-CLOCKWISE signal for MOTOR 0 stepper
QUADA | OUTPUT | QUADRATURE A signal for MOTOR 0 stepper
QUADB | OUTPUT | QUADRATURE B signal for MOTOR 0 stepper
INPUT | INPUT | General purpose input -or- To CAPTURE EVENT 0 input lookup table

XCVR C Functions

XCVR C functions.
MOTOR 0 XCVR C Functions (connector signal pair XCVR0C+ and XCVR0C-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
COMPARE | OUTPUT | Compare output signal for MOTOR 0
INPUT | INPUT | General purpose input -or- To CAPTURE EVENT 0 input lookup table

Note

XCVR D, E and F are available only on the XMP-CPCI-3U board. They are not available on the XMP-PCI or XMP-CPCI.

XCVR D Functions

XCVR D functions.
MOTOR 0 XCVR D Functions (connector signal pair XCVR0D+ and XCVR0D-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
STEP | OUTPUT | STEP signal for MOTOR 0 stepper
DIR | OUTPUT | DIRECTION signal for MOTOR 0 stepper
CW | OUTPUT | CLOCKWISE signal for MOTOR 0 stepper
CCW | OUTPUT | COUNTER-CLOCKWISE signal for MOTOR 0 stepper
QUADA | OUTPUT | QUADRATURE A signal for MOTOR 0 stepper
QUADB | OUTPUT | QUADRATURE B signal for MOTOR 0 stepper
INPUT | INPUT | General purpose input

XCVR E Functions

XCVR E functions.
MOTOR 0 XCVR E Functions (connector signal pair XCVR0E+ and XCVR0E-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
STEP | OUTPUT | STEP signal for MOTOR 0 stepper
DIR | OUTPUT | DIRECTION signal for MOTOR 0 stepper
CW | OUTPUT | CLOCKWISE signal for MOTOR 0 stepper
CCW | OUTPUT | COUNTER-CLOCKWISE signal for MOTOR 0 stepper
QUADA | OUTPUT | QUADRATURE A signal for MOTOR 0 stepper
QUADB | OUTPUT | QUADRATURE B signal for MOTOR 0 stepper

XCVR F Functions

XCVR F functions.
MOTOR 0 XCVR F Functions (connector signal pair XCVR0F+ and XCVR0F-)
Function | Signal Direction | Comments
OUTPUT | OUTPUT | General purpose output
STEP | OUTPUT | STEP signal for MOTOR 0 stepper
DIR | OUTPUT | DIRECTION signal for MOTOR 0 stepper
CW | OUTPUT | CLOCKWISE signal for MOTOR 0 stepper
CCW | OUTPUT | COUNTER-CLOCKWISE signal for MOTOR 0 stepper
QUADA | OUTPUT | QUADRATURE A signal for MOTOR 0 stepper
QUADB | OUTPUT | QUADRATURE B signal for MOTOR 0 stepper

User I/O

There is one USER I/O signal associated with each motor (4 per motion block, 8 for an 8-axis board, 16 for a 16-axis system). These general purpose, opto-isolated signals may be used as either an input or an output. Selecting between input or output is done via the electrical polarity of the external circuit: the polarity of an input circuit disables the output (the output transistor cannot turn on with Vcollector < Vemitter), while the reverse polarity enables the output and disables the input (due to a blocking diode). The circuit design guarantees all components remain within operating limits through the full range of possible values (i.e., with Vin = 24 V, both input and output parts are within spec).

User I/O.
Board | Motion Block | Available functions (choose one) | Signal Names at Connector
Main Board | Motion Block 0 | MOTOR0 USER INPUT OR MOTOR0 USER OUTPUT | USERIO_A0 AND USERIO_AO_RTN
 |  | MOTOR1 USER INPUT OR MOTOR1 USER OUTPUT | USERIO_A1 AND USERIO_A1_RTN
 |  | MOTOR2 USER INPUT OR MOTOR2 USER OUTPUT | USERIO_A2 AND USERIO_A2_RTN
 |  | MOTOR3 USER INPUT OR MOTOR3 USER OUTPUT | USERIO_A3 AND USERIO_A3_RTN
 | Motion Block 2 | MOTOR4 USER INPUT OR MOTOR4 USER OUTPUT | USERIO_B0 AND USERIO_B0_RTN
 |  | MOTOR5 USER INPUT OR MOTOR5 USER OUTPUT | USERIO_B1 AND USERIO_B1_RTN
 |  | MOTOR6 USER INPUT OR MOTOR6 USER OUTPUT | USERIO_B2 AND USERIO_B2_RTN
 |  | MOTOR7 USER INPUT OR MOTOR7 USER OUTPUT | USERIO_B3 AND USERIO_B3_RTN
Expansion Board | Motion Block 1 | MOTOR8 USER INPUT OR MOTOR8 USER OUTPUT | USERIO_C0 AND USERIO_C0_RTN
 |  | MOTOR9 USER INPUT OR MOTOR9 USER OUTPUT | USERIO_C1 AND USERIO_C1_RTN
 |  | MOTOR10 USER INPUT OR MOTOR10 USER OUTPUT | USERIO_C2 AND USERIO_C2_RTN
 |  | MOTOR11 USER INPUT OR MOTOR11 USER OUTPUT | USERIO_C3 AND USERIO_C3_RTN
 | Motion Block 3 | MOTOR12 USER INPUT OR MOTOR12 USER OUTPUT | USERIO_D0 AND USERIO_D0_RTN
 |  | MOTOR13 USER INPUT OR MOTOR13 USER OUTPUT | USERIO_D1 AND USERIO_D1_RTN
 |  | MOTOR14 USER INPUT OR MOTOR14 USER OUTPUT | USERIO_D2 AND USERIO_D2_RTN
 |  | MOTOR15 USER INPUT OR MOTOR15 USER OUTPUT | USERIO_D3 AND USERIO_D3_RTN


XMP Hardware

.

XMP Hardware

Because computer-based motion control systems vary widely, the XMP has been designed to accommodate most common industry hardware. This means providing a variety of platform, porting, form factor, and voltage options.

Platform Options

XMP-series motion controllers are ported to accommodate common industry software platforms, including:

  • Windows95/98
  • Windows2000
  • WindowsNT
  • LynxOS
  • VxWorks
  • VenturCom
  • RTSS
  • QNX
  • PharLap

Form Factor Options

"Form factor" refers to the physical shape and size of an XMP controller and the component(s) it is designed to function with. XMP controllers are available in the following form factors:

  • PCI
  • CPCI-3U
  • CPCI-6U
  • PMC

If your application requires a different form factor, please contact MEI.

Various form factors are shown in the figures below. Four types of I/O connectors are utilized: VHDCI; SERCOS; and, CPCI (rear I/O).

Figure 1-1 Controller form factors: PCI, PMC, and CPCI (-3U and -6U).

XMP Interface Options: Networked and XMP-analog

XMP control systems accommodate two interface categories: networked and XMP-Analog. The types of hardware associated with each category are show here:

Network

  • SERCOS

XMP-analog

  • Analog ± 10 VDC
  • Pulse (Step / Dir)
  • Quadrature encoder
  • Absolute encoder

XMP-SERCOS Systems
SERCOS (SErial Real-time COmmunication System) is the most common type of networked motion control. All data is transmitted over a fiber-optic ring, with each SERCOS device having both a dedicated input and output. At regular intervals, the XMP controller receives a coded data packet from each device in the ring, reporting its current status. The controller then processes the information, and transmits an updated command data packet to each SERCOS device. Typical SERCOS cycle rates vary between 500-1000 samples per second.

XMP-analog Systems
XMP-analog controllers represent a traditional form of motion control, with command and feedback data transmitted via numerous discrete electrical connections.


eXMP-SynqNet Hardware

.

Specifications Hardware and Electrical Requirements Enclosure Dimensions Architecture Features Pinouts Connector Pinouts Power Ethernet RJ-45 SynqNet RJ-45 User I/O CAN Com 2 Com 1 Com 1-4 LEDs Ethernet CAN SynqNet | Documentation Linux Quick Start Guide Board Support Package Guide Linux Release Note VxWorks Quick Start Guide VxWorks Release Note


eXMP Architecture

.

eXMP Architecture

Introduction | Dual-processor Network Architecture | Flexible Development Environment

Introduction

In a standard, bus-based XMP, the DSP and Motion Block subsystems reside in the host PC. As a distributed controller, the eXMP pairs a 366 MHz CPU with the SHARC DSP in a completely autonomous, standalone package.

Since it executes motion programs independent of a host computer, the eXMP is ideal for a variety of high-performance motion control applications, including semiconductor manufacturing, electronic assembly, and robotics.

Figure 1. Low-level communication between the host and eXMP-SynqNet.

Figure 2. High-level communication between the host and eXMP-SynqNet.

Dual-processor Network Architecture

The eXMP controller combines a powerful 366 MHz Intel Celeron microprocessor with a 32-bit floating point SHARC DSP from Analog Devices for autonomous, network-aware motion control. Execution of user programs and communication with other network devices occur on the microprocessor, while the SHARC DSP closes the position loop and handles all real-time servo calculations.

Communication with the higher-level control systems, other network hosts, and popular I/O networks is possible through the on-board 100 MBit Ethernet.

Flexible Development Environment

Running VxWorks, the eXMP provides a highly programmable, highly flexible software development environment. Microsoft Visual Studio or the Wind River Tornado development environment provides a simple way to cross-compile your motion application. The eXMP software provides a full Board Support Package (BSP) that makes it easy to connect to the system across a TCP/IP network.

With full TCP/IP support, MEI’s Windows-based tools can also communicate with the eXMP across a network with the server.exe utility program. Both Motion Console and Motion Scope can be used to configure, tune and troubleshoot problems with the eXMP standalone controller.

User programs can be stored locally in flash memory, or executed in real time across the network from a remote host.


eXMP-Linux Board Support Package Guide

.

eXMP-Linux Board Support Package Guide

eXMP Startup

After BIOS loads, GRUB www.gnu.org/software/grub/ bootloader gets loaded from primary boot partition. Your GRUB selection will specify the kernel image file and the parameters to pass to the kernel. The GRUB boot screen is configured by the /boot/grub/grub.conf file.

As the kernel is loading, messages will print on the serial console. These messages can be viewed at a later time using the 'dmesg' command.

Once the kernel is loaded, the root file system is mounted, and the /etc/iniitab file is executed. This file starts the scripts located in the /etc/init.d/ directory, which include the network address configuration and a script to load the XMP device driver (module).

FTP and Telnet servers are also started (from /etc/inittab). When connecting to the eXMP via a telnet client, no login or password is required. When connecting via an FTP client, an anonymous login supported (login as 'anonymous' or 'ftp') and the password is ignored. After the initialization scripts have been executed, a shell is started on the console.

Software Source: Redhat 8.0

Software for the eXMP was built on a Redhat 8.0 development computer www.redhat.com. Most of the software on the eXMP was taken from the standard distributions on the development computer:

Kernel sources | version 2.4.18-24.8.0
FTP server | wu-ftpd 2.6.2(1)
Telnet server | telnetd
bootloader | GRUB version 0.92

Other Software Used:

BusyBox 0.60.5 (www.busybox.net)
BusyBox combines tiny versions of many common UNIX utilities into a single executable. It provides minimalist replacements for most of the utilities usually found in GNU fileutils, shellutils, etc. The utilities in BusyBox generally have fewer options than their full-featured GNU counterparts. However, the options that are included provide the expected functionality and behave similarly to their GNU counterparts. BusyBox provides a fairly complete POSIX environment for any small or embedded system.

BusyBox was written with size-optimization and limited resources in mind. It is also extremely modular so it is easy to include or exclude commands (or features) at compile time. This makes it easy to customize your embedded systems. To create a working system, simply add /dev, /etc, and a kernel.

sqawnsh

This program is a simple substitute for the "login" program. It simply spawns the shell specified in SPAWN_SHELL. It is used to spawn a shell from the telnet daemon, as follows:

/bin/telnetd -debug 23 -L /bin/spawnsh

Copyright (c) 2001 Simple Network Magic Corporation, dnevil@snmc.com

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

/*
spawnsh -h hostname (for telnetd, etc.)
*/

Files on the Compact Flash (CF)

All partitions are mounted with full read/write access. Be careful! On the 32MB CF card, there is a 4MB boot partition. This gets mounted as /boot. The remaining 28MB is a primary partition which contains the root filesystem. About 20MB of free space remains on these partitions. The directories in this filesystem are described below:

/bin - the bin directory contains user utilities. Most of these come from the BusyBox program.

/boot - the boot directory contains the kernel and the GRUB boot loader files.

/dev - the dev directory contains device files needed in our system. Running the script 'exmp_devs' will create the necessary device files (first-time users only).

/etc - the etc directory contains the necessary configuration files for your system. 'inittab' is the first script that is executed after the kernel is loaded. 'fstab' configures how the CF is mounted. 'init.d/network' contains the network configurations. 'init.d/xmpdriver' loads the XMP device driver (at boot). FTP access files are also found in this location. By default, FTP access is unlimited.

/lib - shared libraries go in this directory. These were copied from the Redhat 8.0 development system.

/proc - this directory is empty. The kernel will put system status files in this directory.

/mei - this directory contains the XMP device driver, and both Debug and Release versions. This device driver is MPI version independent.

/sbin - system utilities go in this directory. These utilities affect the entire system. In our embedded system, they are from the BusyBox.

/usr - the usr directory contains user program files. Most of the files in the usr directory come from the BusyBox package. The ftp and telnet server programs are also located in this directory.

/var - the var directory normally contains log files and other writable directories.

Building the Kernal

Development system: Pentium III 500MHz with Redhat 8.0

Kernel configuration file: exmp.config Copy this file to the /usr/src/linux-2.4 directory.

From a shell in the X environment, type: make xconfig

This will pop up a configuration screen. Select "Load Configuration from file" and type: exmp.config

Then choose "Save Configuration and exit."

Then: make bzImage

Then: make Install

The kernel image "vmlinuz" is now located in the /boot directory. This can be copied to the eXMP CF /boot directory.


CAN Connector

.

CAN Connector

Pin | Signal | Description
1 | (unused) | Reserved
2 | CAN_L | CAN_L bus line dominant low
3 | CAN_GND | CAN Ground
4 | – | Reserved
5 | (CAN_SHLD) | Optional CAN Shield
6 | CAN_GND | CAN Ground
7 | CAN_H | CAN_H bus line dominant high
8 | – | Reserved
9 | CAN_V+ | CAN external supply*
* Used with opto-isolation mode


Com 1 Connector

.

Com 1 Connector

Pin | Signal
1 | CD1
2 | RXD1
3 | TXD1
4 | DTR1
5 | GND1
6 | DSR1
7 | RTS1
8 | CTS1
9 | RIN1


Com 1-4 Connector

.

Com 1-4 Connector

Pin | Signal
1 | GND1
2 | RXD1
3 | GND2
4 | RXD2
5 | GND3

Pin | Signal
6 | RXD3
7 | TXD4
8 | GND4
9 | TXD1
10 | GND5

Pin | Signal
11 | TXD2
12 | GND6
13 | TXD3
14 | GND7
15 | RXD4


Com 2 Connector

.

Com 2 Connector

Pin | Signal
1 | CD2
2 | RXD2
3 | TXD2
4 | DTR2
5 | GND2
6 | DSR2
7 | RTS2
8 | CTS2
9 | RIN2


eXMP Enclosure Dimensions

.

eXMP Enclosure Dimensions


Ethernet RJ-45 Connector

.

Ethernet RJ-45 Connector

Pin | Signal
1 | TD+
2 | TD-
3 | RD+
4 |
5 |
6 | RD-
7 |
8 |


eXMP-SynqNet Features

.

eXMP-SynqNet Features

  • An Intel 366 MHz Celeron CPU running VxWorks®, as well as a high-performance Analog Devices 32-bit floating point SHARC DSP. Use of VxWorks with XMP-Series motion controllers is described in a separate MPI/XMP VxWorks Release Note, available from Motion Engineering; more detailed VxWorks information is available from Wind River Systems, Inc. (http://www.wrs.com).

  • Supports up to 32 axes of SynqNet motor control.

  • Supports CAN interface for integrated I/O programming.

  • Supports SynqNet via 10/100 MBit Ethernet using TCP/IP.

  • Provides all of the XMP’s advanced capabilities, including flexible control algorithms, and support for a variety of position feedback devices.

  • The embedded CPU communicates with the DSP via direct memory reads and writes over a 32-bit PCI bus.

  • Supports applications authored with the MPI or MPX.

  • Supports the use of MEI’s Motion Console and Motion Scope development utilities to configure and debug all axes.


eXMP-SynqNet Controllers: Hardware and Electrical Requirements

.

eXMP-SynqNet Controllers:
Hardware and Electrical Requirements

Environmental

Description | Operating Range
Temperature | 0-50 Deg. C
Humidity | 20-80% RH (no condensation)

Power

Power requirements for the eXMP-SynqNet are shown in the chart below.

Voltage
Operating Range
24VDC +/- 10%
Current
Peak | 2.4 Amps
Typical | 2.0 Amps

Memory

Type | Capacity
RAM | 32MB
Compact Flash | 32MB


User I/O Connector

.

User I/O Connector

Pin | Signal | Signal | Pin
1 | Gnd | Gnd | 26
2 | OPTOA | OPTOA_Rtn | 27
3 | OPTOB | OPTOB_Rtn | 28
4 | OPTOC | OPTOC_Rtn | 29
5 | OPTOD | OPTOD_Rtn | 30
6 | OPTOE | OPTOE_Rtn | 31
7 | OPTOF | OPTOF_Rtn | 32
8 | XESTOP | XESTOP_Rtn | 33
9 | Not Connected | Not Connected | 34
10 | Not Connected | Not Connected | 35
11 | Not Connected | Not Connected | 36
12 | Not Connected | Not Connected | 37
13 | Gnd | Gnd | 38
14 | Reserved | Reserved | 39
15 | Reserved | Reserved | 40
16 | Reserved | Reserved | 41
17 | Reserved | Reserved | 42
18 | Reserved | Reserved | 43
19 | Reserved | Reserved | 44
20 | Reserved | Reserved | 45
21 | Reserved | Reserved | 46
22 | Not Connected | Not Connected | 47
23 | Not Connected | Not Connected | 48
24 | Not Connected | Not Connected | 49
25 | Gnd | Gnd | 50

Cable Accessory

MEI offers the following cable accessory:
C001-0018
CBL-50 VHDCI D-SUB
Interface Cable


CAN LEDs

.

CAN LEDs

The CAN port has two LEDs: CAN1 and CAN2. See the table below for the meaning of each LED and its state.

LED State Table: CAN
CAN1 | CAN2 | Code Executing | State
OFF | OFF | None | No power / No bootloader present
BLINK | ON | Bootloader | No firmware (waiting for firmware)
OFF | ON | Bootloader | Programming firmware
ON | ON | Firmware | No Configuration
ON | OFF |  | Bootloader present with valid firmware
ON | Fast Blinking (0.25/sec) | Firmware | CAN Bus Error
ON | Slow Blinking (1/sec) | Firmware | CAN Operational


Ethernet LEDs

.

Ethernet LEDs

The Ethernet port has two LEDs: Link/Act and 10/100. See the table below for the meaning of each LED and its state.

LED State Table: Ethernet
LED | Meaning | State
Link/Act | Link Activity | ON = link active
 |  | BLINK = network activity
 |  | OFF = link inactive
10/100 | Baud Rate / Network Speed | ON = 100Mb
 |  | OFF = 10Mb


SynqNet LEDs

.

SynqNet LEDs

LED State Table: SynqNet
LED | Port | Meaning | Controlled by | State
LED1 | OUT | Link Activity | PHY | ON = link active
 |  |  |  | OFF = link inactive
LED2 | OUT | Network Activity | MAC | ON = Tx and Rx active (cyclic phase)
 |  |  |  | BLINK = Tx only active (discovery phase)
 |  |  |  | OFF = Idle (shutdown phase)
LED3 | IN | Link Activity | PHY | ON = link active
 |  |  |  | OFF = link inactive
 |  |  |  | ON = Tx
LED4 | IN | Network Activity | MAC | ON = Tx and Rx active (cyclic phase)
 |  |  |  | BLINK = Tx only active (discovery phase)
 |  |  |  | OFF = idle (shutdown phase)


Power Connector

.

Power Connector

Pin | Signal
1 | +24 VDC
2 | 24 VDC Common


SynqNet RJ-45 Connector

.

SynqNet RJ-45 Connector

Pin | In | Out
 | Standard pinout (NIC=MDI) | Crossover pinout (HUB=MDI-X)
1 | Transmit + | Receive +
2 | Transmit - | Receive -
3 | Receive + | Transmit +
4 | UUPI + | UUPI +
5 | UUPI - | UUPI -
6 | Receive - | Transmit -
7 | UUP2 + | UUP2 +
8 | UUP2 - | UUP2 -
- | SHLD | SHLD

UUP1 and UUP2 are "unused pair" 1 and 2. When using a standard CAT5 cable, these pairs are connected to the two unused pairs in the 4 pair (8 wire) cable.

NOTE: Standard CAT5 design practice is to terminate these pairs on the PCB to reduce noise. When using a 2 pair cable, these pins are left unconnected in the cable.

Cable Accessory

MEI offers the following cable accessory:
- C007-0001 (1.2m)
- C007-0002 (3m)
- C007-0003 (10m)


Safety Warnings

.

eXMP-SynqNet QS Guide
Linux

Safety Warnings

During installation, solid electrical contact must be ensured at connectors; otherwise, noise and power problems will develop. (Connections should be verified through inspection and testing.)

Standard safety rules prevail during installation of any hardware. Some are summarized below for the XMP. For more information, refer to local occupational safety regulations and the manufacturer of your motion drive.

Turn Off All Power

Before Installing Equipment Before installing any motion control equipment, including XMP controllers, power should be switched OFF. Unplug all power plugs from their sources of power.

Observe ESD Precautions

To prevent damage to controller and drive electronics due to electrostatic discharge (ESD), service personnel are cautioned to observe proper grounding during handling of components.

Grounding straps should be worn at all times when handling XMP-SynqNetTM electrical components and connection hardware.

Define and Clear a Safety Zone!

During installation and testing of motion control hardware-software, a safety zone should be defined around moving components and kept clear of personnel, hands, fingers and loose hardware. During repowering of the system, motion control components may behave erratically due to misconnected lines, or wrongly configured software settings. Sudden and unexpected moves by components can cause injury, property damage, or even death!

Under NO circumstances, should a motion system be tested or operated while personnel are within the safety zone.

Additionally, beware of flying debris from unsecured hardware operating at high speeds. The use of safety shielding is highly recommended.


Introduction

.

eXMP-SynqNet QS Guide
Linux

Introduction

This Quick Start Guide explains how to configure the eXMP-SynqNet for software start-up and configuration including connection, accessing Linux, and changing network interface parameters. The eXMP-SynqNet has a default image preloaded onto the flash memory. The eXMP-SynqNet will boot this image. The MEI device driver (MEIXMP.o) will automatically load and be ready for executing motion applications at boot-up. The driver can be found in the /MEI/Release directory. Note that no MEI utilities are shipped on the eXMP at the factory. The user will need to copy the necessary files from the MPI release to the eXMP for the specific version.

Fig 1. A full version of the eXMP-SynqNet is shown above containing all the assembly options.

NOTE: Although a fully populated eXMP-SynqNet is shown, the setups should be identical for a "lite" version of the eXMP-SynqNet.

IMPORTANT NOTE
In its default shipping state, the eXMP is configured for an IP address of:

192.1.68.1.74

The user can change his network settings by using telnet to access the eXMP and change the IP address, or connect to the eXMP using a console connection and adapter (see the Configuring for Console Mode section).

IMPORTANT NOTE
The eXMP-SynqNet was designed to allow users to interact with its operating system using a local console and command line via COM1. Therefore, COM1 functions as either a standard COM1 connection or as the console mode connection. Do NOT connect a serial device into the eXMP-SynqNet when COM1 is being used in console mode. COM1 cannot function as a standard COM1 connection and a console mode connection at the same time. The following steps will explain how to set up the eXMP-SynqNet in console mode so that it may be accessed by a network computer for development and testing.


Hardware Setup

.

eXMP-SynqNet QS Guide
Linux

Hardware Setup

A fully populated eXMP-SynqNet is shown below. Depending on the version of eXMP-SynqNet, some connectors may not be present.

Configuring for Console Mode

The following steps will explain how to set up the eXMP-SynqNet in console mode so that it may be accessed by a host computer for local development and testing.

1. The local console must be attached to COM1 via a Null Modem serial cable whose RIN (pin 9) and DTR (pin 4) lines are tied together.

The short between these two pins indicates the presence of a valid console device and is detected during system initialization by the eXMP, thereby enabling the Console output to COM1. This can be done with either an inline adapter or modifications to the Null Modem cable itself.

One example of an inline adapter is the MEI C001-0034 (Cable, Serial, eXMP, DE9).

Although MEI does not sell this adapter, MEI can provide the necessary cable DWG to make your own adapter.


Host-Side Configuration

.

eXMP-SynqNet QS Guide
Linux

Host-Side Configuration

1. Power down Controller.

2. Open HyperTerminal and configure a new connection. Choose a name and icon for this connection.

3. If it is not already connected, connect eXMP COM1/Console to COM1 on the host computer using a NULL serial cable. Console mode is now enabled on the eXMP-SynqNet.

4. After pressing OK, switch Connect using to the appropriate COM port. All other fields should be grayed out after selections have been made.

5. Configure the connection as follows:
  • Bits per second: 9600
  • Data bits: 8
  • Parity: None
  • Stop bits: 2
  • Flow control: None

Click OK. The session is now active. Upon exit, save this session for later use.

6. Power up the eXMP-SynqNet.


Changing Network Interface Parameters

.

eXMP-SynqNet QS Guide
Linux

Changing Network Interface Parameters

1. When you power up the eXMP-SynqNet, the console terminal should display the BIOS information.

2. After the BIOS information is displayed, the GRUB bootloader screen will be displayed. The default boot option will be highlighted and will auto-boot this option after waiting for 5 seconds.

Advanced Linux users can edit the '/boot/grub/grub.conf' to specify a new or different boot option, if necessary.

3. As the default option is booted and the Linux kernel is loaded, the Linux kernel messages will appear in the terminal. The final message will prompt you to press a key to start a shell on the terminal.

4. Once the console is activated, use the vi editor to change the network interface settings in the 'etc/init.d/network' file. This is a small file, and there are BOLD comments marking the location to set the desired IP address, subnet mask, broadcast address, and network routing address. Be sure to write the changes to the file before quitting (:w) and (:q).

5. After saving the valid network interface parameters, reboot the eXMP using the 'reboot' command, or use the 'shutdown' command and then cycle power. After the eXMP completes the Linux boot process, the eXMP should be accessible from another computer on the local area network. The eXMP runs an anonymous FTP server, and a telnet server.

To connect to the eXMP FTP server from a Windows PC, type the following from a Command Prompt (using the new IP address for the eXMP):

ftp 192.168.1.74

Use 'anonymous' or 'ftp' as the login name, the password you choose does not matter.

Full read/write, get/put access is allowed with the eXMP, in every directory. Here is a screenshot of an ftp session:

6. Accessing the eXMP via Telnet provides an eXMP shell with unlimited access. To connect to the eXMP FTP server from a Windows PC, type the following from a Command Prompt (using the new IP address for the eXMP):

telnet 192.168.1.74

The session should look like this:


Using the eXMP-SynqNet Motion Controller

.

eXMP-SynqNet QS Guide
Linux

Using the eXMP-SynqNet Motion Controller

By default, the standard Linux XMP device driver ('/mei/Release/meixmp.o') is loaded during startup. This is an MPI version-independent file.

To execute any XMP utilities or applications, load executable file to the eXMP via ftp, and execute them from a console or telnet shell.

NOTE: As with any UNIX based system, you will need to set the attributes of any file you ftp to the eXMP-SynqNet. This can be done using the chmod command. Please consult your UNIX documentation for more information on using this command.

Congratulations! You have successfully configured the eXMP-SynqNet for console mode using Linux. The eXMP-SynqNet is now ready for testing and development.


eXMP-SynqNet QS Guide: Linux

.

Safety Warnings
Introduction
Hardware Setup
Host-side Configuration
Changing Network Interface Parameters
Using the eXMP-SynqNet Motion Controller


Safety Warnings

.

eXMP-SynqNet QS Guide
VxWorks

Safety Warnings

During installation, solid electrical contact must be ensured at connectors; otherwise, noise and power problems will develop. (Connections should be verified through inspection and testing.)

Standard safety rules prevail during installation of any hardware. Some are summarized below for the XMP. For more information, refer to local occupational safety regulations and the manufacturer of your motion drive.

Turn Off All Power

Before Installing Equipment Before installing any motion control equipment, including XMP controllers, power should be switched OFF. Unplug all power plugs from their sources of power.

Observe ESD Precautions

To prevent damage to controller and drive electronics due to electrostatic discharge (ESD), service personnel are cautioned to observe proper grounding during handling of components.

Grounding straps should be worn at all times when handling XMP-SynqNetTM electrical components and connection hardware.

Define and Clear a Safety Zone!

During installation and testing of motion control hardware-software, a safety zone should be defined around moving components and kept clear of personnel, hands, fingers and loose hardware. During repowering of the system, motion control components may behave erratically due to misconnected lines, or wrongly configured software settings. Sudden and unexpected moves by components can cause injury, property damage, or even death!

Under NO circumstances, should a motion system be tested or operated while personnel are within the safety zone.

Additionally, beware of flying debris from unsecured hardware operating at high speeds. The use of safety shielding is highly recommended.


Introduction

.

eXMP-SynqNet QS Guide
VxWorks

Introduction

This Quick Start Guide explains how to configure the eXMP-SynqNet for software start-up and configuration including connection, accessing VxWorks, and changing boot-line parameters. The eXMP-SynqNet has a default image preloaded into the flash memory. The eXMP-SynqNet will boot this image. The MEI device driver (MEIXMP.o) will automatically load and be ready for executing motion applications at boot-up. The driver can be found in the /MEI/Release directory. Note that no MEI utilities are shipped on the eXMP at the factory. The user will need to copy the necessary files from the MPI release to the eXMP for the specific version.

Fig 1. A full version of the eXMP-SynqNet is shown above containing all the assembly options.

NOTE: Although a fully populated eXMP-SynqNet is shown, the setups should be identical for a "lite" version of the eXMP-SynqNet.

IMPORTANT NOTE
In its default shipping state, the eXMP is configured for an IP address of:

192.1.68.1.74

The user can change his network settings by using telnet to access the eXMP and change the IP address, or connect to the eXMP using a console connection and adapter (See the Configuring for Console Mode section).

IMPORTANT NOTE
The eXMP-SynqNet was designed to allow users to interact with its operating system using a local console and command line via COM1. Therefore, COM1 functions as either a standard COM1 connection or as the console mode connection. Do NOT connect a serial device into the eXMP-SynqNet when COM1 is being used in console mode. COM1 cannot function as a standard COM1 connection and console mode connection at the same time. The following steps will explain how to set up the eXMP-SynqNet in console mode so that it may be accessed by a network computer for development and testing.


Hardware Setup

.

eXMP-SynqNet QS Guide
VxWorks

Hardware Setup

A fully populated eXMP-SynqNet is shown below. Depending on the version of eXMP-SynqNet, some connectors may not be present.

Configuring for Console Mode

The following steps will explain how to set up the eXMP-SynqNet in console mode so that it may be accessed by a host computer for local development and testing. This is mandatory for configuring the Bootline parameters under the VxWorks operating system.

1. The local console must be attached to COM1 via a Null Modem serial cable whose RIN (pin 9) and DTR (pin 4) lines are tied together.

The short between these two pins indicates the presence of a valid console device and is detected during system initialization by the eXMP, thereby enabling the Console output to COM1. This can be done with either an inline adapter or modifications to the Null Modem cable itself. The eXMP-LCF must be placed into console mode to exercise the instructions listed in the Changing Boot Parameters section.


Host-Side Configuration

.

eXMP-SynqNet QS Guide
VxWorks

Host-Side Configuration

1. Power down Controller.

2. Start the FTP server supplied by Tornado on the host computer. An FTP server is only needed if files will be loaded off the host computer.

3. Add a User Profile for the eXMP-SynqNet.
Default setttings:
User Name: target
Password: pw

4. Open HyperTerminal and configure a new connection. Choose a name and icon for this connection.

5. If it is not already connected, connect eXMP COM1/Console to COM1 on the host computer using a NULL serial cable. Console mode is now enabled on the eXMP-SynqNet.

6. After pressing OK, switch "Connect using" to apporpriate COM port. All other fields should be grayed out after selections have been made.

7. Configure the connection as follows:

  • Bits per second: 9600
  • Data bits: 8
  • Parity: None
  • Stop bits: 2
  • Flow control: None

Click OK. The session is now active. (Upon exit, save this session for later use.)

8. Power up the eXMP-SynqNet.


Changing Boot Parameters

.

eXMP-SynqNet QS Guide
VxWorks

Changing Boot Parameters

1. When you power up the eXMP-SynqNet the console terminal should display the BIOS information.

2. In order to change the boot parameters of VxWorks, you need to stop the auto-boot process. At the VxWorks boot screen, press the <Enter> key to stop the auto-boot. There is only one second to do this, so you need to be quick. If you missed it and VxWorks auto-loads, reset the controller and try again.

3. At [VxWorks Boot]: line enter 'c' to change boot parameters. Type in the new values. Any changed values will be saved into the flash and used on next boot up.

boot device | : ata0 | ata is the eXMP's Compact Flash memory. NOTE: to boot from the host use the Ethernet fei device.
processor number | : 0 | Use processor 0
host name | : host | Name of host computer.
file name | : /ata0/vxWorks | Boot VxWorks from Compact Flash memory.
inet on ethernet (e) | : 192.168.1.4 | Set to eXMP IP address.
inet on backplane (b) |  |
host inet (h) | : 192.168.1.2 | Host IP address.
gateway inet (g) | : |
user (u) | : target | Login name for ftp server.
ftp password (pw) (blank = use rsh) | : pw | Login password for ftp server.
flags (f) | : 0x8 | Option flags
target name (tn) | : target | eXMP name
startup script (s) | : | Enter path and startup script if needed.
other (o) | : fei | Enables Ethernet.

4. Once your boot parameters have been entered, type '@' to boot the eXMP-SynqNet.

5. If VxWorks loads correctly, the following screen should appear:

6. Download the mpixmp.o, apputil.o, and server.o files to the target system and then spawn the 'server' command to start the MEI server.

7. Once the server is running, initial system tuning and checkout can be accomplished using the Motion Console and Motion Scope utilities. For more information regarding XMP utilities using server mode, please see the Utilities section on http://support.motioneng.com.

Congratulations! You have successfully configured the eXMP-SynqNet for console mode. The eXMP-SynqNet is now ready for testing and development.


eXMP-SynqNet QS Guide: VxWorks

.

Safety Warnings
Introduction
Hardware Setup
Host-side Configuration
Changing Boot Parameters


DSP Hardware Home

.

DSP Manuals
 Installation Manual
DSP Pro Manual
Application Notes
 OptoCon Release Note

Pinouts
 CPCI
LC
PCI
PCX
STD
V6U
104
104X

Data Sheets
 PCI / DSP
PCX / DSP
VME / DSP
104 /DSP
104X / DSP
LC / DSP
OptoCon


DSP-CPCI: Rear I/O Bus J4

.

DSP-CPCI: Rear I/O Bus J4

For Header Locations:

  • CPCI

Pin | E | D | C | B | A
25 | +5V | Encoder Index(4)– | Encoder Index(4)+ | Encoder Index(3)– | Encoder Index(3)+
24 | Gnd | Encoder B(4)– | Encoder B(4)+ | Encoder A(4)– | Encoder A(4)+
23 | Encoder Index(5)+ | Encoder B(5)– | Encoder B(5)+ | Encoder A(5)– | Encoder A(5)+
22 | Encoder Index(5)– | Encoder B(6)– | Encoder B(6)+ | Encoder A(6))– | Encoder A(6)+
21 | Reserved | Encoder B(7)– | Encoder B(7)+ | Encoder A(7)– | Encoder A(7)+
20 | Reserved | Encoder Index(7)– | Encoder Index(7)+ | Encoder Index(6)– | Encoder Index(6)+
19 | Negative Limit(0) | Positive Limit(0) | Home Input(0) | Amp Fault(0) | Amp Enable(0)
18 | Reserved | In Position(1) | User I/O PC0 | Reserved | In Position(0)
17 | Negative Limit(1) | Positive Limit(1) | Home Input(1) | Amp Fault(1) | Amp Enable(1)
16 | Negative Limit(2) | Positive Limit(2) | Home Input(2) | Amp Fault(2) | Amp Enable(2)
15 | Reserved | In Position(3) | User I/O PCI | Reserved | In Position(2)
14 | Key Area | Key Area | Key Area | Key Area | Key Area
13
12
11 | Negative Limit(3) | Positive Limit(3) | Home Input(3) | Amp Fault(3) | Amp Enable(3)
10 | Negative Limit(4) | Positive Limit(4) | Home Input(5) | Amp Fault(4) | Amp Enable(4)
9 | Reserved | In Position(5) | User I/O PC2 | Reserved | In Position(4)
8 | Negative Limit(5) | Positive Limit(5) | Home Input(5) | Amp Fault(5) | Amp Enable(5)
7 | Negative Limit(6) | Positive Limit(6) | Home Input(6) | Amp Fault(6) | Amp Enable(6)
6 | Reserved | In Position(7) | User I/O PC3 | Reserved | In Position(6)
5 | Negative Limit(7) | Positive Limit(7) | Home Input(7) | Amp Fault(7) | Amp Enable(7)
4 | User I/O PC4 | User I/O PA3 | User I/O PA2 | User I/O PA1 | User I/O PA0
3 | User I/O PC5 | User I/O PA7 | User I/O PA6 | User I/O PA5 | User I/O PA4
2 | User I/O PC6 or DSP Interrupt | User I/O PB3 | User I/O PB2 | User I/O PB1 | User I/O PB0
1 | User I/O PC7 or PC Interrupt | User I/O PB7 | User I/O PB6 | User I/O PB5 | User I/O PB4
Pin | E | D | C | B | A


DSP-CPCI: Rear I/O Bus J5

.

DSP-CPCI: Rear I/O Bus J5

For Header Locations:

  • CPCI

* - Column F is the gold-plated grounding strip on the outside edge of the shroud. F1-F22 are grounds.

Pin | E | D | C | B | A
22 | Analog in 3 | Analog in 2 | Analog Gnd | Analog in 1 | Analog in 0
21 | Analog in 7 | Analog in 6 | Analog Gnd | Analog in 5 | Analog in 4
20 | Reserved | Reserved | –12V | Analog Out Ref(0) | +/- 10V Analog Out(0)
19 | Reserved | Reserved | Analog Gnd | Analog Out Ref(1) | +/- 10V Analog Out(1)
18 | Reserved | Reserved | +12V | Analog Out Ref(2) | +/- 10V Analog Out(2)
17 | Reserved | Reserved | Analog Gnd | Analog Out Ref(3) | +/- 10V Analog Out(3)
16 | Reserved | Reserved | Reserved | Analog Out Ref(4) | +/- 10V Analog Out(4)
15 | Reserved | Reserved | Reserved | Analog Out Ref(5) | +/- 10V Analog Out(5)
14 | Reserved | Reserved | +5V | Analog Out Ref(6) | +/- 10V Analog Out(6)
13 | Reserved | Reserved | Gnd | Analog Out Ref(7) | +/- 10V Analog Out(7)
12 | Out 2 | Out 1 | Out 0 | Gate 0 | Clock 0
11 | Direction(7)+ | Step Pulse(0)– | Step Pulse(0)+ | Direction(0)– | Direction(0)+
10 | Direction(7)– | Step Pulse(1)– | Step Pulse(1)+ | Direction(1)– | Direction(1)+
9 | Step Pulse(7)+ | Step Pulse(2)– | Step Pulse(2)+ | Direction(2)– | Direction(2)+
8 | Step Pulse(7)– | Step Pulse(3)– | Step Pulse(3)+ | Direction(3)– | Direction(3)+
7 | Reserved | Step Pulse(4)– | Step Pulse(4)+ | Direction(4)– | Direction(4)+
6 | Encoder Index(0)+ | Step Pulse(5)– | Step Pulse(5)+ | Direction(5)– | Direction(5)+
5 | Encoder Index(0)– | Step Pulse(6)– | Step Pulse(6)+ | Direction(6)– | Direction(6)+
4 | Encoder Index(1)+ | Encoder B(0)– | Encoder B(0)+ | Encoder A(0)– | Encoder A(0)+
3 | Encoder Index(1)– | Encoder B(1)– | Encoder B(1)+ | Encoder A(1)– | Encoder A(1)+
2 | Encoder Index(2)+ | Encoder B(2)– | Encoder B(2)+ | Encoder A(2)– | Encoder A(2)+
1 | Encoder Index(2)– | Encoder B(3)– | Encoder B(3)+ | Encoder A(3)– | Encoder A(3)+
Pin | E | D | C | B | A


DSP Dedicated I/O Axes 0-3: P2

.

DSP Dedicated I/O Axes 0-3: P2

For Header Locations:

  • PCX
  • CPCI
  • STD
  • 104X
  • V6U

There are 6 Dedicated I/O signals for each axis of the controller: 4 inputs and 2 outputs. All even pins are grounds.

Inputs | Positive Limit Negative Limit Home Amplifier Fault
Outputs | In Position Amplifier Enable

Dedicated I/O Connections: 50-pin box headers
Pin | Signal | P2 Axis
1 | In-Position Out | 3
3 | Amp Enable Out | 3
5 | In-Position Out | 2
7 | Amp Enable Out | 2
9 | In-Position Out | 1
11 | Amp Enable Out | 1
13 | In-Position Out | 0
15 | Amp Enable Out | 0
17 | Amp Fault Input | 3
19 | Home Input | 3
21 | NEG Limit Input | 3
23 | POS Limit Input | 3
25 | Amp Fault Input | 2
27 | Home Input | 2
29 | NEG Limit Input | 2
31 | POS Limit Input | 2
33 | Amp Fault Input | 1
35 | Home Input | 1
37 | NEG Limit Input | 1
39 | POS Limit Input | 1
41 | Amp Fault Input | 0
43 | Home Input | 0
45 | NEG Limit Input | 0
47 | POS Limit Input | 0
49 | + 5V |

NOTE: All even pins are grounds.


DSP Dedicated I/O Axes 4-7: P3

.

DSP Dedicated I/O Axes 4-7: P3

For Header Locations:

  • PCX
  • CPCI
  • STD
  • 104X
  • V6U

There are 6 Dedicated I/O signals for each axis of the controller: 4 inputs and 2 outputs. All even pins are grounds.

Inputs | Positive Limit Negative Limit Home Amplifier Fault
Outputs | In Position Amplifier Enable

The even-numbered pins are grounds, and pin 49 is +5V.

Dedicated I/O Connections: 50-pin box headers
Pin | Signal | P3 Axis
1 | In-Position Out | 7
3 | Amp Enable Out | 7
5 | In-Position Out | 6
7 | Amp Enable Out | 6
9 | In-Position Out | 5
11 | Amp Enable Out | 5
13 | In-Position Out | 4
15 | Amp Enable Out | 4
17 | Amp Fault Input | 7
19 | Home Input | 7
21 | NEG Limit Input | 7
23 | POS Limit Input | 7
25 | Amp Fault Input | 6
27 | Home Input | 6
29 | NEG Limit Input | 6
31 | POS Limit Input | 6
33 | Amp Fault Input | 5
35 | Home Input | 5
37 | NEG Limit Input | 5
39 | POS Limit Input | 5
41 | Amp Fault Input | 4
43 | Home Input | 4
45 | NEG Limit Input | 4
47 | POS Limit Input | 4
49 | + 5V |

NOTE: All even pins are grounds.


DSP-104

.

DSP-104

Pinouts
User I/O and Dedicated I/O Axes 0-3


DSP-CPCI

.

DSP-CPCI

Pinouts
User I/O

Dedicated I/O Axes 0-3
Dedicated I/O Axes 4-7

Motor Axes 0-7

Analog Inputs (8)

Rear I/O J4
Rear I/O J5


DSP-LC

.

DSP-LC

Pinouts
User I/O and Dedicated I/O Axes 0-3


DSP-PCI

.

DSP-PCI

Pinouts
Motor Axes 0-4

User I/O


DSP-PCX

.

DSP-PCX

Pinouts
User I/O

Dedicated I/O Axes 0-3
Dedicated I/O Axes 4-7

Motor Axes 0-7

Analog Inputs (8)


DSP-STD and DSP-104X

.

DSP-STD
DSP-104X

Pinouts
User I/O

Dedicated I/O Axes 0-3
Dedicated I/O Axes 4-7

Motor Axes 0-7

Analog Inputs (8)


DSP-V6U

.

DSP-V6U

Pinouts
User I/O

Dedicated I/O Axes 0-3
Dedicated I/O Axes 4-7

Motor Axes 0-7

Analog Inputs (8)


DSP Pinouts: User I/O and Motor Axes 0-3

.

DSP Pinouts: User I/O and Motor Axes 0-3

Top Cable: (red)
User I/O
Motor Axes 0-1

Bottom Cable: (blue)
User I/O
Motor Axes 2-3

For Header Locations:

  • 104
  • LC

Motor Axes Connections— Top Cable: User I/O and Motor Axes 0-1 (red) 50-pins
Pin | Signal
1 | +5V
3 | Encoder A(0) +
5 | Encoder A(0) –
7 | Encoder B(0) +
9 | Encoder B(0) –
11 | Encoder Index(0) +
13 | Encoder Index(0) –
15 | +/– 10V Analog Out(0)
17 | Gnd
19 | Step Pulse(0)+
21 | Step Pulse(0) –
23 | Direction(0)+
25 | Direction(0) –
27 | Positive Limit(0)
29 | Positive Limit(0)
31 | Home Input(0)
33 | Amp Fault(0)
35 | Amp Enable(0)
37 | In Position(0)
39 | User I/O PA0
41 | User I/O PA1
43 | User I/O PA2
45 | User I/O PC0
47 | User I/O PC1
49 | Gnd

Signal | Pin
+5V | 2
Encoder A(1) + | 4
Encoder A(1) – | 6
Encoder B(1) + | 8
Encoder B(1) – | 10
Encoder Index(1) + | 12
Encoder Index(1) – | 14
+/– 10V Analog Out(1) | 16
Gnd | 18
Step Pulse(1)+ | 20
Step Pulse(1) – | 22
Direction(1)+ | 24
Direction(1) – | 26
Positive Limit(1) | 28
Positive Limit(1) | 30
Home Input(1) | 32
Amp Fault(1) | 34
Amp Enable(1) | 36
In Position(1) | 38
User I/O PA3 | 40
User I/O PA4 | 42
User I/O PA5 | 44
User I/O PC2 | 46
User I/O PC3 | 48
Gnd | 50

Motor Axes Connections— Bottom Cable: User I/O and Motor Axes 2-3 (blue) 50-pins
Pin | Signal
1 | +5V
3 | Encoder A(2) +
5 | Encoder A(2) –
7 | Encoder B(2) +
9 | Encoder B(2) –
11 | Encoder Index(2) +
13 | Encoder Index(2) –
15 | +/– 10V Analog Out(2)
17 | Gnd
19 | Step Pulse(2)+
21 | Step Pulse(2) –
23 | Direction(2)+
25 | Direction(2) –
27 | Positive Limit(2)
29 | Positive Limit(2)
31 | Home Input(2)
33 | Amp Fault(2)
35 | Amp Enable(2)
37 | In Position(2)
39 | User I/O PB0
41 | User I/O PB1
43 | User I/O PB2
45 | User I/O PC4
47 | User I/O PC5
49 | Gnd

Signal | Pin
+5V | 2
Encoder A(3) + | 4
Encoder A(3) – | 6
Encoder B(3) + | 8
Encoder B(3) – | 10
Encoder Index(3) + | 12
Encoder Index(3) – | 14
+/– 10V Analog Out(3) | 16
Gnd | 18
Step Pulse(3)+ | 20
Step Pulse(3) – | 22
Direction(3)+ | 24
Direction(3) – | 26
Positive Limit(3) | 28
Positive Limit(3) | 30
Home Input(3) | 32
Amp Fault(3) | 34
Amp Enable(3) | 36
In Position(3) | 38
User I/O PB3 | 40
User I/O PB4 | 42
User I/O PB5 | 44
User I/O PC6 or DSP Interrrupt | 46
User I/O PC7 or PC Interrrupt | 48
Gnd | 50


DSP Analog Inputs: P8

.

DSP Analog Inputs: P8

For Header Locations:

  • PCX
  • CPCI
  • STD
  • 104X
  • V6U

Two motors of the same type can be connected to each motor header.

Analog Input Connections: 20-pin box headers
Pin | Signal | Signal | Pin
1 | Gnd | Analog Gnd | 2
3 | Clock 0 | Analog in 0 | 4
5 | –12V | Analog in 1 | 6
7 | +12V | Analog in 2 | 8
9 | +5V | Analog in 3 | 10
11 | Gate 0 | Analog in 4 | 12
13 | Out 0 | Analog in 5 | 14
15 | Out 1 | Analog in 6 | 16
17 | Out 2 | Analog in 7 | 18
19 | Gnd | Analog Gnd | 20


DSP Pinouts: Motor Axes 0-3

.

DSP Pinouts: Motor Axes 0-3

For Header Locations:

  • PCI

The Dedicated I/O connectors for the DSP-PCI are used with the STC-136.

Motor Axes Connections— Motor Axes 0-1, 68-pins

Pin | Signal
1 | Analog 0+
2 | Analog 1+
3 | Gnd
4 | Enc0_A+
5 | Enc0_B+
6 | Enc0_I+
7 | Home0_IN
8 | Pos_Lim0_IN
9 | Neg_Lim0_IN
10 | Command_0+
11 | Reserved
12 | Amp_Flt0_In
13 | Amp_En0_C
14 | Reserved
15 | Step0+
16 | Dir0+
17 | In_Pos0+
18 | Enc1_A+
19 | Enc1_B+
20 | Enc1_I+
21 | Home1_IN
22 | Pos_Lim1_IN
23 | Neg_Lim1_IN
24 | Command_1+
25 | Reserved
26 | Amp_Flt1_IN
27 | Amp_En1_C
28 | Gnd
29 | Step1+
30 | Dir1+
31 | In_Pos1+
32 | Gnd
33 | Analog_4+
34 | Analog_5+

Signal | Pin
AGnd | 35
AGnd | 36
Gnd | 37
Enc0_A– | 38
Enc0_B– | 39
Enc0_I– | 40
5V_OUT | 41
Gnd_OUT | 42
Mech0_Rtn | 43
Command_0– | 44
Reserved | 45
Amp_Flt0_Rtn | 46
Amp_En0_E | 47
Reserved | 48
Step0- | 49
Dir0- | 50
In_Pos0– | 51
Enc1_A– | 52
Enc1_B– | 53
Enc1_I– | 54
5V_OUT | 55
Gnd_OUT | 56
Mech1_Rtn | 57
Command_1– | 58
Reserved | 59
Amp_Flt1_Rtn | 60
Amp_En1_E | 61
Gnd | 62
Step1– | 63
Dir1– | 64
In_Pos1– | 65
Gnd | 66
AGnd | 67
AGnd | 68

Motor Axes Connections— Motor Axes 2-3, 68-pins

Pin | Signal
1 | Analog 6+
2 | Analog 7+
3 | Gnd
4 | Enc2_A+
5 | Enc2_B+
6 | Enc2_I+
7 | Home2_IN
8 | Pos_Lim2_IN
9 | Neg_Lim2_IN
10 | Command_2+
11 | Reserved
12 | Amp_Flt2_In
13 | Amp_En2_C
14 | Reserved
15 | Step2+
16 | Dir2+
17 | In_Pos2+
18 | Enc3_A+
19 | Enc3_B+
20 | Enc3_I+
21 | Home3_IN
22 | Pos_Lim3_IN
23 | Neg_Lim3_IN
24 | Command_3+
25 | Reserved
26 | Amp_Flt3_IN
27 | Amp_En3_C
28 | Gnd
29 | Step3+
30 | Dir3+
31 | In_Pos3+
32 | Gnd
33 | Analog_2+
34 | Analog_3+

Signal | Pin
AGnd | 35
AGnd | 36
Gnd | 37
Enc2_A– | 38
Enc2_B– | 39
Enc2_I– | 40
5V_OUT | 41
Gnd_OUT | 42
Mech2_Rtn | 43
Command_2– | 44
Reserved | 45
Amp_Flt2_Rtn | 46
Amp_En2_E | 47
Reserved | 48
Step2- | 49
Dir2- | 50
In_Pos2– | 51
Enc3_A– | 52
Enc3_B– | 53
Enc3_I– | 54
5V_OUT | 55
Gnd_OUT | 56
Mech3_Rtn | 57
Command_3– | 58
Reserved | 59
Amp_Flt3_Rtn | 60
Amp_En3_E | 61
Gnd | 62
Step3– | 63
Dir3– | 64
In_Pos3– | 65
Gnd | 66
AGnd | 67
AGnd | 68


DSP Pinouts: Motor Axes 0-7

.

DSP Pinouts: Motor Axes 0-7

Motor Axes 0, 1: P6
Motor Axes 2, 3: P7
Motor Axes 4, 5: P4
Motor Axes 6, 7: P5

For Header Locations:

  • PCX
  • CPCI
  • STD
  • 104X
  • V6U

Two motors of the same type can be connected to each motor header.
1st Axis: Pins 1-13
2nd Axis: Pins 14-26

Motor Axes Connections: 26-pin box headers

1st Axis
Pin | Signal | Signal | Pin
1 | Gnd | 5V | 2
3 | Encoder A + | Encoder A – | 4
5 | Encoder B + | Encoder B – | 6
7 | Encoder Index + | Encoder Index – | 8
9 | +/- 10V Analog Out | Step Pulse + | 10
11 | Step Pulse – | Step Direction + | 12
13 | Step Direction – |  |

2nd Axis
Pin | Signal | Signal | Pin
 |  | GND | 14
15 | 5V | Encoder A + | 16
17 | Encoder A – | Encoder B + | 18
19 | Encoder B – | Encoder Index + | 20
21 | Encoder Index – | +/- 10V Analog Out | 22
23 | Step Pulse + | Step Pulse – | 24
25 | Step Direction + | Step Direction – | 26


DSP User I/O: P1

.

DSP User I/O: P1

For Header Locations:

  • PCX
  • CPCI
  • STD
  • 104X
  • V6U

The PCX, CPCI, STD, 104X, and V6U Series Controllers support 24 or 44-bits of general purpose I/O. These signals can be configured as inputs or outputs in groups of 8.

Dedicated I/O for axes 4-7 is available for User I/O on PCX, CPCI, STD, and V6U controllers with four or less axes. If an 8-bit port with Home sensor signals is configured as an output port, only 6 of the 8 signals can be used. For the PCX, CPCI, STD, and V6U the Home Sensor inputs are not available for User I/O. The following diagram shows the configuration of the 72 I/O lines for the PCX, CPCI, STD, and V6U.

Each I/O Port (A,B,C) can be defined as inputs or outputs.

User I/O Connections: 50-pin Opto-22 compatible header
Pin | Signal
1 | I/O Line C-7 or PC Interrupt
3 | I/O Line C-6 or DSP Interrupt
5 | I/O Line C-5
7 | I/O Line C-4
9 | I/O Line C-3
11 | I/O Line C-2
13 | I/O Line C-1
15 | I/O Line C-0
17 | I/O Line B-7
19 | I/O Line B-6
21 | I/O Line B-5
23 | I/O Line B-4
25 | I/O Line B-3
27 | I/O Line B-2
29 | I/O Line B-1
31 | I/O Line B-0
33 | I/O Line A-7
35 | I/O Line A-6
37 | I/O Line A-5
39 | I/O Line A-4
41 | I/O Line A-3
43 | I/O Line A-2
45 | I/O Line A-1
47 | I/O Line A-0
49 | + 5V

NOTE: All even pins are grounds.


DSP User I/O

.

DSP User I/O

For Header Locations:

  • PCI

The User I/O connector for the DSP-PCI is used with the STC-D50.

Motor Axes Connections— Motor Axes 0-1, 68-pins

Pin | Signal
1 | UserIO_A0
2 | UserIO_A1
3 | UserIO_A2
4 | UserIO_A3
5 | UserIO_A4
6 | UserIO_A5
7 | UserIO_A6
8 | UserIO_A7
9 | UserIO_B0
10 | UserIO_B1
11 | UserIO_B2
12 | UserIO_B3
13 | UserIO_B4
14 | UserIO_B5
15 | UserIO_B6
16 | UserIO_B7
17 | UserIO_C0
18 | UserIO_C1
19 | UserIO_C2
20 | UserIO_C3
21 | UserIO_C4
22 | UserIO_C5
23 | UserIO_C6
24 | UserIO_C7
25 | 5V

Signal | Pin
UserIO_A0_Rtn | 26
UserIO_A1_Rtn | 27
UserIO_A2_Rtn | 28
UserIO_A3_Rtn | 29
UserIO_A4_Rtn | 30
UserIO_A5_Rtn | 31
UserIO_A6_Rtn | 32
UserIO_A7_Rtn | 33
UserIO_B0_Rtn | 34
UserIO_B1_Rtn | 35
UserIO_B2_Rtn | 36
UserIO_B3_Rtn | 37
UserIO_B4_Rtn | 38
UserIO_B5_Rtn | 39
UserIO_B6_Rtn | 40
UserIO_B7_Rtn | 41
UserIO_C0_Rtn | 42
UserIO_C1_Rtn | 43
UserIO_C2_Rtn | 44
UserIO_C3_Rtn | 45
UserIO_C4_Rtn | 46
UserIO_C5_Rtn | 47
UserIO_C6_Rtn | 48
UserIO_C7_Rtn | 49
Gnd | 50

Cable Accessory

MEI offers the following cable accessory: C001-0018


MPI Sample Applications Home

.


ampFlt1.c -- Configure the amp fault input

.

ampFlt1.c -- Configure the amp fault input.
/* ampflt1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure the amp fault input.

The program will configure the amp fault input for a motor.

  A motor's amp fault input has four items to configure:

  1) Event Action   (any MPIAction such as MPIActionE_STOP)
  2) Event Trigger  (a trigger polarity, active HIGH or LOW)
  3) Direction Flag (TRUE will cause the command direction of motion to
                     qualify the events,    FALSE will ignore direction,
                     based solely on the limit input state)
  4) Duration       (requires the limit condition to exist for
                     a programmable number of seconds before an
                     event will occur)

The duration configuration provides filtering of the amp fault input by requiring the input to
remain active for the defined duration.  This will effectively keep the amp fault from activating prematurely
due to electrical noise on the amp fault input.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define  ACTIVE_HIGH    (1)
#define  ACTIVE_LOW     (0)

#if defined(ARG_MAIN_RENAME)
#define main    ampflt1Main

argMainRENAME(main, ampflt1)
#endif

/* Command line arguments and defaults */
long            axisNumber      = 0;
long            motionNumber    = 0;
long            motorNumber     = 0;
float           ampfaultduration= (float)5.0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-motor",   ArgTypeLONG,    &motorNumber,   },
    {   "-duration",ArgTypeFLOAT,   &ampfaultduration,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;    /* motion controller handle */
    MPIAxis         axis;       /* axis handle(s) */
    MPIMotor        motor;      /* motor handle(s) */
    MPIMotion       motion;     /* motion supervisor handle */
    MPINotify       notify;     /* event notification handle */
    MPIEventMgr     eventMgr;   /* event manager handle */

    Service service;

    MEIXmpData  *firmware;

    MPIMotorEventConfig eventConfig;

    long    messageCount;

    long    returnValue;    /* return value from library */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIEventMask        eventMask;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motorNumber  >= MEIXmpMAX_Motors) ||
        (ampfaultduration  < 0)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-duration # (>0)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle. */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Get pointer to XMP firmware */
    returnValue =
        mpiControlMemory(control,
                         (void**)&firmware,
                         (void**)NULL);
    msgCHECK(returnValue);

    /* Create axis object using axisNumber on controller */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motor object using axisNumber on controller */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create motion supervisor object using MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    /* Get configuration for ampfault event */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               MPIEventTypeAMP_FAULT,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Event Action, configure to ABORT on Amp Fault Input */
    eventConfig.action = MPIActionABORT;

    /* Event trigger, set trigger level to Active Low */
    eventConfig.trigger.polarity = ACTIVE_LOW;

    /* Direction Flag, do not use commanded velocity direction as a trigger qualifier */
    eventConfig.direction = FALSE;

    /* Duration, wait ampfaultduration seconds before triggering */
    eventConfig.duration = ampfaultduration;

    returnValue =
        mpiMotorEventConfigSet(motor,
                               MPIEventTypeAMP_FAULT,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    meiPlatformConsole("amp fault duration and polarity configured: wait for events.\n");

    messageCount = 0;

    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus  eventStatus;

        long    motorNumber;

        /* Wait for event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        messageCount++;

        motorNumber = ((MEIEventStatusInfo *)eventStatus.info)->type.number;

        printf("Event! (%d) Type = %d \n",
               messageCount,
               eventStatus.type);

        switch (eventStatus.type) {
            case MPIEventTypeAMP_FAULT: {

                printf("Amp Fault has occurred on motor # %d\n",motorNumber);
                printf("Resetting...\n");

                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                meiASSERT(returnValue == MPIMessageOK);

                break;
            }
            default: {
                break;
            }
        }
    }

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


anticol1.c -- Program Sequencer aborts axes prior to a collision

.

anticol1.c -- Program Sequencer aborts axes prior to a collision (anti-collision protection)
/* anticol1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Program Sequencer aborts axes prior to a collision (anti-collision protection)

This sample program provides anti-collision protection for two axes that move
 along the same physical space.  The program creates a program sequencer that
 will continually monitor the relative actual positions of two axes.  When the
 relative positions get closer than a defined tolerance (defined at the top of
 the program as DIFFERENCE_TOLEARNCE) the axes will be aborted by the program
 sequencer.

The XMP program sequencer controls the execution of a single command or a
 series of commands on the XMP controller.  The program sequencer provides the
 ability to execute programs directly on the XMP controller without host
 intervention.  Examples of individual commands that can be executed by the
 program sequencer are motion, looping, conditional branching, computation,
 reading and writing of memory, time delays, waiting for conditions, setting
 inputs/outputs, and generation of events.  This rich command set provides
 capability similar to, and beyond, that provided by Programmable Logic
 Controller (PLC) programs.

From anticol1c.c (8/1/1999)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    anticol1Main

argMainRENAME(main, anticol1)
#endif

#define AXIS_COUNT              (2)
#define DIFFERENCE_TOLERANCE    (7000)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
long            sequenceNumber  = 0;
long            differenceTolerance = DIFFERENCE_TOLERANCE;

Arg argList[] = {
    {   "-axis",        ArgTypeLONG,    &axisNumber[0],         },
    {   "-motion",      ArgTypeLONG,    &motionNumber,          },
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,        },
    {   "-tolerance",   ArgTypeLONG,    &differenceTolerance,   },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

                        /* COMPUTE + BRANCH + BRANCH + ABORT = 4 */
MPICommand  CommandTable[4];
#define COMMAND_COUNT   (sizeof(CommandTable) / sizeof(MPICommand))

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIMotion   motion;             /* motion handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handles */
    MPISequence sequence;           /* sequence handle */

    MPICommandParams    commandParams;  /* command parameters */

    long    returnValue;    /* return value from library */

    long    commandIndex;   /* CommandTable[] index */
    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEIXmpData          *firmware;
    MEIPlatform         platform;   /* platform handle */
    MEIXmpBufferData    *xmpBufferData;
    long                *addressActPos1;
    long                *addressActPos2;
    long                address;
    long                *allocPointer;
    long                difference;
    long                *addressDifferenceStored;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]  > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber   >= MEIXmpMAX_MSs) ||
        (sequenceNumber >= MEIXmpMAX_PSs) ||
        (differenceTolerance < 0)){

        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[-tolerance # ( larger than 0)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_PSs - 1);

        exit(MPIMessageARG_INVALID);
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize motion controller */
    returnValue = mpiControlInit(control);
    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiControlInit() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(1);
    }

    /* Get pointer to XMP firmware */
    returnValue =
        mpiControlMemory(control,
                         &firmware,
                         &xmpBufferData);
    msgCHECK(returnValue);

    platform =
        meiControlPlatform(control);
    msgCHECK(meiPlatformValidate(platform));

    /*Pointer into xmp memory space.  Pointer to the user buffer  */
    returnValue =
        mpiControlMemoryAlloc(control,
                              MPIControlMemoryTypeUSER,
                              sizeof(long),
                              &allocPointer);
    msgCHECK(returnValue);

    returnValue =
            meiPlatformMemoryToFirmware(platform,
                                        allocPointer,
                                        (void **)&address);
    msgCHECK(returnValue);

    meiPlatformConsole("address of allocPointer (user buffer) is 0x%x\n",address);

    /* Create motion object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create axis object for axis #0 */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);   /* axis #0 */
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create axis object for axis #1 */
    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);   /* axis #1 */
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion axis list */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Write the axis list to the motion supervisor on the board */
    returnValue =
        mpiMotionAction(motion,
                        MEIActionMAP);

    msgCHECK(returnValue);

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          -1);
    msgCHECK(mpiSequenceValidate(sequence));

    /* CommandTable[commandIndex] */
    commandIndex = 0;

    /* Get the address for the first axis's actual position register */
    addressActPos1 = &firmware->Axis[axisNumber[0]].ActualPosition;

    /* Get the address for the second axis's actual position register */
    addressActPos2 = &firmware->Axis[axisNumber[1]].ActualPosition;

    returnValue =
            meiPlatformMemoryToFirmware(platform,
                                        addressActPos1,
                                        (void **)&address);
    msgCHECK(returnValue);

    meiPlatformConsole("addressActPos1 is 0x%x\n",address);

    returnValue =
            meiPlatformMemoryToFirmware(platform,
                                        addressActPos2,
                                        (void **)&address);
    msgCHECK(returnValue);
    meiPlatformConsole("addressActPos2 is 0x%x\n",address);

    /* 1st. Command  */
    /* Take the difference of the two actual positions and store them in the user buffer */
    addressDifferenceStored = allocPointer;

    commandParams.compute.dst.l         = addressDifferenceStored;
    commandParams.compute.expr.address.l    = addressActPos1;
    commandParams.compute.expr.oper     = MPICommandOperatorSUBTRACT;
    commandParams.compute.expr.by.ref.l = addressActPos2;

    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeCOMPUTE_REF,
                         &commandParams,
                         "First");
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /*  2nd Command */
    /*  Compare the position differences to the position diference tolerance */
    /*  Perform abort if test is true */

    commandParams.branch.label              = "ABORT";
    commandParams.branch.expr.address.l     = addressDifferenceStored;
    commandParams.branch.expr.oper          = MPICommandOperatorLESS;
    commandParams.branch.expr.by.value.l    = differenceTolerance;

    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* 3rd. Command */
    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* 4th. command */
    /* Abort the axes that are part of motion supervisor motion */

    commandParams.motion.motionCommand  = MPICommandMotionABORT;
    commandParams.motion.motion     = motion;

    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeMOTION,
                         &commandParams,
                         "ABORT");
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Create sequence command list */
    returnValue =
        mpiSequenceCommandListSet(sequence,
                                  commandIndex,
                                  CommandTable);
    msgCHECK(returnValue);

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);

    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiSequenceStart() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(2);
    }

    meiPlatformConsole("Press any key to stop sequence\n");
    meiPlatformKey(MPIWaitFOREVER);

    returnValue =
            mpiControlMemoryGet(control,
                                &difference,
                                allocPointer,
                                sizeof(long));
    msgCHECK(returnValue);

    meiPlatformConsole("Axis Position difference is %ld\n",difference);

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue =
        mpiControlMemoryFree(control,
                             MPIControlMemoryTypeUSER,
                             sizeof(long),
                             allocPointer);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


can1.c -- Toggle digital outputs on a CAN node

.

can1.c -- Toggle digital outputs on a CAN node
/* can1.c */

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

/*

:Toggle digital outputs on a CAN node

This sample application describes how to access a CAN node and toggle its
 digital outputs.

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.

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

#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    adc1Main
argMainRENAME(main, adc1)
#endif

/* Modify this macro to specify a node with digital outputs. */
#define OUTPUT_NODE_NUMBER  (11)

/* Modify this to specify the number of digital output channels. */
#define CHANNEL_COUNT       (16)

/* Modify this to specify the CAN network number */
#define CAN_NETWORK_NUMBER  (0) /* Currently, only one CAN network is supported */

/* 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,
                 MEICan             *can,
                 long               canNumber)
{
    long returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Create and validate a handle to the CAN object. */
    *can =
        meiCanCreate(*control, canNumber);
    msgCHECK(meiCanValidate(*can));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
                    MEICan     *can)
{
    long    returnValue;

    /* Delete CAN handle */
    returnValue =
        meiCanDelete(*can);
    msgCHECK(returnValue);

    *can = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Toggle CAN Outputs */
void toggleCanOutputs(MEICan can, long nodeNumber, long channelCount)
{
    MEICanDigitalIO outputs;
    long            returnValue;
    long            channel;

    /* Turn off all the digital outputs in one instruction. */
    outputs.data[0] = 0;
    outputs.data[1] = 0;
    meiCanNodeDigitalOutputsSet(can, nodeNumber, &outputs);

    /* Set each output bit in turn. */
    for(channel = 0; channel<CHANNEL_COUNT; channel++) {
        /* Turn digital output "on" */
        returnValue =
            meiCanNodeDigitalOutputSet(can, nodeNumber, channel, TRUE);
        msgCHECK(returnValue);

        /* Pause for one half second */
        meiPlatformSleep(500);

        /* Turn digital output "off" */
        returnValue =
            meiCanNodeDigitalOutputSet(can, nodeNumber, channel, FALSE);
        msgCHECK(returnValue);
    }
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEICan              can;
    long                canNumber    = CAN_NETWORK_NUMBER;
    long                channelCount = CHANNEL_COUNT;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &can,
                canNumber);

    /* Toggle CAN Outputs */
    toggleCanOutputs(can, OUTPUT_NODE_NUMBER, CHANNEL_COUNT);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &can);

    /* return a success. */
    return 0;
}


capture1.c -- Perform a velocity move and capture position based

.

capture1.c -- Perform a velocity move and capture position based on Home or Index pulse.
/* capture1.c */

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

/*

:Perform a velocity move and capture position based on Home or Index pulse.

This sample application demonstrates use of the Capture feature on the XMP.
 First, a velocity move is commanded on an Axis.  A capture is then configured
 to trigger on either a Home sensor or index pulse.

Each motor currently has two capture registers per motor encoder. Valid
 capture numbers are 0 and 1.

This program presumes the tuning parameters(PID, PIV, etc.) for your
 stage(or tool, or machine) have already been set.  That is, the tuning
 parameters need to be established prior to running this program so the
 stage can move in a stable manner.  Please use the Tuning Guidelines if
 these values haven't been determined.

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.

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 "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    capture1Main

argMainRENAME(main, capture1)
#endif

/* Capture Parameters */
#define  CAPTURE_COUNT       (1)                            /* Enable Capture count	 */
#define  CAPTURE_NUMBER      (0)                            /* Capture object number */
#define  CAPTURE_MOTOR       (0)                            /* Motor number */
#define  CAPTURE_INDEX       (0)                            /* Index to capture engine */
#define  CAPTURE_FEEDBACK    (0)                            /* same as CAPTURE_MOTOR for CaptureTypePOSITION */

#define CAPTURE_TYPE            (MPICaptureTypePOSITION)    /* Capture type */
                                                            /* Position	(MPICaptureTypePOSITION) or          */
                                                            /* Time		(MPICaptureTypeTIME)                 */

#define CAPTURE_ENCODER			(MPIMotorEncoderPRIMARY)	/* Encoder primary or secondary                  */
                                                            /* primary   (MPIMotorEncoderPRIMARY) or         */
                                                            /* secondary (MPIMotorEncoderSECONDARY)          */
/* Capture Parameters */
#define CAPTURE_GLOBAL_TRIGGER  (FALSE)                     /* signal all captures to latch */
#define CAPTURE_TRIGGER_EDGE    (MPICaptureEdgeRISING)

/* IO */
#define TRIGGER_SOURCE_HOME	    (FALSE)
#define TRIGGER_HOME_INVERT     (FALSE)

#define TRIGGER_SOURCE_IO       (MPICaptureSourceHOME)      /* choice of IO */
                                                            /*  MPICaptureSourceHOME
                                                                MPICaptureSourceLIMIT_HW_NEG
                                                                MPICaptureSourceLIMIT_HW_POS
                                                                MPICaptureSourceGLOBAL
                                                                MPICaptureSourceMOTOR_IO_0
                                                                MPICaptureSourceMOTOR_IO_1
                                                                MPICaptureSourceMOTOR_IO_2
                                                                MPICaptureSourceMOTOR_IO_3
                                                                MPICaptureSourceMOTOR_IO_4
                                                                MPICaptureSourceMOTOR_IO_5
                                                                MPICaptureSourceMOTOR_IO_6
                                                                MPICaptureSourceMOTOR_IO_7
                                                            */

/* INDEX */
#define TRIGGER_SOURCE_INDEX	(TRUE)
#define TRIGGER_INDEX_INVERT	(FALSE)

/* Motion Parameters */
#define VELOCITY				(30000.0)    /* Move velocity */
#define ACCEL					(100000.0)	/* Move acceleration*/

/* 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) {
        meiPlatformConsole("usage: %s %s\n", argv[0], ArgUSAGE);
        exit(MPIMessageARG_INVALID);
    }
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPICapture         *capture)
{
    MPIControlConfig	controlConfig;

    long    returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

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

    /* Enable a controller capture object */
    returnValue =
        mpiControlConfigGet(*control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    controlConfig.captureCount = CAPTURE_COUNT;

    returnValue =
        mpiControlConfigSet(*control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    *capture =
        mpiCaptureCreate(*control,
                         CAPTURE_NUMBER);
    msgCHECK(mpiCaptureValidate(*capture));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl      *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    MPIMotor        *motor,
                    MPICapture      *capture)
{
    long    returnValue;

    /* Delete capture object */
    returnValue =
        mpiCaptureDelete(*capture);
    msgCHECK(returnValue);

    *capture = MPIHandleVOID;

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    *motor = MPIHandleVOID;

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    *motion = MPIHandleVOID;

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    *axis = MPIHandleVOID;

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Configure capture object. */
void configureCapture(MPICapture capture)
{
    MPICaptureConfig    captureConfig;
    long				index;
    long                returnValue;

    /* Disable capture */
    returnValue =
        mpiCaptureArm(capture,
                      FALSE);
    msgCHECK(returnValue);

    /* Read caputre configuration */
    returnValue =
        mpiCaptureConfigGet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Set capture parameters */
    captureConfig.captureMotorNumber  = CAPTURE_MOTOR;
    captureConfig.feedbackMotorNumber = CAPTURE_FEEDBACK;
    captureConfig.encoder             = CAPTURE_ENCODER;
    captureConfig.global.enabled      = CAPTURE_GLOBAL_TRIGGER;
    captureConfig.edge                = CAPTURE_TRIGGER_EDGE;
    captureConfig.type                = CAPTURE_TYPE;
    captureConfig.captureIndex        = CAPTURE_INDEX;

    /* disable capture source */
    for(index=0; index < MPICaptureSourceLAST; index++) {
        captureConfig.source[index].enabled = FALSE;
    }

    /* Enable capture source */
    /* IO */
    if (TRIGGER_SOURCE_HOME) {
        captureConfig.source[TRIGGER_SOURCE_IO].enabled = TRUE;
        captureConfig.source[TRIGGER_SOURCE_IO].invert  = TRIGGER_HOME_INVERT;
    }

    /* Index */
    if (TRIGGER_SOURCE_INDEX) {
        captureConfig.source[MPICaptureSourceINDEX].enabled = TRUE;
        captureConfig.source[MPICaptureSourceINDEX].invert  = TRIGGER_INDEX_INVERT;
    }

    /* Write capture configuration */
    returnValue =
        mpiCaptureConfigSet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);
}

/* Disable Home Event action */
void disableHomeEvent(MPIMotor      motor,
                      MPICapture    capture)
{
    MPIMotorEventConfig eventConfig;
    long                returnValue;

    returnValue =
        mpiMotorEventConfigGet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    eventConfig.action           = MPIActionNONE;   /* No action   */
    eventConfig.trigger.polarity = TRUE;			/* Active high */

    returnValue =
        mpiMotorEventConfigSet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Arm the capture */
    returnValue =
        mpiCaptureArm(capture,
                      TRUE);
    msgCHECK(returnValue);
}

/* Perform a Velocity move */
void velocityMove(MPITrajectory     *trajectory,
                  MPIMotionParams   *params,
                  MPIMotion         *motion)
{
    long    returnValue;

    /* Setup motion parameters */
    trajectory->velocity        = VELOCITY;
    trajectory->acceleration    = ACCEL;
    trajectory->deceleration    = ACCEL;	/* Not used for velocity move */
    trajectory->jerkPercent     = 0.0;		/* Not used for velocity move */
    params->velocity.trajectory = trajectory;

    /* Start a velocity move */
    returnValue =
        mpiMotionStart(*motion,
                       MPIMotionTypeVELOCITY,
                       params);
    msgCHECK(returnValue);
}

/* Poll capture status and update display */
void pollForCaptureAndUpdateDisplay(MPICapture      *capture,
                                    MPIMotor        *motor)
{
    MPICaptureStatus    captureStatus;
    MPIMotorIo          io;
    long                caputuresCounted = 0;
    long                returnValue;

    /* State Machine - Poll capture status, update display, etc. */
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        long	position[2] = {0, 0};

        returnValue =
            mpiCaptureStatus(*capture,
                             &captureStatus,
                             NULL);
        msgCHECK(returnValue);

        /* Display Home and Capture state */
        returnValue =
            mpiMotorIoGet(*motor,
                          &io);
        msgCHECK(returnValue);

        meiPlatformConsole("\rCaptureState:%d  ", captureStatus.state);        /* (1=ARMED, 2=CAPTURED) */

        if (captureStatus.state == MPICaptureStateCAPTURED) {
            caputuresCounted++;
            position[1] = position[0];
            position[0] = (long)captureStatus.latchedValue;

            meiPlatformConsole("IO = 0x%08X\tLatched Position = %d (%d)\n\n",
                                io.input,
                                (long)captureStatus.latchedValue,
                                position[0] - position[1]);

            /* Re-arm position capture */
            returnValue =
              mpiCaptureArm(*capture,
                              TRUE);
            msgCHECK(returnValue);
        }
        meiPlatformSleep(1);
    }
}

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

    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIMotor            motor;
    MPICapture          capture;
    MPITrajectory       trajectory;
    MPIMotionParams     params;

    long    returnValue;                /* Return value from library */
    long    motorNumber  = CAPTURE_MOTOR;
    long    motionNumber = motorNumber;
    long    axisNumber   = motorNumber;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                motionNumber,
                &axis,
                axisNumber,
                &motor,
                motorNumber,
                &capture);

    /* Configure capture  */
    configureCapture(capture);

    /* Disable Home Event action */
    disableHomeEvent(motor,
                     capture);

    /* Perform a Velocity move */
    velocityMove(&trajectory,
                 ¶ms,
                 &motion);

    meiPlatformConsole("\n Moving.... Press any key to quit.\n\n");

    /* Poll capture status and update display */
    pollForCaptureAndUpdateDisplay(&capture,
                                   &motor);

    meiPlatformConsole("\nStopping.\n");

    /* Stop motion on axis */
    returnValue =
        mpiMotionAction(motion,
                        MPIActionSTOP);
    msgCHECK(returnValue);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motion,
                   &axis,
                   &motor,
                   &capture);

    return ((int)returnValue);
}


coffee.c -- Read XMP firmware signature

.

coffee.c -- Read XMP firmware signature
/* coffee.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Read XMP firmware signature

This sample application reads the firmware signature and other controller
ID registers including:  Signature, Disable, SoftwareID, and Option.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    coffeeMain

argMainRENAME(main, coffee)
#endif

unsigned long MEIMemory[64];

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* Motion controller handle */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    void    *memory;        /* Control memory */

    long    returnValue;    /* Return value from library */
    long    argIndex;

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

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n",
                           argv[0],
                           ArgUSAGE);
        exit(MPIMessagePARAM_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    returnValue =
        mpiControlMemory(control,
                         &memory,
                         NULL);
    msgCHECK(returnValue);

    /* Read and Print the Controller firmware signature */
    returnValue =
        mpiControlMemoryGet(control,
                            MEIMemory,
                            memory,
                            sizeof(MEIMemory));
    msgCHECK(returnValue);

    fprintf(stderr, "Sharc memory: 0x0%08x 0x%08x 0x%08x 0x%08x\n",
                    MEIMemory[0],
                    MEIMemory[1],
                    MEIMemory[2],
                    MEIMemory[3]);

    /* Delete objects */
    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


comp.c -- Configure Axis Compensation Tables

.

comp.c -- Configure Axis Compensation Tables
/* comp.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure Axis Compensation Tables

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 <ctype.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    compMain

argMainRENAME(main, comp)
#endif

#define COMP_FILENAME   "comp.txt"

MEIXmpCompensator   Comp;

long    CompTable[MEIXmpCompTableSize];

long    loadCompTable(MPIControl        control,
                      long              index,
                      MEIXmpCompensator *comp);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */

    char    *fileName;
    FILE    *fp;
    long    compIndex;
    long    compIndexOld;
    long    controlIndex;
    long    tableIndex;
    long    tableCount = 0;
    char    buffer[256];

    long    returnValue;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

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

    fileName =
        (argIndex >= argc)
                ? COMP_FILENAME
                : argv[argIndex++];

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[fileName (%s)]",
                           argv[0],
                           ArgUSAGE,
                           COMP_FILENAME);
        exit(0);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    fp = fopen(fileName, "r");

    if (fp == NULL) {
        fprintf(stderr,
                "%s: file not found.\n",
                fileName);
        exit(2);
    }

    compIndex = 0;
    compIndexOld = -1;

    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        long    inAxis;
        long    outAxis;
        long    minPosition;
        long    deltaPosition;
        long    compPoints;
        long    dimension;

        char    *ptr;

        if (compIndex > compIndexOld) {
            Comp.Dimension                  = -1;
            Comp.OutAxis                    = -1;
            Comp.Control[0].InAxis          = -1;
            Comp.Control[0].DeltaPosition   = -1;
            Comp.Control[0].CompPoints      = -1;
            Comp.Control[1].InAxis          = -1;
            Comp.Control[1].DeltaPosition   = -1;
            Comp.Control[1].CompPoints      = -1;
            tableCount = 0;

            memset(CompTable, 0, sizeof(CompTable));
            Comp.CompTable = CompTable;

            compIndexOld = compIndex;
        }

        for (ptr = buffer; *ptr != '\0'; ptr++) {
            char    byte = *ptr;

            if (islower(byte)) {
                *ptr = (char)toupper(byte);
            }
        }

        if (sscanf(buffer, "#DIMENSION  = %d", &dimension) == 1) {
            Comp.Dimension = dimension;
            continue;
        }

        if (sscanf(buffer, "#INAXIS[%d]  = %d",&controlIndex, &inAxis) == 2) {
            Comp.Control[controlIndex].InAxis = inAxis;
            continue;
        }

        if (sscanf(buffer, "#OUTAXIS  = %d", &outAxis) == 1) {
            Comp.OutAxis = outAxis;
            continue;
        }

        if (sscanf(buffer, "#MINPOSITION[%d]  = %d",&controlIndex, &minPosition) == 2) {
            Comp.Control[controlIndex].MinPosition = minPosition;
            continue;
        }

        if (sscanf(buffer, "#DELTAPOSITION[%d]  = %d",&controlIndex, &deltaPosition) == 2) {
            Comp.Control[controlIndex].DeltaPosition = deltaPosition;
            continue;
        }

        if (sscanf(buffer, "#COMPPOINTS[%d]  = %d",&controlIndex, &compPoints) == 2) {
            Comp.Control[controlIndex].CompPoints = compPoints;
            continue;
        }

        if (sscanf(buffer, "#POSITION[%d]", &tableIndex) == 1) {
            long    index;
            long    calc_x;

            if (Comp.Dimension == 1) {
                Comp.Control[1].CompPoints = 1;
                Comp.Control[1].InAxis          = 0;
                Comp.Control[1].DeltaPosition   = 0;
            }

            /* Do some error checking. */
            if (compIndex >= MEIXmpMAX_Compensators) {
                fprintf(stderr,
                        "Too many compensators. Max = %d.\n",
                        MEIXmpMAX_Compensators);
                break;
            }

            if (Comp.OutAxis < 0) {
                fprintf(stderr,
                        "No #OutAxis statement.\n");
                break;
            }

            if (Comp.Dimension < 0) {
                fprintf(stderr,
                        "No #Dimension statement.\n");
                break;
            }

            for (controlIndex = 0; controlIndex < Comp.Dimension; controlIndex++) {
                if (Comp.Control[controlIndex].InAxis < 0) {
                    fprintf(stderr,
                            "No #InAxis[%d] statement.\n",
                            controlIndex);
                    break;
                }

                if (Comp.Control[controlIndex].CompPoints < 0) {
                    fprintf(stderr,
                            "No #CompPoints[%d] statement.\n",
                            controlIndex);
                    break;
                }

                if (Comp.Control[controlIndex].DeltaPosition < 0) {
                    fprintf(stderr,
                            "Delta Position[%d] (%d) is invalid.\n",
                            controlIndex,
                            Comp.Control[controlIndex].DeltaPosition);
                    break;
                }
            }
            if ((Comp.Control[0].CompPoints * Comp.Control[1].CompPoints)
                    > MEIXmpCompTableSize) {
                fprintf(stderr,
                        "Too many compensation points. Max = %d.\n",
                        MEIXmpCompTableSize);
                break;
            }

            if (tableIndex >= Comp.Control[1].CompPoints) {
                fprintf(stderr,
                        "Compensation table number (%d) out of range [0-%d].\n",
                        tableIndex,
                        Comp.Control[1].CompPoints);
                break;
            }

            calc_x = Comp.Control[0].MinPosition;

            index = 0;

            while (index < Comp.Control[0].CompPoints) {
                long    x;
                long    y;
                long    tableOffset;

                if (fgets(buffer, sizeof(buffer), fp) == NULL) {
                    fprintf(stderr,
                            "Unexpected end-of-file\n");
                    break;
                }

                if (sscanf(buffer, "%d %d", &x, &y) == 2) {
                    if (x != calc_x) {
                        fprintf(stderr,
                                "Table out of order, expected position = %d, read %d\n",
                                calc_x,
                                x);
                        break;
                    }
                    tableOffset = index + tableIndex * Comp.Control[0].CompPoints;
                    Comp.CompTable[tableOffset] = y;
                    calc_x += Comp.Control[0].DeltaPosition;
                    index++;
                }
            }

            if (index < Comp.Control[0].CompPoints) {
                fprintf(stderr,
                        "Compensation table number (%d) too small.\n",
                        tableIndex);
                break;
            }
            else {
                tableCount++;
                fprintf(stderr,
                        "Compensation Table %d read.\n",
                        tableIndex);
            }

            if (tableCount >= Comp.Control[1].CompPoints) {
                returnValue =
                    loadCompTable(control,
                                  compIndex,
                                  &Comp);

                fprintf(stderr,
                        "Compensator %d is %sconfigured.\n",
                        compIndex,
                        (returnValue == MPIMessageOK)
                                    ? ""
                                    : "NOT ");

                compIndex++;
            }
        }
    }

    fclose(fp);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long loadCompTable(MPIControl           control,
                   long                 index,
                   MEIXmpCompensator    *comp)
{
    MPIControlConfig    controlConfig;
    MEIControlConfig    controlConfigXmp;

    long    returnValue;

    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            &controlConfigXmp);

    if (returnValue == MPIMessageOK) {
        if (controlConfigXmp.Compensator[index].CompTable != NULL) {

            fprintf(stderr,
                    "Warning: controlConfigXmp.Compensator[%d] is already in use\n",
                    index);
        }

        controlConfigXmp.compensatorCount = index + 1;
        controlConfigXmp.Compensator[index] = *comp;

        if (index > 0) {
            long *prev_dest;
            long prev_size;

            prev_dest = controlConfigXmp.Compensator[index - 1].CompTable;
            prev_size = controlConfigXmp.Compensator[index - 1].Control[0].CompPoints *
               controlConfigXmp.Compensator[index-1].Control[1].CompPoints;

            controlConfigXmp.Compensator[index].CompTable = &prev_dest[prev_size];
        }
        else {
            controlConfigXmp.Compensator[index].CompTable =
                controlConfigXmp.CompensationTable;
        }

        meiASSERT(&controlConfigXmp.CompensationTable[MEIXmpCompTableSize] >=
                  &controlConfigXmp.Compensator[index].CompTable[
                            controlConfigXmp.Compensator[index].Control[0].CompPoints *
                            controlConfigXmp.Compensator[index].Control[1].CompPoints]);

        memcpy(controlConfigXmp.Compensator[index].CompTable,
               comp->CompTable,
               controlConfigXmp.Compensator[index].Control[0].CompPoints *
               controlConfigXmp.Compensator[index].Control[1].CompPoints *
                    sizeof(long));

        returnValue =
            mpiControlConfigSet(control,
                                &controlConfig,
                                &controlConfigXmp);
    }

    return (returnValue);
}


encfltcfg.c -- Configure encoder fault settings for a motor

.

encfltcfg.c -- Configure encoder fault settings for a motor.
/* encfltcfg.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    limitsw1Main
argMainRENAME(main, limitsw1)
#endif

/*

:Configure encoder fault settings for a motor.

Encoder faults are set with an action, duration, and trigger.

  The action is one of the following:

    MPIActionSTOP,
    MPIActionE_STOP,
    MPIActionE_STOP_ABORT,
    MPIActionABORT,

The duration is in seconds. Keep in mind that the resolution of this setting
  is one servo sample period (1/sample rate).

The trigger sets three switches.
    MPIMotorEncoderFaultMaskBW_DET,		Broken wire switch
    MPIMotorEncoderFaultMaskILL_DET,	Illegal state switch
    MPIMotorEncoderFaultMaskABS_ERR,	Absolute encoder error switch

Broken wires occur when the positive and negative halves of an encoder signal
  pull together. An example would be when A+ and A- are at the same voltage
  because one of the A wires is disconnected.

Illegal state occurs when the A and B channel change level within 40 nsec.

Absolute encoder errors occur when there is a communication error on an
  absolute encoder. The details of this will vary with different types of
  absolute encoders.

Events are configured using MPIMotorEventConfigGet/Set(...).

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTOR           (0)
#define EVENT_DURATION  (0.010)     /* seconds */

/* 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);
    }
}

void encoderFaultConfigure(MPIMotor        motor,
                           MPIAction       action,
                           double          duration)
{
    MPIMotorEventConfig eventConfig;
    long returnValue;

    /* Get the current limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               MPIEventTypeENCODER_FAULT,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

      /* Wait duration seconds before triggering */
    eventConfig.duration = (float) duration;

    /* Configure motor to perform action upon limit */
    eventConfig.action = action;

    /* Turn on all encoder fault types */
    eventConfig.trigger.mask = 	MPIMotorEncoderFaultMaskBW_DET |
        MPIMotorEncoderFaultMaskILL_DET |
        MPIMotorEncoderFaultMaskABS_ERR;

    /* Set the new limit configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               MPIEventTypeENCODER_FAULT,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotor           *motor,
                 long                motorNumber)
{
    long returnValue;

    /* Obtain a Control handle */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Obtain a Motor handle */
    *motor =
        mpiMotorCreate(*control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(*motor));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIMotor    *motor)
{
    long returnValue;

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete control object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIMotor            motor;
    MPIControlAddress   controlAddress;
    MPIControlType      controlType;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motor,
                MOTOR);

    /* Change the ENCODER_FAULT configuration */
    encoderFaultConfigure(motor,
                        MPIActionABORT,             /* ABORT on limit  */
                        EVENT_DURATION);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motor);

    return MPIMessageOK;
}


event1.c -- Perform a repeated two-axis motion while polling an event

.

event1.c -- Perform a repeated two-axis motion while polling an event manager.
/* event1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a repeated two-axis motion while polling an event manager.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    event1Main

argMainRENAME(main, event1)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  20000.0,    },
    { 0.0,      0.0,        },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axisX;      /* X axis */
    MPIAxis     axisY;      /* Y axis */
    MPIMotion   motion;     /* coordinated motion object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    long    returnValue;    /* return value from library */

    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create X axis object using axis number X_AXIS on controller */
    axisX =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axisX));

    /* Create Y axis object using axis number Y_AXIS on controller */
    axisY =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axisY));

    /* Create motion object using MS number */
    /* Append X axis to motion */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axisX);
    msgCHECK(mpiMotionValidate(motion));

    /* Append Y axis to motion */
    returnValue =
        mpiMotionAxisAppend(motion,
                            axisY);
    msgCHECK(returnValue);

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    msgCHECK(mpiNotifyValidate(notify));

    /* Create event manager object */
    eventMgr =
        mpiEventMgrCreate(control);
    msgCHECK(mpiEventMgrValidate(eventMgr));

    /* Flush any existing events */
    returnValue =
        mpiEventMgrFlush(eventMgr);
    msgCHECK(returnValue);

    /* Add notify to event manager's list */
    returnValue =
        mpiEventMgrNotifyAppend(eventMgr,
                                notify);
    msgCHECK(returnValue);

    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index = 0;
    while ((returnValue == MPIMessageOK) &&
           (meiPlatformKey(MPIWaitPOLL) <= 0)) {
        MPIMotionParams motionParams;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           motionType,
                           &motionParams);

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                msgCHECK(returnValue);

                /* Wait for reset to take effect */
                meiPlatformSleep(2);

                /* FALL THROUGH */
            }
            case MPIMotionMessageNOT_READY: {
                returnValue = MPIMessageOK;
                continue;
            }
            case MPIMotionMessageMOVING: {
                returnValue = MPIMessageOK;
                break;
            }
            case MPIMessageOK:
            default: {
                break;
            }
        }

        /* Collect motion events */
        while (TRUE) {
            MPIEventStatus  eventStatus;

            /* Obtain firmware event(s) (if any) */
            returnValue =
                mpiEventMgrService(eventMgr,
                                   MPIHandleVOID);
            msgCHECK(returnValue);

            /* Poll for motion event */
            returnValue =
                mpiNotifyEventWait(notify,
                                   &eventStatus,
                                   MPIWaitPOLL);

            if (returnValue == MPIMessageOK) {
                if (eventStatus.type == MPIEventTypeMOTION_DONE) {
                    break;
                }
            }
            else {
                meiASSERT(returnValue == MPIMessageTIMEOUT);
            }
        }

        if (++index >= MOTION_COUNT) {
            index = 0;
        }
    }

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisX);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


event3.c -- Perform a repeated single-axis motion using command-line-specified

.

event3.c -- Perform a repeated single-axis motion using command-line-specified axis (default 0).
/* event3.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a repeated single-axis motion using command-line-specified axis (default 0).

Wait for events to be distributed by the event manager in a separate service thread.
 Check status after motion complete, warn of inPosition not set.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    event3Main

argMainRENAME(main, event3)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            axisNumber      = 0;
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0, },
    { 0.0, },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.0,   },
    },
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.0,   },
    },
};

/* motion parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

long
    motionDone(MPIMotion    motion,
               MPIStatus    *status);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;        /* motion controller handle */
    MPIAxis     axisList[AXIS_COUNT];   /* axis handle(s) */
    MPIMotion   motion;         /* motion handle */
    MPINotify   notify;         /* event notification object */
    MPIEventMgr eventMgr;       /* event manager handle */

    MPIEventMask    eventMask;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    Service service;

    long    returnValue;    /* return value from library */

    long    index;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object using axisNumber on controller*/
    axisList[0] =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axisList[0]));

    /* Create motion supervisor object using MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create 1-axis motion coordinate system */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axisList);
    msgCHECK(returnValue);

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    /* Loop repeatedly */
    index = 0;
    while ((returnValue == MPIMessageOK) &&
           (meiPlatformKey(MPIWaitPOLL) <= 0)) {
        MPIMotionParams motionParams;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           motionType,
                           &motionParams);

        fprintf(stderr,
                "mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                motion,
                motionType,
                &motionParams,
                returnValue,
                mpiMessage(returnValue, NULL));

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion,
                        returnValue);
                msgCHECK(returnValue);

                /* FALL THROUGH */
            }
            case MPIMotionMessageNOT_READY: {
                returnValue = MPIMessageOK;
                continue;
            }
            case MPIMotionMessageMOVING: {
                returnValue = MPIMessageOK;
                break;
            }
            case MPIMessageOK:
            default: {
                break;
            }
        }

        /* Collect motion events */
        while (returnValue == MPIMessageOK) {
            MPIEventStatus  eventStatus;

            /* Wait for motion event */
            returnValue =
                mpiNotifyEventWait(notify,
                                   &eventStatus,
                                   MPIWaitFOREVER);

            fprintf(stderr,
                    "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]);

            if (returnValue == MPIMessageOK) {
                if (eventStatus.type == MPIEventTypeMOTION_DONE) {
                    break;
                }
            }
            else {
                break;
            }
        }

        if (returnValue == MPIMessageOK) {
            MPIStatus   status;

            returnValue =
                motionDone(motion,
                           &status);

            if ((returnValue == MPIMessageOK) &&
                (status.state == MPIStateERROR)) {
                if ((status.action == MPIActionABORT) ||
                    (status.action == MPIActionE_STOP_ABORT)) {
                    double  position[AXIS_COUNT];

                    returnValue =
                        mpiMotionPositionGet(motion,
                                             position,  /* actual */
                                             NULL);     /* command */
                    msgCHECK(returnValue);

                    returnValue =
                        mpiMotionPositionSet(motion,
                                             NULL,      /* actual */
                                             position); /* command */
                    msgCHECK(returnValue);
                }

                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion,
                        returnValue);
                msgCHECK(returnValue);
            }
        }

        putchar('\n');

        if (++index >= MOTION_COUNT) {
            index = 0;
        }
    }

    fprintf(stderr,
            "%s exiting: returnValue 0x%x: %s\n",
            argv[0],
            returnValue,
            mpiMessage(returnValue, NULL));

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axisList[index]);
        msgCHECK(returnValue);
    }

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long motionDone(MPIMotion motion,
                MPIStatus *status)
{
    long    returnValue;

    double  actual[AXIS_COUNT];
    double  command[AXIS_COUNT];

    returnValue =
        mpiMotionStatus(motion,
                        status,
                        NULL);
    msgCHECK(returnValue);

    printf("MotionDone: status: state %d action %d eventMask 0x%x\n"
           "\tatTarget %d settled %d %s\n",
            status->state,
            status->action,
            status->eventMask,
            status->atTarget,
            status->settled,
            (status->settled == FALSE)
                    ? "=== NOT SETTLED ==="
                    : "");

    returnValue =
        mpiMotionPositionGet(motion,
                             actual,
                             command);
    msgCHECK(returnValue);

    if (returnValue == MPIMessageOK) {
        long    index;

        /* Display axis positions */
        for (index = 0; index < AXIS_COUNT; index++) {
            printf("\taxis[%d]    position: command %11.3lf\tactual %11.3lf\n",
                    index,
                    command[index],
                    actual[index]);
        }
    }

    return (returnValue);
}


EventLog.c -- Event Logging Application

.

EventLog.c -- Event Logging Application
/* EventLog.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    EventLogMain
argMainRENAME(main, EventLog)
#endif

/*

:Event Logging Application

This application logs all events generated by a single controller.  To end
 the application, simply press a key.  To save the output to a file,
 please redirect the output using a pipe (type "EventLog > logOfEvents.txt")

NOTE:  This application does not change any configuration on the controller.
 If the controller is not configured to report events, then this application
 will report nothing.  Please refer to the sample application EventReport.c
 to see how to enable reporting of all events.

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.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

/* 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,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service)
{
    MEIEventMgrServiceConfig    serviceConfig;
    MPIEventMask                eventMask;

    long            returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Obtain a notify handle */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    *notify =
        mpiNotifyCreate(eventMask, NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Obtain an eventMgr handle */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr, *notify);
    msgCHECK(returnValue);

    /* Retrieve events from all processes */
    returnValue =
        meiEventMgrServiceConfigGet(*eventMgr, &serviceConfig);
    msgCHECK(returnValue);

    serviceConfig.allProcesses = TRUE;

    returnValue =
        meiEventMgrServiceConfigSet(*eventMgr, &serviceConfig);
    msgCHECK(returnValue);

    /* Obtain a service handle */
    *service =
        serviceCreate(*eventMgr, -1, -1);
    meiASSERT(service != NULL);
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIEventMgr *eventMgr,
                    MPINotify   *notify,
                    Service     *service)
{
    long    returnValue;

    /* Delete service handle */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    *service = NULL;

    /* Delete eventMgr handle */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    *eventMgr = NULL;

    /* Delete notify handle */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    *notify = NULL;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = NULL;
}

/*
    Identifies the source (type and index) of an event
        (from the MPIEventStatus structure)

    This is particularly useful when attempting to identify which axis produced
    an event in a different process or when identifying the axis without
    comparing MPIAxis handles.

    identifyEventSource() will return MPIMessageARG_INVALID if status is NULL or
    if both sourceType and sourceIndex are NULL.  Otherwise, the function will
    succeed and return MPIMessageOK.

    Possible values for sourceType:

    sourceType Value        Event Source Type
    ----------------        -----------------
    MEIXmpSignalID_MOTOR    Motor object
    MEIXmpSignalID_AXIS     Axis
    MEIXmpSignalID_MS       Motion Supervisor
    MEIXmpSignalID_PS       Program Sequencer (Non-user commanded events)
    MEIXmpSignalID_DR       Data Recorder
    MEIXmpSignalID_USER     User Commanded Event in a Program Sequencer

    NOTE: As of Feb 2002, only one Data Recorder exists per controller, so
    when the source is the data recorder, sourceIndex will filled with the
    value of zero.
 */
long identifyEventSource(MPIEventStatus* status,
                         MEIXmpSignalID* sourceType,
                         long* sourceIndex)
{
    if (status==NULL)
    {
        return MPIMessageARG_INVALID;
    }

    if ((sourceType==NULL) && (sourceIndex==NULL))
    {
        return MPIMessageARG_INVALID;
    }

    if (sourceType!=NULL)
    {
        *sourceType =
            ((((MEIEventStatusInfo*)status->info)->signalID) &
                MEIXmpSignalID_MASK);
    }

    if (sourceIndex!=NULL)
    {
        *sourceIndex =
            ((((MEIEventStatusInfo*)status->info)->signalID) &
                MEIXmpSignalID_INDEX) >> 16;
    }

    return MPIMessageOK;
}

/* Display event information */
void reportEvent(MPIEventStatus* status)
{
    MEIXmpSignalID  sourceType;

    long            sourceIndex;
    long            returnValue;

    returnValue =
        identifyEventSource(status, &sourceType, &sourceIndex);
    msgCHECK(returnValue);

    /* Report event source */
    switch (sourceType)
    {
        case MEIXmpSignalID_MOTOR:
            if (sourceIndex<10)
            {
                printf("Motor[%1d]     : ",sourceIndex);
            }
            else
            {
                printf("Motor[%2d]    : ",sourceIndex);
            }
            break;
        case MEIXmpSignalID_AXIS:
            if (sourceIndex<10)
            {
                printf("Axis[%1d]      : ",sourceIndex);
            }
            else
            {
                printf("Axis[%2d]     : ",sourceIndex);
            }
            break;
        case MEIXmpSignalID_MS:
            if (sourceIndex<10)
            {
                printf("Motion[%1d]    : ",sourceIndex);
            }
            else
            {
                printf("Motion[%2d]   : ",sourceIndex);
            }
            break;
        case MEIXmpSignalID_DR:
            printf("Data Recorder : ");
            break;
        case MEIXmpSignalID_PS:
            if (sourceIndex<10)
            {
                printf("Sequence[%1d]  : ",sourceIndex);
            }
            else
            {
                printf("Sequence[%2d] : ",sourceIndex);
            }
            break;
        case MEIXmpSignalID_USER:
            if (sourceIndex<10)
            {
                printf("User (PS[%1d]) : ",sourceIndex);
            }
            else
            {
                printf("User (PS[%2d]): ",sourceIndex);
            }
            break;
        default:
            printf("Unknown Source: ",sourceIndex);
    }

    /* Report event type */
    switch (status->type)
    {
        case MPIEventTypeAMP_FAULT:
            printf("Amplifier Fault      ");
            break;
        case MPIEventTypeHOME:
            printf("Home Event           ");
            break;
        case MPIEventTypeLIMIT_ERROR:
            printf("Position Error Limit ");
            break;
        case MPIEventTypeLIMIT_HW_NEG:
            printf("Negative HW Limit    ");
            break;
        case MPIEventTypeLIMIT_HW_POS:
            printf("Positive HW Limit    ");
            break;
        case MPIEventTypeLIMIT_SW_NEG:
            printf("Negative SW Limit    ");
            break;
        case MPIEventTypeLIMIT_SW_POS:
            printf("Positive SW Limit    ");
            break;
        case MPIEventTypeENCODER_FAULT:
            printf("Encoder Fault        ");
            break;
        case MPIEventTypeMOTION_DONE:
            printf("Motion Done          ");
            break;
        case MPIEventTypeMOTION_AT_VELOCITY:
            printf("Motion at Velocity   ");
            break;
        case MPIEventTypeRECORDER_FULL:
            printf("Data Recorder Full   ");
            break;
        case MPIEventTypeRECORDER_DONE:
            printf("Data Recorder Done   ");
            break;
        case MPIEventTypeEXTERNAL:
            printf("External Event       ");
            break;
        case MEIEventTypeLIMIT_USER0:
            printf("User Limit 0         ");
            break;
        case MEIEventTypeLIMIT_USER1:
            printf("User Limit 1         ");
            break;
        case MEIEventTypeLIMIT_USER2:
            printf("User Limit 2         ");
            break;
        case MEIEventTypeLIMIT_USER3:
            printf("User Limit 3         ");
            break;
        case MEIEventTypeLIMIT_USER4:
            printf("User Limit 4         ");
            break;
        case MEIEventTypeLIMIT_USER5:
            printf("User Limit 5         ");
            break;
        case MEIEventTypeLIMIT_USER6:
            printf("User Limit 6         ");
            break;
        case MEIEventTypeLIMIT_USER7:
            printf("User Limit 7         ");
            break;
        case MEIEventTypeLIMIT_TORQUE:
            printf("Torque Limit         ");
            break;
        case MEIEventTypeMOTION_OUT_OF_FRAMES:
            printf("Motion out of frames ");
            break;
        case MEIEventTypeMOTION_RESERVED0:
            printf("Reserved Event 0     ");
            break;
        case MEIEventTypeIN_POSITION_COARSE:
            printf("In Coarse Position   ");
            break;
        case MEIEventTypeIN_POSITION_FINE:
            printf("Settled              ");
            break;
        case MEIEventTypeAT_TARGET:
            printf("Cmd Pos at Target    ");
            break;
        case MEIEventTypeFRAME:
            printf("Frame Event          ");
            break;
        case MEIEventTypeAXIS_RESERVED0:
            printf("Reserved Event 0     ");
            break;
        case MEIEventTypeAXIS_RESERVED1:
            printf("Reserved Event 1     ");
            break;
        case MEIEventTypePOWER_FAILURE:
            printf("Power Failure        ");
            break;
        default:
            printf("Unknown event        ");
    }

    /* Report event sample */
    printf("Sample %10u ",((MEIEventStatusInfo*)status->info)->data.sampleCounter);

    /* Report additional information */
    switch (sourceType)
    {
        case MEIXmpSignalID_MOTOR:
            printf("Enc Position  %11d\n",
                    ((MEIEventStatusInfo*)status->info)->data.motor.encoderPosition);
            break;
        case MEIXmpSignalID_AXIS:
            printf("Axis Position %11d\n",
                    ((MEIEventStatusInfo*)status->info)->data.axis.actualPosition);
            break;
        default:
            printf("\n");
    }
}

/* Gather and display events */
void reportEventsUntilUserRequestsExit(MPIEventMgr eventMgr, MPINotify notify)
{
    MPIEventStatus  eventStatus;

    long returnValue;

    fprintf(stderr, "Press any key to exit...\n");

    /* Collect motion events */
    while (meiPlatformKey(MPIWaitPOLL) < 0)
    {
        /* Obtain firmware event(s) (if any) */
        returnValue =
            mpiEventMgrService(eventMgr,
                               MPIHandleVOID);
        msgCHECK(returnValue);

        /* Poll for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               (MPIWait)MPIWaitMSEC*20);

        if (returnValue != MPIMessageTIMEOUT)
        {
            reportEvent(&eventStatus);
        }
    }
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIEventMgr         eventMgr;
    MPINotify           notify;

    Service             service;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &eventMgr,
                &notify,
                &service);

    /* Gather and display events */
    reportEventsUntilUserRequestsExit(eventMgr, notify);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &eventMgr,
                   &notify,
                   &service);

    return MPIMessageOK;
}


EventReport.c -- Enable controller event reporting

.

EventReport.c -- Enable controller event reporting
/* EventReport.c */

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

/*

:Enable controller event reporting

Enables event reporting for all enabled objects on a controller except for
 program sequencers.  Creating a program sequencer requires allocating
 controller memory for its program, so it's not possible to create (and thus
 not possible to configure) a program sequencer without interfering with other
 applications.  This is ok though, because if a program sequencer uses events,
 it should be already configured to report them.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

/* 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)
{
    long    returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control)
{
    long    returnValue;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Enable Events */
void enableEventReporting(MPIControl control)
{
    MPIControlConfig    controlConfig;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIMotor            motor;
    MPIRecorder         recorder;
    MPIEventMask        eventMask;

    long    index;
    long    returnValue;

    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    for (index = 0; index < controlConfig.motionCount; ++index)
    {
        motion =
            mpiMotionCreate(control,
                            index,
                            MPIHandleVOID);
        msgCHECK(mpiMotionValidate(motion));

        returnValue =
            mpiMotionEventNotifySet(motion,
                                    eventMask,
                                    NULL);
        msgCHECK(returnValue);

        returnValue =
            mpiMotionDelete(motion);
        msgCHECK(returnValue);
    }

    for (index = 0; index < controlConfig.axisCount; ++index)
    {
        axis =
            mpiAxisCreate(control,
                          index);
        msgCHECK(mpiAxisValidate(axis));

        returnValue =
            mpiAxisEventNotifySet(axis,
                                  eventMask,
                                  NULL);
        msgCHECK(returnValue);

        returnValue =
            mpiAxisDelete(axis);
        msgCHECK(returnValue);
    }

    for (index = 0; index < controlConfig.motorCount; ++index)
    {
        motor =
            mpiMotorCreate(control,
                           index);
        msgCHECK(mpiMotorValidate(motor));

        returnValue =
            mpiMotorEventNotifySet(motor,
                                   eventMask,
                                   NULL);
        msgCHECK(returnValue);

        returnValue =
            mpiMotorDelete(motor);
        msgCHECK(returnValue);
    }

    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    returnValue =
        mpiRecorderEventNotifySet(recorder,
                                  eventMask,
                                  NULL);
    msgCHECK(returnValue);

    returnValue =
        mpiRecorderDelete(recorder);
    msgCHECK(returnValue);
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress);

    /* Enable Events */
    enableEventReporting(control);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control);

    return MPIMessageOK;
}


home1.c -- Simple Homing routine that captures the hardware position,

.

home1.c -- Simple Homing routine that captures the hardware position, sets the origin
/* home1.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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    home1Main

argMainRENAME(main, home1)
#endif

/*
:Simple Homing routine that captures the hardware position, sets the origin
  and moves back to home.

home1.c allows the user to trigger his home off an input or index
 pulse, capture the hardware position, set the origin and then move back
 to that home position.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define CapturesPerMotor    (2) /* Default Capture configuration */

#define ACTIVE_FALLING_EDGE     (0)
#define ACTIVE_RAISING_EDGE     (1)

/* MPI Object numbers */
#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define MOTOR_NUMBER    (0)

/* Motion Parameters */
#define VELOCITY        (5000)  /* Move velocity     */
#define ACCELERATION    (10000) /* Move acceleration */
#define DECELERATION    (10000) /* Move deceleration */

/* Capture Parameters */
#define CAPTURE_EDGE        (ACTIVE_FALLING_EDGE) /* Capture on falling edge */

/* CAPTURE_TRIGGER can be MEIMotorInputHOME or MEIMotorInputINDEX */
#define CAPTURE_TRIGGER     (MEIMotorInputHOME)   /* Capture on home pulse */

/* 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,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPICapture         *capture,
                 long                captureNumber)
{
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

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

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl      *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    MPIMotor        *motor,
                    MPICapture      *capture)
{
    long    returnValue;

    /* Delete capture object */
    returnValue =
        mpiCaptureDelete(*capture);
    msgCHECK(returnValue);

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/* Calculate default capture number for axisNumber */
long captureNumber(long     motorNumber)
{
    return  ((motorNumber/MEIXmpMotorsPerBlock) * MEIXmpMaxLatches) +
            ((motorNumber % MEIXmpMotorsPerBlock) * CapturesPerMotor);
}

/*
   Configure caputure object

   edge: 0 for falling edge, 1 for rising edge
*/
void configureCapture(MPICapture    capture,
                      MEIMotorInput trigger,
                      long          edge)
{
    MPICaptureConfig    captureConfig;
    long                returnValue;

    /* Disable capture */
    returnValue =
        mpiCaptureArm(capture,
                      FALSE);
    msgCHECK(returnValue);

    /* Read caputre configuration */
    returnValue =
        mpiCaptureConfigGet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Set capture parameters */
    captureConfig.trigger.mask    = trigger;
    captureConfig.trigger.pattern = edge ? trigger : 0;

    /* Write caputre configuration */
    returnValue =
        mpiCaptureConfigSet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);
}

/* Configure Home Event action */
void configureHomeAction(MPIMotor   motor,
                         MPIAction  action,
                         long       activeHigh)
{
    MPIMotorEventConfig eventConfig;
    MPIEventMask        eventMask;
    long                returnValue;

    /* Read home event configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Configure Home Event action */
    eventConfig.action = action;
    eventConfig.trigger.polarity = activeHigh;

    /* Write home event configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Reset Home Event */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskSET(eventMask, MPIEventTypeHOME);
    returnValue =
        mpiMotorEventReset(motor,
                           eventMask);
    msgCHECK(returnValue);
}

/* Command simple trapezoidal motion */
void simpleVelocityMove(MPIMotion   motion,
                        double      velocity,
                        double      acceleration,
                        double      deceleration)
{
    MPIMotionParams params;      /* Motion parameters      */
    MPITrajectory   trajectory;  /* Trajectory information */

    long            returnValue; /* MPI library return value */

    /* Setup trajectory structure */
    trajectory.velocity     = velocity;
    trajectory.acceleration = acceleration;
    trajectory.deceleration = deceleration;
    trajectory.jerkPercent  = 0.0;          /* Trapezoidal profile */

    /* Setup parameters structure */
    params.velocity.trajectory  = &trajectory;

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeVELOCITY,
                       &params);
    msgCHECK(returnValue);
}

/* Command simple trapezoidal motion */
void simpleTrapMove(MPIMotion   motion,
                    double      goalPosition,
                    double      velocity,
                    double      acceleration,
                    double      deceleration)
{
    MPIMotionParams params;      /* Motion parameters      */
    MPITrajectory   trajectory;  /* Trajectory information */

    long            returnValue; /* MPI library return value */

    /* Setup trajectory structure */
    trajectory.velocity     = velocity;
    trajectory.acceleration = acceleration;
    trajectory.deceleration = deceleration;

    /* Setup parameters structure */
    params.trapezoidal.trajectory   = &trajectory;
    params.trapezoidal.position     = &goalPosition;

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);
}

/* Display caputure status while waiting for the motion to be done */
void displayCaptureStatusUntilMotionDone(MPIMotion           motion,
                                         MPICapture          capture,
                                         MPICaptureStatus   *captureStatus)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue;

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the capture status */
        returnValue =
            mpiCaptureStatus(capture,
                             captureStatus,
                             NULL);
        msgCHECK(returnValue);

        printf("CaptureState:0x%x\r",
                captureStatus->state);

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 20ms and give up control to other threads */
                meiPlatformSleep(20);
                break;
            }
            case MPIStateIDLE:
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
    /* Display latched position */
    printf("\nLatched Home Position = %.0lf\n",
            captureStatus->latch[0]);
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIMotor            motor;
    MPICapture          capture;
    MPICaptureStatus    captureStatus;

    long    returnValue;        /* Return value from library */

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &capture,
                captureNumber(MOTOR_NUMBER));

    /* Configure capture */
    configureCapture(capture,
                     CAPTURE_TRIGGER,
                     CAPTURE_EDGE);

    /* Configure Home Event action to stop */
    configureHomeAction(motor,
                        MPIActionSTOP,
                        TRUE);          /* Active High */

    /* Arm the capture */
    returnValue =
        mpiCaptureArm(capture,
                      TRUE);
    msgCHECK(returnValue);

    printf("Looking for home...\n");

    /* Start a velocity move */
    simpleVelocityMove(motion,
                       VELOCITY,
                       ACCELERATION,
                       DECELERATION);

    /* Display caputure status while waiting for the motion to be done */
    displayCaptureStatusUntilMotionDone(motion,
                                        capture,
                                        &captureStatus);

    /* Set origin to home position */
    returnValue =
        mpiAxisOriginSet(axis,
                         captureStatus.latch[0]);
    msgCHECK(returnValue);

    printf("Moving back to origin.\n");

    /* Configure Home Event action to none */
    configureHomeAction(motor,
                        MPIActionNONE,
                        TRUE);

    /* Move back to home */
    simpleTrapMove(motion,
                   0.0,     /* Go back to home position */
                   VELOCITY,
                   ACCELERATION,
                   DECELERATION);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motion,
                   &axis,
                   &motor,
                   &capture);

    return ((int)returnValue);
}


initFlsh.c -- Controller initialization and automatic firmware download

.

initFlsh.c -- Controller initialization and automatic firmware download
/* initFlsh.c */

/* Copyright(c) 1991-2003 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 MEIUtilRCS[] =
    "RCSHeader";
#endif

/*

:Controller initialization and automatic firmware download

  ********************************* Warning ***********************************
  This application will overwrite the controller configuration that is saved
  to the Flash memory.  If connected to hardware this could cause motors to
  be enabled or to run away.  Do NOT use without proper knowledge of the system
  *****************************************************************************

This sample code demonstrates how to download Firmware to the XMP-Series
 controller.  The Firmware can also be downloaded using one of the utilities
 provided by MEI.  This sample application requires the user to specify the
 location and filename for a valid, matching Firmware file and optional
 FPGA file(s).  During initialization the controller's firmware version,
 revision, option and user version numbers are checked.  If the controller's
 version doesn't match the expected version, the firmware is downloaded to
 the controller's flash memory.

Note: The flash utility program uses the same code to download firmware to the
 flash memory.

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"

/* Set desired Firmware version. these values could be read from a file */
#define FW_VERSION          332
#define FW_REVISION         'A'
#define FW_SUBREVISION      2
#define FW_OPTION           0
#define FW_VERSION_USER     0   /* user configurable */

#if defined(ARG_MAIN_RENAME)
#define main    initFlshMain

argMainRENAME(main, initFlsh)
#endif

#define FIRMWARE    "c:\\xmp332a2.bin"  /* this string could be read from a file */
#define FPGA0       (NULL)              /* specify NULL for default FPGA image */
#define FPGA1       (NULL)
#define FPGA2       (NULL)

long initXmp(MPIControl control, MEIFlashFiles *fileNames);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl          control;

    long    returnValue;
    long    argIndex;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MEIFlashFiles       flashFiles;

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

    /* Obtain a Control handle */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* copy file names into structure */
    if (FIRMWARE != NULL) {
        strcpy(flashFiles.binFile, FIRMWARE);
    }
    else {
        flashFiles.binFile[0] = '\0';
    }
    if (FPGA0 != NULL) {
        strcpy(flashFiles.FPGAFile[0], FPGA0);
    }
    else {
        flashFiles.FPGAFile[0][0] = '\0';
    }
    if (FPGA1 != NULL) {
        strcpy(flashFiles.FPGAFile[1], FPGA1);
    }
    else {
        flashFiles.FPGAFile[1][0] = '\0';
    }
    if (FPGA2 != NULL) {
        strcpy(flashFiles.FPGAFile[2], FPGA2);
    }
    else {
        flashFiles.FPGAFile[2][0] = '\0';
    }

    /* Initialize the controller, load flash if firmware is different */
    returnValue =
        initXmp(control,
                &flashFiles);   /* firmware and FPGA file name(s) */
    msgCHECK(returnValue);

    /* Delete object handles */
    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long versionCheck(MPIControl control)
{
    MPIControlConfig    controlConfig;
    MEIControlVersion   version;

    long returnValue;

    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);

    returnValue =
        meiControlVersionGet(control,
                             &version);

    if ((version.xmp.firmware.version != FW_VERSION)
        || (version.xmp.firmware.revision != FW_REVISION)
        || (version.xmp.firmware.subRevision != FW_SUBREVISION)
        || (version.xmp.firmware.option != FW_OPTION)
        || (controlConfig.userVersion != FW_VERSION_USER)) {

        meiPlatformConsole("ERROR: Controller firmware does not match expected version.\n"
                           " Version:  %d%c%d option:%d user:%d\n"
                           " Expected: %d%c%d option:%d user:%d\n\n",
                           version.xmp.firmware.version,
                           version.xmp.firmware.revision,
                           version.xmp.firmware.subRevision,
                           version.xmp.firmware.option,
                           controlConfig.userVersion,
                           FW_VERSION,
                           FW_REVISION,
                           FW_SUBREVISION,
                           FW_OPTION,
                           FW_VERSION_USER);

        returnValue = MEIControlMessageFIRMWARE_VERSION;
    }

    /* display check result */
    meiPlatformConsole("Firmware Version Check: %s\n", mpiMessage(returnValue, NULL));

    return (returnValue);
}

long firmwareLoad(MPIControl control, MEIFlashFiles *fileNames)
{
    MEIFlash            flash;
    MEIFlashFiles       loadedFiles;
    MEIControlVersion   version;

    long                MB0 = -1;
    long                MB1 = -1;
    long                update20Khz = 0;

    long        returnValue;

    returnValue =
        mpiControlValidate(control);

    if (returnValue == MPIMessageOK) {
        /* fake a valid version so we can still use the MPI routines */
        returnValue =
            meiControlVersionGet(control,
                                 &version);

        if (returnValue == MPIMessageOK) {
            memset(&version.xmp.firmware,
                   0,
                   sizeof(version.xmp.firmware));

            version.xmp.firmware.version = version.mpi.firmware.version;
            version.xmp.firmware.option  = version.mpi.firmware.option;

            returnValue =
                meiControlVersionSet(control,
                                     &version);
        }
    }

    if (returnValue == MPIMessageOK) {
        /* Create Flash object */
        flash =
            meiFlashCreate(control);
        returnValue = meiFlashValidate(flash);
    }

    if (returnValue == MPIMessageOK) {
        meiPlatformConsole("Loading flash memory from \"%s\" ...\n",
                                   fileNames->binFile);
    }

    if (returnValue == MPIMessageOK) {
        /* Load Firmware and FPGAs from file(s) */
        returnValue =
            meiFlashMemoryFromFile(flash,
                                   fileNames,
                                   &loadedFiles);
    }

    if (returnValue == MPIMessageOK) {
        meiPlatformConsole("Code loaded and verified from \"%s\".\n",
                           loadedFiles.binFile);

        meiPlatformConsole("FPGAs loaded and verified from\n"
                            "%s\n"
                            "%s\n"
                            "%s\n\n",
                            loadedFiles.FPGAFile[0],
                            loadedFiles.FPGAFile[1],
                            loadedFiles.FPGAFile[2]);

    }
    else {
        meiPlatformConsole("Can't load flash from \"%s\"\n"
                            "\"%s\"\n"
                            "\"%s\"\n"
                            "\"%s\"\n"
                            "(%s)\n",
                            loadedFiles.binFile,
                            loadedFiles.FPGAFile[0],
                            loadedFiles.FPGAFile[1],
                            loadedFiles.FPGAFile[2],
                            mpiMessage(returnValue, NULL));
    }

    if (returnValue == MPIMessageOK) {
        returnValue = mpiControlReset(control);
        msgCHECK(returnValue);
    }

    if (returnValue == MPIMessageOK) {
        MEIControlSocketInfo socketInfo;
        MEIControlRipTideConfig config;

        returnValue = meiControlSocketInfoGet(control,
                                              &socketInfo);
        msgCHECK(returnValue);

        /* Get default RipTide configuration */
        returnValue = meiControlRipTideDefaultGet(control,
                                                   &socketInfo,
                                                   &config);
        msgCHECK(returnValue);

        /* Configure RipTide */
        if (MB0 != -1) {
            config.motionBlocks[0] = MB0;
        }

        if (MB1 != -1) {
            config.motionBlocks[1] = MB1;
        }

        config.update20khz = update20Khz;

        if (config.update20khz) {
            MPIControlConfig controlConfig;

            config.motionBlocks[0] = 1;
            config.motionBlocks[1] = 0;

            /* Set Sample Rate */
            returnValue = mpiControlFlashConfigGet(control,
                                                   NULL,
                                                   &controlConfig,
                                                   NULL);
            msgCHECK(returnValue);

            if (returnValue == MPIMessageOK) {
                controlConfig.sampleRate = 20000;

                returnValue = mpiControlFlashConfigSet(control,
                                                       NULL,
                                                       &controlConfig,
                                                       NULL);
                msgCHECK(returnValue);
            }
        }

        if (returnValue == MPIMessageOK) {
            meiPlatformConsole("Configuring RipTide\n");

            returnValue = meiControlFlashRipTideConfigSet(control,
                                                        flash,
                                                        &config);

            if (config.update20khz) {
                meiPlatformConsole("Reconfigured RipTide:\n"
                                    "Configured for 20Khz operation\n"
                                    "Main Board has 1 Motion Block\n"
                                    "Expansion Board has 0 Motion Blocks\n\n");
            }
            else {
                meiPlatformConsole("Reconfigured RipTide:\n"
                                    "Main Board has %d Motion Blocks\n"
                                    "Expansion Board has %d Motion Blocks\n\n",
                                    config.motionBlocks[0],
                                    config.motionBlocks[1]);
            }
        }
    }

    /* clean up */
    if (returnValue == MPIMessageOK) {
        returnValue = meiFlashDelete(flash);
    }

    /* re-initialize controller */
    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiControlInit(control);
    }

    /* check version values */
    if (returnValue == MPIMessageOK) {
        returnValue =
            versionCheck(control);
    }

    return returnValue;
}

long initXmp(MPIControl control, MEIFlashFiles *fileNames)
{
    long returnValue;

    /* Initialize the controller */
    returnValue =
        mpiControlInit(control);

    /* check init returnValue */
    if ((returnValue == MEIControlMessageFIRMWARE_INVALID) ||
        (returnValue == MEIControlMessageFIRMWARE_VERSION) ||
        (returnValue == MEIControlMessageFIRMWARE_VERSION_NONE)) {
        /* display warning */
        meiPlatformConsole("WARNING: %s\n\n",
                   mpiMessage(returnValue, NULL));

        /* load firmware */
        returnValue =
            firmwareLoad(control, fileNames);
    }
    else {
        if (returnValue == MPIMessageOK) {
            /* check firmware version, revision, option, and user version */
            returnValue =
                versionCheck(control);

            if (returnValue == MEIControlMessageFIRMWARE_VERSION) {
                /* load firmware */
                returnValue =
                    firmwareLoad(control, fileNames);
            }
        }
    }

    return (returnValue);
}


limitSw1.c -- Configure positive and negative hardware limit inputs

.

limitSw1.c -- Configure positive and negative hardware limit inputs.
/* limitsw1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    limitsw1Main
argMainRENAME(main, limitsw1)
#endif

/*

:Configure positive and negative hardware limit inputs.

A motor's positive and negative hardware limit inputs have four configurations:

  1) Event Action   (any MPIAction such as MPIActionE_STOP)
  2) Event Trigger  (a trigger polarity, active HIGH or LOW)
  3) Direction Flag (TRUE will cause the command direction of motion to
                        qualify the events, FALSE will ignore direction,
                        based solely on the limit input state)
  4) Duration       (requires the limit condition to exist for
                        a programmable number of seconds before an
                        event will occur)

Events are configured using MPIMotorEventConfigGet/Set(...).

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTOR           (0)
#define EVENT_DURATION  (0.010)     /* seconds */

/* 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);
    }
}

void limitConfigure(MPIMotor        motor,
                    MPIEventType    eventType,
                    MPIAction       action,
                    long            polarity,
                    long            direction,
                    double          duration)
{
    MPIMotorEventConfig eventConfig;
    long                returnValue;

    /* Get the current limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               eventType,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Set trigger level to Active Low (FALSE) or Active High (TRUE) */
    eventConfig.trigger.polarity = polarity;

    /* Use commanded velocity direction as a trigger qualifier. (TRUE/FALSE) */
    eventConfig.direction = direction;

    /* Wait duration seconds before triggering */
    eventConfig.duration = (float) duration;

    /* Configure motor to perform action upon limit */
    eventConfig.action = action;

    /* Set the new limit configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               eventType,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotor           *motor,
                 long                motorNumber)
{
    long returnValue;

    /* Obtain a Control handle */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Obtain a Motor handle */
    *motor =
        mpiMotorCreate(*control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(*motor));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIMotor    *motor)
{
    long returnValue;

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete control object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIMotor            motor;
    MPIControlAddress   controlAddress;
    MPIControlType      controlType;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motor,
                MOTOR);

    /* Change the LIMIT_HW_POS configuration */
    limitConfigure(motor,
                   MPIEventTypeLIMIT_HW_POS,    /* +HW limit        */
                   MPIActionE_STOP,             /* E-STOP on limit  */
                   TRUE,                        /* Active High      */
                   TRUE,     /* Use velocity as a trigger qualifier */
                   EVENT_DURATION);

    /* Change the LIMIT_HW_POS configuration */
    limitConfigure(motor,
                   MPIEventTypeLIMIT_HW_NEG,    /* -HW limit        */
                   MPIActionE_STOP,             /* E-STOP on limit  */
                   TRUE,                        /* Active High      */
                   TRUE,     /* Use velocity as a trigger qualifier */
                   EVENT_DURATION);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motor);

    return MPIMessageOK;
}


mboard1.c -- Setup multiple controllers, clear positions and perform

.

mboard1.c -- Setup multiple controllers, clear positions and perform a two-point motion.
/* mboard1.c */

/* Copyright(c) 1991-2003 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
 */
#if defined(MEI_RCS)
    static const char MEIAppRCS[] =
    "RCSHeader";
#endif
/*

:Setup multiple controllers, clear positions and perform a two-point motion.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    mboard1Main

argMainRENAME(main, mboard1)
#endif

#define BOARD_COUNT (2)

#define MOTION_COUNT    (1)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            controlNumber   = 0;
long            axisNumber      = 0;
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-control", ArgTypeLONG,    &controlNumber, },
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0, },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.0,   },
    },
};

/* motion parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl          controller[BOARD_COUNT];    /* Array of control handles   */
    MPIMotion           motion[BOARD_COUNT];        /* Array of motion  handles   */
    MPIAxis             axis[BOARD_COUNT];          /* Array of axis    handles   */

    MPIControlAddress   controlAddress;

    long    returnValue;
    long    argIndex = 0;
    long    index;

    /* 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 - 1) ||    /* minus application name */
        (axisNumber   >= MEIXmpMAX_Axes) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /*
        Initialize each controller with default settings,
        specifying the board's controller number.
     */
    for (index = 0; index < BOARD_COUNT; index++) {
        controlAddress.number = controlNumber + index;  /* setting controller number */

        controller[index] =
            mpiControlCreate(MPIControlTypeDEFAULT,
                             &controlAddress);
        msgCHECK(mpiControlValidate(controller[index]));
    }

    /* Initialize the controllers */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiControlInit(controller[index]);

        if (returnValue != MPIMessageOK) {
            fprintf(stderr,
                    "Controller #%d : mpiControlInit(0x%x) returns 0x%x: %s\n",
                    index,
                    controller[index],
                    returnValue,
                    mpiMessage(returnValue, NULL));

            exit(1);
        }
    }

    /*  Obtain Axis and Motion handle for each board */
    for (index = 0; index < BOARD_COUNT; index++) {
        axis[index] =
            mpiAxisCreate(controller[index],
                          axisNumber);
        msgCHECK(mpiAxisValidate(axis[index]));

        /* Create motion object, append axis */
        motion[index] =
            mpiMotionCreate(controller[index],
                            motionNumber,
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));
    }

    /* Clear the command and actual positions on each controller */
    for (index = 0; index < BOARD_COUNT; index++) {
        double command;

        returnValue =
            mpiAxisCommandPositionGet(axis[index],
                                      &command);
        msgCHECK(returnValue);

        returnValue =
            mpiAxisOriginSet(axis[index],
                             command);
        msgCHECK(returnValue);

        /* clear position error */
        returnValue =
            mpiAxisActualPositionSet(axis[index],
                                     0.0);
        msgCHECK(returnValue);
    }

    /* Sequentially Start motion */
    for (index = 0; index < BOARD_COUNT; index++) {
        MPIMotionParams motionParams;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[0];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[0];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[0];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Start motion */
        returnValue =
            mpiMotionStart(motion[index],
                           motionType,
                           &motionParams);

        fprintf(stderr,
                "mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                motion[index],
                motionType,
                &motionParams,
                returnValue,
                mpiMessage(returnValue, NULL));

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion[index],
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion[index],
                        returnValue);
                msgCHECK(returnValue);

                /* FALL THROUGH */
            }
            case MPIMotionMessageNOT_READY: {
                returnValue = MPIMessageOK;
                continue;
            }
            case MPIMotionMessageMOVING: {
                returnValue = MPIMessageOK;
                break;
            }
            case MPIMessageOK:
            default: {
                break;
            }
        }
    }

    /* Delete the Motion handles */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiMotionDelete(motion[index]);
        msgCHECK(returnValue);
    }

    /* Delete the Axis handles */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete the CONTROL handles */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiControlDelete(controller[index]);
        msgCHECK(returnValue);
    }

    return ((int)returnValue);
}


mboard2.c -- Two point motion on multiple controllers with an event

.

mboard2.c -- Two point motion on multiple controllers with an event manager in polling mode.
/* mboard2.c */

/* Copyright(c) 1991-2003 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
 */
#if defined(MEI_RCS)
static const char MEIAppRCS[] =
    "RCSHeader";
#endif
/*

:Two point motion on multiple controllers with an event manager in polling mode.

Creates a two point motion sequentially on multiple controller boards.
 One event manager is used for all controllers.  The event manager is polled
 to retrieve MotionDone events from each motion.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    mboard2Main

argMainRENAME(main, mboard2)
#endif

#define BOARD_COUNT (2)

#define MOTION_COUNT    (1)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            controlNumber   = 0;
long            axisNumber      = 0;
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-control", ArgTypeLONG,    &controlNumber, },
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0 },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel */
        { 10000.0,      100000.0,   100000.0,   },
    },
};

/* motion parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      controller[BOARD_COUNT];/* Array of control handles */
    MPIMotion       motion[BOARD_COUNT];    /* Array of motion handles */
    MPIAxis         axis[BOARD_COUNT];      /* Array of axis handles */
    MPINotify       notify[BOARD_COUNT];    /* Array of notify handles */
    MPIEventMgr     eventMgr;   /* Array of event manager handles */

    MPIEventMask    eventMask;

    MPIControlAddress   address;

    long    returnValue;
    long    argIndex=0;
    long    index;

    /* 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 - 1) ||    /* minus application name */
        (axisNumber   >= MEIXmpMAX_Axes) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /*
        Initialize each controller with default settings,
        specifying the board's controller number.
     */
    for (index = 0; index < BOARD_COUNT; index++) {
        address.number = controlNumber + index; /* set controller number */

        controller[index] =
            mpiControlCreate(MPIControlTypeDEFAULT,
                             &address);
        msgCHECK(mpiControlValidate(controller[index]));
    }

    /* Initialize the controllers */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiControlInit(controller[index]);

        if (returnValue != MPIMessageOK) {
            fprintf(stderr,
                    "Controller #%d : mpiControlInit(0x%x) returns 0x%x: %s\n",
                    index,
                    controller[index],
                    returnValue,
                    mpiMessage(returnValue, NULL));

            exit(1);
        }
    }

    /* Obtain Axis and Motion handle for each board */
    for (index = 0; index < BOARD_COUNT; index++) {
        axis[index] =
            mpiAxisCreate(controller[index],
                          axisNumber);
        msgCHECK(mpiAxisValidate(axis[index]));

        /* Create motion object, append axis */
        motion[index] =
            mpiMotionCreate(controller[index],
                            motionNumber,
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));
    }

    /* Setup one Event Manager for all boards */

    /* Create event manager object */
    eventMgr = mpiEventMgrCreate(controller[0]);
    msgCHECK(mpiEventMgrValidate(eventMgr));

    for (index = 1; index < BOARD_COUNT; index++) {
        /* Append additional controllers to the event manager */
        returnValue =
            mpiEventMgrControlAppend(eventMgr,
                                     controller[index]);
        msgCHECK(returnValue);
    }

    /* Flush any existing events */
    returnValue = mpiEventMgrFlush(eventMgr);
    msgCHECK(returnValue);

    /* Setup Notify Object */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskSET(eventMask, MPIEventTypeMOTION_DONE);

    for (index = 0; index < BOARD_COUNT; index++) {
        /* Request notification of Motion Done events from motion */
        returnValue =
            mpiMotionEventNotifySet(motion[index],
                                    eventMask,
                                    NULL);
        msgCHECK(returnValue);

        /* Create event notification object for motion */
        notify[index] =
            mpiNotifyCreate(eventMask,
                            motion[index]);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Add notify to event manager's list */
        returnValue =
            mpiEventMgrNotifyAppend(eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Clear the command and actual positions on each controller */
    for (index = 0; index < BOARD_COUNT; index++) {
        double command;

        returnValue =
            mpiAxisCommandPositionGet(axis[index],
                                      &command);
        msgCHECK(returnValue);

        returnValue =
            mpiAxisOriginSet(axis[index],
                             command);
        msgCHECK(returnValue);

        /* clear position error */
        returnValue =
            mpiAxisActualPositionSet(axis[index],
                                     0.0);
        msgCHECK(returnValue);
    }

    /* Sequentially start motion */
    for (index = 0; index < BOARD_COUNT; index++) {
        MPIMotionParams motionParams;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[0];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[0];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[0];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Start motion */
        returnValue =
            mpiMotionStart(motion[index],
                           motionType,
                           &motionParams);

        fprintf(stderr,
                "mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                motion[index],
                motionType,
                &motionParams,
                returnValue,
                mpiMessage(returnValue, NULL));

        switch (returnValue) {
            case MPIMotionMessageERROR: {
                returnValue =
                    mpiMotionAction(motion[index],
                                    MPIActionRESET);
                fprintf(stderr,
                        "mpiMotionAction(0x%x, RESET) returns 0x%x\n",
                        motion[index],
                        returnValue);
                msgCHECK(returnValue);
                /* FALL THROUGH */
            }
            case MPIMotionMessageNOT_READY: {
                returnValue = MPIMessageOK;
                continue;
            }
            case MPIMotionMessageMOVING: {
                returnValue = MPIMessageOK;
                break;
            }
            case MPIMessageOK:
            default: {
                break;
            }
        }

        /* Collect motion events (Polling Event Manager)*/
        while (TRUE) {
            MPIEventStatus  eventStatus;

            /* Obtain firmware event(s) (if any) */
            returnValue =
                mpiEventMgrService(eventMgr,
                                   MPIHandleVOID);
            msgCHECK(returnValue);

            /* Poll for motion event */
            returnValue =
                mpiNotifyEventWait(notify[index],
                                   &eventStatus,
                                   MPIWaitPOLL);

            if (returnValue == MPIMessageTIMEOUT) {
                /* no events have happend yet */
                returnValue = MPIMessageOK;
            }

            if (returnValue == MPIMessageOK) {
                if (eventStatus.type == MPIEventTypeMOTION_DONE) {
                    /* Caught the motion done event */
                    printf("Motion Done: type %d source 0x%x info 0x%x\n",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
            }
            else {
                printf("%d\n",returnValue);
                meiASSERT(FALSE);
            }
        }
    }

    /* Delete the EventMgr handle (must happen before removing Notify) */
    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    /* Delete the Notify handles */
    for (index = 0; index < BOARD_COUNT ;index++) {
        returnValue = mpiNotifyDelete(notify[index]);
        msgCHECK(returnValue);
    }

    /* Delete the Motion handles */
    for ( index = 0; index < BOARD_COUNT ;index++) {
        returnValue = mpiMotionDelete(motion[index]);
        msgCHECK(returnValue);
    }

    /* Delete the Axis handles */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete the CONTROL handles */
    for (index = 0; index < BOARD_COUNT; index++) {
        returnValue = mpiControlDelete(controller[index]);
        msgCHECK(returnValue);
    }

    return ((int)returnValue);
}


motGate1.c -- Load and trigger a point to point motion using a control

.

motGate1.c -- Load and trigger a point to point motion using a control Gate.
/* motGate1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    motGate1Main
argMainRENAME(main, motGate1)
#endif

/*

:Load and trigger a point to point motion using a control Gate.

This sample program demonstrates how to use the motion HOLD attribute and
 a control Gate, to pre-load a single axis trapezoidal profile motion.

The XMP-Series controller supports a motion HOLD attribute, which is useful
 for preloading and triggering motion profiles.  One or more motion supervisors
 can be started from the same HOLD conditions.  When multiple motion supervisors
 are triggered by the same HOLD conditions, the individual motion profiles will
 start in the same DSP sample period.  The HOLD can be set/cleared with a host
 function call, an XMP-Series controller internal variable or a Motor I/O
 state change.

The MEIMotionAttrHold{...} structure is used to configure the HOLD conditions:

 typedef    struct MEIMotionAttrHold {
    MEIMotionAttrHoldType   type;
    MEIMotionAttrHoldSource source;

    float   timeout;
} MEIMotionAttrHold;

The HOLD "type" can be one of the following:

 MEIMotionHoldTypeGATE - host software controlled.
 MEIMotionHoldTypeINPUT - XMP controller internal variable.
 MEIMotionHoldTypeMOTOR - XMP controller motor I/O state change.

For each HOLD "type" the "source" union, MEIMotionAttrHoldSource{...},
 configures the HOLD conditions:

 MEIMotionHoldTypeGATE:

  long gate - number between 0 to 31.

  The motion is held until the "gate" is cleared.  The function
  meiControlGateSet(...) is used to set/clear a gate.  When the closed
  parameter is TRUE, the gate is set, and motion is held.  When the
  closed parameter is FALSE, the gate is cleared, and motion starts.

 MEIMotionHoldTypeINPUT

  long *input - address of XMP memory location.
  long mask - bit mask, bitwise ANDed with the input value.
  long pattern - HOLD is released when masked value matches pattern.

  The motion is held until the value of the internal XMP memory location
  (pointed to by *input) bitwise ANDed with the mask matches the pattern.

 MEIMotionHoldTypeMOTOR

  long number - motor "n", XMP's dedicated inputs (Motor[n].IO.DedicaedIN.IO)
  long mask - bit mask, bitwise ANDed with the dedicated inputs.
  long pattern - HOLD is released when masked inputs matches pattern.

  The motion is held until the value of the dedicated input word
  (Motor[n].IO.DedicaedIN.IO) bitwise ANDed with the mask matches the
  pattern.

The HOLD "timeout" will cause the motion to start after the specified period
 (in seconds) even if the hold criteria have not been met.  To disable the
 timeout feature, set the timeout value to zero.

The MPI expects an array of hold attributes specifying separate attributes
 form each axis of a motion supervisor. All axes holding with the same hold
 attributes (same gate, same input, mask, and pattern) will start motion in
 the same sample even if the moves are specified using different motion
 supervisors.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define GATE_NUMBER     (0)
#define TIMEOUT         (0) /* Wait forever */

#define GOAL_POSITION   ( 10000.0)
#define VELOCITY        ( 10000.0)
#define ACCELERATION    (100000.0)
#define DECELERATION    (100000.0)
#define JERK_PERCENT    (   100.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);
    }
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber)
{
    long returnValue;

    /* Create control object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create Motion object */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));
}

/* Delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIMotion   *motion,
                    MPIAxis     *axis)
{
    long returnValue;

    /* Delete motion supervisor object */
    returnValue = mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue = mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete control object */
    returnValue = mpiControlDelete(*control);
    msgCHECK(returnValue);
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;        /* motion controller object handle */
    MPIMotion           motion;         /* motion object handle */
    MPIAxis             axis;           /* axis object handle */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotionParams     params;         /* motion parameters */
    MPITrajectory       trajectory;     /* motion trajectory */
    MEIMotionAttributes attributes;     /* motion attributes */
    MEIMotionAttrHold   hold;           /* hold attribute configuration */

    long                gateNumber  = GATE_NUMBER;
    float               gateTimeout = (float)TIMEOUT;

    double              position;       /* final target position */

    long                returnValue;    /* return value from library */

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc, argv, &controlType, &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER);

    /* Set up motion parameters */
    position                = GOAL_POSITION;    /* counts               */
    trajectory.velocity     = VELOCITY;         /* counts per sec       */
    trajectory.acceleration = ACCELERATION;     /* counts per sec * sec */
    trajectory.deceleration = DECELERATION;     /* counts per sec * sec */
    trajectory.jerkPercent  = JERK_PERCENT;

    params.sCurve.trajectory    = &trajectory;
    params.sCurve.position      = &position;

    /* Configure Motion Attributes */
    hold.type = MEIMotionAttrHoldTypeGATE;  /* software motion Gate control */
    hold.source.gate = gateNumber;
    hold.timeout = gateTimeout;

    attributes.hold = &hold;
    params.external = &attributes;

    printf("Setting the Control Gate to TRUE.\n");

    /* Set a control gate to prevent the motion profile from executing */
    returnValue =
        meiControlGateSet(control,
                          gateNumber,
                          TRUE);    /* set gate */
    msgCHECK(returnValue);

    printf("Loading the motion.\n");

    /* Load motion profile with HOLD attribute */
    returnValue =
        mpiMotionStart(motion,
                       (MPIMotionType)
                            (MPIMotionTypeS_CURVE | MEIMotionAttrMaskHOLD),
                       &params);
    msgCHECK(returnValue);

    printf("Press any key to set the Control Gate to FALSE...\r");

    /* Wait for user key */
    meiPlatformKey(MPIWaitFOREVER);

    printf("Setting the Control Gate to FALSE (executing the motion).\n");

    /* Clear a control gate, executing the preloaded motion */
    returnValue =
        meiControlGateSet(control,
                          gateNumber,
                          FALSE);   /* clear the gate */
    msgCHECK(returnValue);

    /* Delete MPI objects */
    programCleanup(&control,
                   &motion,
                   &axis);

    return ((int)returnValue);
}


motGate2.c -- Load and trigger motion profiles using a control Gate

.

motGate2.c -- Load and trigger motion profiles using a control Gate.
/* motGate2.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    motGate2Main
argMainRENAME(main, motGate2)
#endif

/*

:Load and trigger motion profiles using a control Gate.

This sample program demonstrates how to use the motion HOLD attribute and
 a control Gate, to pre-load a single axis motion, and to synchronize the
 start of two independent motion profiles.

Here are the steps:

 1) Move the X axis.
 2) Set a control Gate.
 3) Load a Y axis motion profile, using the HOLD attribute.
 4) Clear the control Gate, causing the Y axis motion to execute.
 5) Set a control Gate.
 6) Load X and Y axis motion profiles, using the HOLD attribute.
 7) Clear the control Gate, causing the X and Y axis motions to execute
    simultaneously.

The XMP-Series controller supports a motion HOLD attribute, which is useful
 for preloading and triggering motion profiles.  One or more motion supervisors
 can be started from the same HOLD conditions.  When multiple motion supervisors
 are triggered by the same HOLD conditions, the individual motion profiles will
 start in the same DSP sample period.  The HOLD can be set/cleared with a host
 function call, an XMP-Series controller internal variable or a Motor I/O
 state change.

The MEIMotionAttrHold{...} structure is used to configure the HOLD conditions:

 typedef    struct MEIMotionAttrHold {
    MEIMotionAttrHoldType   type;
    MEIMotionAttrHoldSource source;

    float   timeout;
} MEIMotionAttrHold;

The HOLD "type" can be one of the following:

 MEIMotionHoldTypeGATE - host software controlled.
 MEIMotionHoldTypeINPUT - XMP controller internal variable.
 MEIMotionHoldTypeMOTOR - XMP controller motor I/O state change.

For each HOLD "type" the "source" union, MEIMotionAttrHoldSource{...},
 configures the HOLD conditions:

 MEIMotionHoldTypeGATE:

  long gate - number between 0 to 31.

  The motion is held until the "gate" is cleared.  The function
  meiControlGateSet(...) is used to set/clear a gate.  When the closed
  parameter is TRUE, the gate is set, and motion is held.  When the
  closed parameter is FALSE, the gate is cleared, and motion starts.

 MEIMotionHoldTypeINPUT

  long *input - address of XMP memory location.
  long mask - bit mask, bitwise ANDed with the input value.
  long pattern - HOLD is released when masked value matches pattern.

  The motion is held until the value of the internal XMP memory location
  (pointed to by *input) bitwise ANDed with the mask matches the pattern.

 MEIMotionHoldTypeMOTOR

  long number - motor "n", XMP's dedicated inputs (Motor[n].IO.DedicaedIN.IO)
  long mask - bit mask, bitwise ANDed with the dedicated inputs.
  long pattern - HOLD is released when masked inputs matches pattern.

  The motion is held until the value of the dedicated input word
  (Motor[n].IO.DedicaedIN.IO) bitwise ANDed with the mask matches the
  pattern.

The HOLD "timeout" will cause the motion to start after the specified period
 (in seconds) even if the hold criteria have not been met.  To disable the
 timeout feature, set the timeout value to zero.

The MPI expects an array of hold attributes specifying separate attributes
 form each axis of a motion supervisor. All axes holding with the same hold
 attributes (same gate, same input, mask, and pattern) will start motion in
 the same sample even if the moves are specified using different motion
 supervisors.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTION_NUMBER1  (0)
#define MOTION_NUMBER2  (1)
#define AXIS_NUMBER1    (0)
#define AXIS_NUMBER2    (1)
#define GATE_NUMBER     (0)
#define TIMEOUT         (0) /* Wait forever */

#define GOAL_POSITION1  ( 10000.0)
#define GOAL_POSITION2  (     0.0)
#define VELOCITY        ( 10000.0)
#define ACCELERATION    (100000.0)
#define DECELERATION    (100000.0)
#define JERK_PERCENT    (   100.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);
    }
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motionX,
                 MPIMotion          *motionY,
                 long               *motionNumber,
                 MPIAxis            *axisX,
                 MPIAxis            *axisY,
                 long               *axisNumber)
{
    long returnValue;

    /* Create control object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create X axis object using AXIS_X number on controller */
    *axisX =
        mpiAxisCreate(*control,
                      axisNumber[0]);       /* axis Number */
    msgCHECK(mpiAxisValidate(*axisX));

    /* Create Y axis object using AXIS_Y number on controller */
    *axisY =
        mpiAxisCreate(*control,
                      axisNumber[1]);       /* axis Number */
    msgCHECK(mpiAxisValidate(*axisY));

    /* Create Motion object for axisX */
    *motionX =
        mpiMotionCreate(*control,
                        motionNumber[0],        /* motion supervisor number */
                        *axisX);
    msgCHECK(mpiMotionValidate(*motionX));

    /* Create Motion object for axisY */
    *motionY =
        mpiMotionCreate(*control,
                        motionNumber[1],        /* motion supervisor number */
                        *axisY);
    msgCHECK(mpiMotionValidate(*motionY));
}

/* Delete MPI objects */
void programCleanup(MPIControl  *control,
                    MPIMotion   *motionX,
                    MPIMotion   *motionY,
                    MPIAxis     *axisX,
                    MPIAxis     *axisY)
{
    long returnValue;

    /* Delete motion supervisor Y */
    returnValue = mpiMotionDelete(*motionY);
    msgCHECK(returnValue);

    /* Delete motion supervisor X */
    returnValue = mpiMotionDelete(*motionX);
    msgCHECK(returnValue);

    /* Delete axis Y */
    returnValue = mpiAxisDelete(*axisY);
    msgCHECK(returnValue);

    /* Delete axis X */
    returnValue = mpiAxisDelete(*axisX);
    msgCHECK(returnValue);

    /* Delete control object */
    returnValue = mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*
  waitForMotionDone() polls motion to see if the axis is in an idle or error
  state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
  MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.
*/
void waitForMotionDone(MPIMotion motion)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue = 0;

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 10ms and give up control to other threads */
                meiPlatformSleep(10);
                break;
            }
            case MPIStateIDLE:
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}

/* Function demonstrating how gates can control motion */
void gateControlledMotion(MPIControl         control,
                          MPIMotion          motion1,
                          MPIMotion          motion2,
                          MPIMotionParams   *motionParams,
                          MPIMotionType      motionType,
                          long               gateNumber,
                          long               hold)
{
    long returnValue;

    /* If hold = TRUE, turn on the HOLD bit of MPIMotionType */
    if (hold==TRUE) {
        motionType = (MPIMotionType) (motionType | MEIMotionAttrMaskHOLD);
    }

    printf("Turning control gate ON.\r");

    /* Set a control gate to prevent the motion profile from executing */
    returnValue =
        meiControlGateSet(control,
                          gateNumber,
                          TRUE);    /* set gate */
    msgCHECK(returnValue);

    printf("Turned control gate ON. \n");
    printf("Press any key to call mpiMotionStart(...) %s HOLD attribute.\r",
           (hold) ? "with" : "without");

    /* Wait for a key form the user */
    meiPlatformKey(MPIWaitFOREVER);

    /* Load motion profile */
    returnValue = mpiMotionStart(motion1,
                                 motionType,
                                 motionParams);
    msgCHECK(returnValue);

    /* If user specified a second motion object */
    if (motion2!=MPIHandleVOID) {

        /* Load motion profile */
        returnValue = mpiMotionStart(motion2,
                                     motionType,
                                     motionParams);
        msgCHECK(returnValue);
    }

    printf("Called mpiMotionStart(...) %s HOLD attribute.               \n",
           (hold) ? "with" : "without");

    printf("Press any key to turn control gate OFF\r");

    /* Wait for a key form the user */
    meiPlatformKey(MPIWaitFOREVER);

    /* Clear a control gate, executing the preloaded motion */
    returnValue =
        meiControlGateSet(control,
                          gateNumber,
                          FALSE);   /* clear the gate */
    msgCHECK(returnValue);

    printf("Turned control gate OFF.              \n");
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller handle */
    MPIAxis             axisX;      /* X axis                   */
    MPIAxis             axisY;      /* Y axis                   */
    MPIMotion           motionX;    /* motion object for axisX  */
    MPIMotion           motionY;    /* motion object for axisY  */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotionParams     motionParams;   /* motion parameters            */
    MPITrajectory       trajectory;     /* trajectory information       */
    MEIMotionAttributes attributes;     /* motion attributes            */
    MEIMotionAttrHold   hold;           /* hold attribute configuration */

    long    axisNumber[2]   = { AXIS_NUMBER1,   AXIS_NUMBER2,   };
    long    motionNumber[2] = { MOTION_NUMBER1, MOTION_NUMBER2, };
    long    gateNumber      = GATE_NUMBER;
    float   gateTimeout     = (float)TIMEOUT;
    double  position;

    /* Set up motion parameters */
    trajectory.velocity     = VELOCITY;         /* counts per sec       */
    trajectory.acceleration = ACCELERATION;     /* counts per sec * sec */
    trajectory.deceleration = DECELERATION;     /* counts per sec * sec */
    trajectory.jerkPercent  = JERK_PERCENT;

    motionParams.sCurve.trajectory  = &trajectory;
    motionParams.sCurve.position    = &position;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc, argv, &controlType, &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motionX,
                &motionY,
                motionNumber,
                &axisX,
                &axisY,
                axisNumber);

    /* Configure Motion Attributes */
    hold.type = MEIMotionAttrHoldTypeGATE;  /* software motion Gate control */
    hold.source.gate = gateNumber;
    hold.timeout = gateTimeout;

    attributes.hold = &hold;
    motionParams.external = &attributes;

    /* Tell axis to go to GOAL_POSITION1 */
    position = GOAL_POSITION1;  /* counts */

    printf("\n*** X AXIS ***\n");

    /* Execute X-axis motion without HOLD attribute */
    gateControlledMotion(control,
                         motionX,
                         MPIHandleVOID,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         FALSE);

    printf("Wating for motion to complete...\n");

    /* Wait for motion to complete */
    waitForMotionDone(motionX);

    printf("\n*** Y AXIS ***\n");

    /* Execute Y-axis motion with HOLD attribute */
    gateControlledMotion(control,
                         motionY,
                         MPIHandleVOID,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         TRUE);

    printf("Wating for motion to complete...\n");

    /* Wait for motion to complete */
    waitForMotionDone(motionY);

    /* Tell axis to go to GOAL_POSITION2 */
    position = GOAL_POSITION2;  /* counts */

    printf("\n*** X & Y AXES ***\n");

    /* Execute X,Y-axes motion with HOLD attribute */
    gateControlledMotion(control,
                         motionX,
                         motionY,
                         &motionParams,
                         MPIMotionTypeS_CURVE,
                         gateNumber,
                         TRUE);

    /* Delete MPI objects */
    programCleanup(&control,
                   &motionX,
                   &motionY,
                   &axisX,
                   &axisY);

    return MPIMessageOK;
}


motid1.c -- Point to Point motion with Motion Done event identification.

.

motid1.c -- Point to Point motion with Motion Done event identification.
/* motId1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Point to Point motion with Motion Done event identification.

The MPI supports a motion attribute that allows an application to tag
 a mpiMotionStart(...) or mpiMotionModify(...) with an identification
 value.

This feature is useful in tracking the commanded motions to the done
 events.  It is also applicable when using the AUTO_START attribute
 with mpiMotionModify(...).

For example:

Suppose mpiMotionStart(...) is called with the MPIMotionAttrMaskID attribute,
 and the params.attributes.id = 1 and later mpiMotionModify(...) is called
 with params.attributes.id = 2.

Case 1: MPIMotionAttrAUTO_START is not used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageIDLE, there will be 1 DONE
 event with info->data.motion.id = 1.

Case 2: MPIMotionAttrAUTO_START is used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageAUTO_START,
 there will be 2 DONE events. The first will have info->data.motion.id = 1
 and the second will have info->data.motion.id = 2.

The XMP-Series controller supports some user data to be copied during Events
 and then later retrieved from the Host via the Notify object.

There are MEIXmpSignalUserData words of data for the motion, axis and motor
 event sources.  The default configuration for the first word is the XMP's
 sampleCounter.  The default for the second word is "actualPosition" for axis
 event sources, and "encoderPosition" for motor event sources.

In this sample, the second word for motion and axis events is configured for "id".

Note:  Keeping the first word configured for the "sampleCounter" is very
 helpful in determining event sequences.

Here is the default configuration for the event data:

    union {
        long sampleCounter;
        struct {
            long sampleCounter;
        } motion;
        struct {
            long sampleCounter;
            long actualPosition;
        } axis;
        struct {
            long sampleCounter;
            long encoderPosition;
        } motor;
        long word[MEIXmpSignalUserData];
    } data;

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motId1Main

argMainRENAME(main, motId1)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0,   };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Motion Parameters */
double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  },
    { 0.0,      },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent*/
        { 10000.0,      100000.0,   100000.0,   0.0,    },
    },
};

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis object */
    MPIMotion   motion;     /* motion object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    MEIEventNotifyData  motionData;
    MEIXmpAxis          *xmpAxis;

    long    returnValue;    /* return value from library */

    long    index;
    long    moveId;         /* identification tag */
    long    motionDone;

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Get current user data configuration */
    mpiEventMaskCLEAR(eventMask);
    returnValue =
        mpiMotionEventNotifyGet(motion,
                                &eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Request notification of all events from motion */
    mpiEventMaskALL(eventMask);

    /* Request ID data from motion event info[...] */
    returnValue  =
        mpiAxisMemory(axis,     /* use ID from first axis in motion object */
                      &(void *)xmpAxis);
    msgCHECK(returnValue);

    motionData.address[1] = (void *)(&xmpAxis->MoveID);

    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index       = 0;
    moveId      = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus  eventStatus;

        if (motionDone == TRUE) {
            MPIMotionParams motionParams;       /* motion parameters */

            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            motionParams.attributes.id = moveId;        /* identification tag */

            returnValue =
                mpiMotionStart(motion,
                               (MPIMotionType)(motionType | MPIMotionAttrMaskID),
                               &motionParams);
            msgCHECK(returnValue);

            printf("\nMotion Start #%d...", moveId);

            moveId++;

            motionDone = FALSE;
        }

        /* Wait for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            MEIEventStatusInfo *info;

            info = (MEIEventStatusInfo *)eventStatus.info;

            printf(" done #%ld",
                    info->data.word[1]);        /* user configurable data */

            if (++index >= MOTION_COUNT) {
                index = 0;
            }

            motionDone = TRUE;
        }
    }

    printf("\n");

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motid2.c -- Point to Point motion with motion/axis event identification.

.

motid2.c -- Point to Point motion with motion/axis event identification.
/* motId2.c */

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

/*

:Point to Point motion with motion/axis event identification.

The MPI supports a motion attribute that allows an application to tag
 a mpiMotionStart(...) or mpiMotionModify(...) with an identification
 value.

This feature is useful in tracking the commanded motions to the done
 events.  It is also applicable when using the AUTO_START attribute
 with mpiMotionModify(...).

For example:

Suppose mpiMotionStart(...) is called with the MPIMotionAttrMaskID attribute,
 and the params.attributes.id = 1 and later mpiMotionModify(...) is called
 with params.attributes.id = 2.

Case 1: MPIMotionAttrAUTO_START is not used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageIDLE, there will be 1 DONE
 event with info->data.motion.id = 1.

Case 2: MPIMotionAttrAUTO_START is used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageAUTO_START,
 there will be 2 DONE events. The first will have info->data.motion.id = 1
 and the second will have info->data.motion.id = 2.

The XMP-Series controller supports some user data to be copied during Events
 and then later retrieved from the Host via the Notify object.

There are MEIXmpSignalUserData words of data for the motion, axis and motor
 event sources.  The default configuration for the first word is the XMP's
 sampleCounter.  The default for the second word is "actualPosition" for axis
 event sources, and "encoderPosition" for motor event sources.

In this sample, the second word for motion and axis events is configured for "id".

Note:  Keeping the first word configured for the "sampleCounter" is very
 helpful in determining event sequences.

Here is the default configuration for the event data:

    union {
        long sampleCounter;
        struct {
            long sampleCounter;
        } motion;
        struct {
            long sampleCounter;
            long actualPosition;
        } axis;
        struct {
            long sampleCounter;
            long encoderPosition;
        } motor;
        long word[MEIXmpSignalUserData];
    } data;

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motId2Main

argMainRENAME(main, motId2)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0,   };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Motion Parameters */
double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  },
    { 0.0,      },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent*/
        { 10000.0,      100000.0,   100000.0,   0.0,    },
    },
};

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis object */
    MPIMotion   motion;     /* motion object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    MEIEventNotifyData  motionData;
    MEIXmpAxis          *xmpAxis;

    long    returnValue;    /* return value from library */

    long    index;
    long    moveId;     /* identification tag */
    long    motionDone; /* flag when Done occurs */

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Get current user data configuration */
    mpiEventMaskCLEAR(eventMask);
    returnValue =
        mpiMotionEventNotifyGet(motion,
                                &eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Request notification of ALL events from motion */
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Request ID data from motion event info[...] */
    returnValue  =
        mpiAxisMemory(axis,     /* use ID from first axis in motion object */
                      &(void *)xmpAxis);
    msgCHECK(returnValue);

    motionData.address[1] = (void *)(&xmpAxis->MoveID);

    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Configure sampleCounter and ID to be returned from Axis event sources */
    returnValue =
        mpiAxisEventNotifySet(axis,
                              eventMask,    /* use the same eventMask as motion */
                              &motionData); /* use the same data as motion */
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index       = 0;
    moveId      = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        if (motionDone) {
            MPIMotionParams     motionParams;       /* motion parameters */

            /* fill in the MPIMotionParams structure */
            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            motionParams.attributes.id = moveId;    /* identification tag */

            returnValue =
                mpiMotionStart(motion,
                               (MPIMotionType)(motionType | MPIMotionAttrMaskID),
                               &motionParams);
            msgCHECK(returnValue);

            printf("\n\nMotion Start #%d...\n", moveId);

            moveId++;

            motionDone = FALSE;
        }

        /* Wait for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        info = (MEIEventStatusInfo *)eventStatus.info;

        switch (eventStatus.type) {
            /* In Coarse Event from axis source */
            case MEIEventTypeIN_POSITION_COARSE: {
                printf("  InCoarse #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeIN_POSITION_FINE: {
                printf("  InFine #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeAT_TARGET: {
                printf("  AtTarget #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* Motion Done Event from motion source */
            case MPIEventTypeMOTION_DONE: {
                printf("  Done #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.motion.sampleCounter);

                motionDone = TRUE;

                if (++index >= MOTION_COUNT) {
                    index = 0;
                }
                break;
            }
            default: {
                printf("  %d #%ld(%ld)",
                       eventStatus.type,
                       info->data.word[1],
                       info->data.word[0]);
                break;
            }
        }
    }

    printf("\n");

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motid3.c -- Point to Point motion with ID, APPEND, and HOLD attributes

.

motid3.c -- Point to Point motion with ID, APPEND, and HOLD attributes.
/* motId3.c */

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

/*

:Point to Point motion with ID, APPEND, and HOLD attributes.

The MPI supports a motion attribute that allows an application to tag
 a mpiMotionStart(...) or mpiMotionModify(...) with an identification
 value.

This feature is useful in tracking the commanded motions to the done
 events.  It is also applicable when using the AUTO_START attribute
 with mpiMotionModify(...).

For example:

Suppose mpiMotionStart(...) is called with the MPIMotionAttrMaskID attribute,
 and the params.attributes.id = 1 and later mpiMotionModify(...) is called
 with params.attributes.id = 2.

Case 1: MPIMotionAttrAUTO_START is not used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageIDLE, there will be 1 DONE
 event with info->data.motion.id = 1.

Case 2: MPIMotionAttrAUTO_START is used.
if mpiMotionModify(...) returns MPIMessageOK, there will be 1 DONE event
 with info->data.motion.id = 2.
if mpiMotionModify(...) returns MPIMotionMessageAUTO_START,
 there will be 2 DONE events. The first will have info->data.motion.id = 1
 and the second will have info->data.motion.id = 2.

The XMP-Series controller supports some user data to be copied during Events
 and then later retrieved from the Host via the Notify object.

There are MEIXmpSignalUserData words of data for the motion, axis and motor
 event sources.  The default configuration for the first word is the XMP's
 sampleCounter.  The default for the second word is "actualPosition" for axis
 event sources, and "encoderPosition" for motor event sources.

In this sample, the second word for motion and axis events is configured for "id".

Note:  Keeping the first word configured for the "sampleCounter" is very
 helpful in determining event sequences.

Here is the default configuration for the event data:

    union {
        long sampleCounter;
        struct {
            long sampleCounter;
        } motion;
        struct {
            long sampleCounter;
            long actualPosition;
        } axis;
        struct {
            long sampleCounter;
            long encoderPosition;
        } motor;
        long word[MEIXmpSignalUserData];
    } data;

The APPEND attribute is useful for buffering moves in the controller.
 When the APPEND attribute is used with mpiMotionStart(...), a new motion
 profile is added to the end of any previously loaded motion profiles in
 the controller.  The XMP-Series controller automatically buffers the APPENDed
 MotionStarts, executing each sequentially after the Motion Done criteria has
 been met for each profile.  Each MotionStart profile generates a Motion Done
 event to the Host.

When APPEND attribute is used with mpiMotionModify(...), the motion profile
 is added to the end of any previously loaded motion profiles in the
 controller.  The XMP-Series controller automatically buffers the APPENDed
 MotionModifies, executing each sequentially.  Only the very last
 MotionModify waits for the Motion Done criteria to be met before generating
 a Motion Done event to the host.

The XMP-Series controller supports a motion HOLD attribute, which is useful
 for preloading and triggering motion profiles.  One or more motion
 supervisors can be started from the same HOLD conditions.  When multiple
 motion supervisors are triggered by the same HOLD conditions, the individual
 motion profiles will start in the same DSP sample period.  The HOLD can be
 set/cleared with a host function call, an XMP-Series controller internal
 variable or a Motor I/O state change.

The MEIMotionAttrHold{...} structure is used to configure the HOLD conditions:

 typedef    struct MEIMotionAttrHold {
    MEIMotionAttrHoldType   type;
    MEIMotionAttrHoldSource source;

    float   timeout;
} MEIMotionAttrHold;

The HOLD "type" can be one of the following:

 MEIMotionHoldTypeGATE - host software controlled.
 MEIMotionHoldTypeINPUT - XMP controller internal variable.
 MEIMotionHoldTypeMOTOR - XMP controller motor I/O state change.

For each HOLD "type" the "source" union, MEIMotionAttrHoldSource{...},
 configures the HOLD conditions:

 MEIMotionHoldTypeGATE:

  long gate - number between 0 to 31.

  The motion is held until the "gate" is cleared.  The function
  meiControlGateSet(...) is used to set/clear a gate.  When the closed
  parameter is TRUE, the gate is set, and motion is held.  When the
  closed parameter is FALSE, the gate is cleared, and motion starts.

 MEIMotionHoldTypeINPUT

  long *input - address of XMP memory location.
  long mask - bit mask, bitwise ANDed with the input value.
  long pattern - HOLD is released when masked value matches pattern.

  The motion is held until the value of the internal XMP memory location
  (pointed to by *input) bitwise ANDed with the mask matches the pattern.

 MEIMotionHoldTypeMOTOR

  long number - motor "n", XMP's dedicated inputs (Motor[n].IO.DedicaedIN.IO)
  long mask - bit mask, bitwise ANDed with the dedicated inputs.
  long pattern - HOLD is released when masked inputs matches pattern.

  The motion is held until the value of the dedicated input word
  (Motor[n].IO.DedicaedIN.IO) bitwise ANDed with the mask matches the
  pattern.

The HOLD "timeout" will cause the motion to start after the specified period
 (in seconds) even if the hold criteria have not been met.  To disable the
 timeout feature, set the timeout value to zero.

The MPI expects an array of hold attributes specifying separate attributes
 form each axis of a motion supervisor. All axes holding with the same hold
 attributes (same gate, same input, mask, and pattern) will start motion in
 the same sample even if the moves are specified using different motion
 supervisors.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motionId3Main

argMainRENAME(main, motionId3)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (1)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0,   };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;
long            gateNumber = 0;
float           gateTimeout = (float)0.0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },
    {   "-gate",    ArgTypeLONG,    &gateNumber,    },
    {   "-timeout", ArgTypeFLOAT,   &gateTimeout,   },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Motion Parameters */
double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  },
    { 0.0,      },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent*/
        { 10000.0,      100000.0,   100000.0,   0.0,    },
    },
};

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis object */
    MPIMotion   motion;     /* motion object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    MEIEventNotifyData  motionData;
    MEIXmpAxis          *xmpAxis;

    MPIMotionParams     motionParams;   /* motion parameters */
    MEIMotionAttributes attributes;     /* motion attributes */
    MEIMotionAttrHold   hold;           /* hold attribute configuration */

    long    returnValue;    /* return value from library */

    long    index;
    long    moveId;     /* identification tag */
    long    motionDone; /* flag when Done occurs */

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST) ||
        (gateNumber < 0) ||
        (gateNumber >= MEIXmpMaxGates) ||
        (gateTimeout < 0.0)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n"
                           "\t\t[-gate # (0 .. %d)]\n"
                           "\t\t[-timeout # (0.0 ..)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1,
                            MEIXmpMaxGates - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Get current user data configuration */
    mpiEventMaskCLEAR(eventMask);
    returnValue =
        mpiMotionEventNotifyGet(motion,
                                &eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Request notification of ALL events from motion */
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Request ID data from motion event info[...] */
    returnValue  =
        mpiAxisMemory(axis,     /* use ID from first axis in motion object */
                      &(void *)xmpAxis);
    msgCHECK(returnValue);

    /* Configure the second user data word for the ID */
    motionData.address[1] = (void *)(&xmpAxis->MoveID);

    /* Configure sampleCounter and ID to be returned from Motion event sources */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                &motionData);
    msgCHECK(returnValue);

    /* Configure sampleCounter and ID to be returned from Axis event sources */
    returnValue =
        mpiAxisEventNotifySet(axis,
                              eventMask,    /* use the same eventMask as motion */
                              &motionData); /* use the same data as motion */
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    /* Configure Motion Attributes */
    hold.type = MEIMotionAttrHoldTypeGATE;  /* software motion Gate control */
    hold.source.gate = gateNumber;
    hold.timeout = gateTimeout;

    attributes.hold = &hold;
    motionParams.external = &attributes;

    printf("Press any key to stop ...\n");

    /* Loop repeatedly */
    index       = 0;
    moveId      = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        if (motionDone) {

            /* Set a control gate to prevent motion profile from executing */
            returnValue =
                meiControlGateSet(control,
                                  gateNumber,
                                  TRUE);    /* set gate */
            msgCHECK(returnValue);

            for (index = 0; index < MOTION_COUNT; index++) {
                /* fill in the MPIMotionParams structure */
                switch (motionType) {
                    case MPIMotionTypeS_CURVE: {
                        motionParams.sCurve = sCurve[index];
                        break;
                    }
                    case MPIMotionTypeTRAPEZOIDAL: {
                        motionParams.trapezoidal = trapezoidal[index];
                        break;
                    }
                    case MPIMotionTypeVELOCITY: {
                        motionParams.velocity = velocity[index];
                        break;
                    }
                    default: {
                        meiASSERT(FALSE);
                        break;
                    }
                }

                motionParams.attributes.id = moveId;    /* identification tag */

                returnValue =
                    mpiMotionStart(motion,
                                   (MPIMotionType)(motionType |
                                   MPIMotionAttrMaskID |
                                   MPIMotionAttrMaskAPPEND |
                                   MEIMotionAttrMaskHOLD),
                                   &motionParams);
                msgCHECK(returnValue);

                printf("\nMotion Start #%d...\n", moveId);

                moveId++;
            }

            /* Clear a control gate, executing the preloaded motion */
            returnValue =
                meiControlGateSet(control,
                                  gateNumber,
                                  FALSE);   /* clear the gate */
            msgCHECK(returnValue);

            index = 0;
            motionDone = FALSE;
        }

        /* Wait for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        info = (MEIEventStatusInfo *)eventStatus.info;

        switch (eventStatus.type) {
            /* In Coarse Event from axis source */
            case MEIEventTypeIN_POSITION_COARSE: {
                printf("  InCoarse #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeIN_POSITION_FINE: {
                printf("  InFine #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeAT_TARGET: {
                printf("  AtTarget #%ld(%ld)",
                       info->data.word[1],      /* user configurable data */
                       info->data.axis.sampleCounter);
                break;
            }
            /* Motion Done Event from motion source */
            case MPIEventTypeMOTION_DONE: {
                printf("  Done #%ld(%ld)\n",
                       info->data.word[1],
                       info->data.motion.sampleCounter);

                if (++index >= MOTION_COUNT) {
                    index = 0;
                    motionDone = TRUE;
                }
                break;
            }
            default: {
                printf("  %d #%ld(%ld)",
                       eventStatus.type,
                       info->data.word[1],
                       info->data.word[0]);
                break;
            }
        }
    }

    printf("\n");

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motion1.c -- Perform point to point trapezoidal profile motion.

.

motion1.c -- Perform point to point trapezoidal profile motion.
/* motion1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    motion1Main

argMainRENAME(main, motion1)
#endif

/*

:Perform point to point trapezoidal profile motion.

This is a simple program to demonstrate how to start a trapezoidal profile
 motion on a single axis.  There is a minimal error checking in this sample.

Warning!  This is a sample program to assist in the longegration 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 <math.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)

#define GOAL_POSITION   (50000)
#define VELOCITY        (5000)
#define ACCELERATION    (10000)
#define DECELERATION    (20000)

/* 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,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber)
{
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,       /* motion supervisor number */
                        *axis);             /* axis object handle */
    msgCHECK(mpiMotionValidate(*motion));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl      *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis)
{
    long    returnValue;

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/* Command simple trapezoidal motion */
long simpleTrapMove(MPIMotion   motion,
                    double      goalPosition,
                    double      velocity,
                    double      acceleration,
                    double      deceleration)
{
    MPIMotionParams     params;     /* Motion parameters      */
    MPITrajectory       trajectory; /* Trajectory information */

    long returnValue;               /* MPI library return value */

    /* Setup trajectory structure */
    trajectory.velocity     = velocity;
    trajectory.acceleration = acceleration;
    trajectory.deceleration = deceleration;

    /* Setup parameters structure */
    params.trapezoidal.trajectory   = &trajectory;
    params.trapezoidal.position     = &goalPosition;

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);

    return returnValue;
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller object handle */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;     /* motion object handle */
    MPIAxis             axis;       /* axis object handle */

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER);

    /* Command simple motion */
    simpleTrapMove(motion,
                   GOAL_POSITION,
                   VELOCITY,
                   ACCELERATION,
                   DECELERATION);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motion,
                   &axis);

    return MPIMessageOK;
}


motion2.c -- Two-axis motion, with synchronized and coordinated S-Curve

.

motion2.c -- Two-axis motion, with synchronized and coordinated S-Curve profiles.
/* motion2.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Two-axis motion, with synchronized and coordinated S-Curve profiles.

This sample demonstrates how to create a two-axis motion system, using
 a single motion object.  Simple point to point motion is commanded
 using S-Curve (or Trapezoidal) profile.

When motion is commanded to point 0, using the MPIMotionAttrMaskSYNC_START
 attribute, the controller starts the motion profiles for both axes at the
 same time.  Each axis uses it's own MPITrajectory, independently reaching
 their target positions at different times.

When motion is commanded to point 1, (no attributes), the controller
 starts and completes the motion profiles for the axes at the same time.
 Each axis shares a single MPITrajectory, by breaking the vector trajectory
 values into component trajectory values based on the ratio of the axis
 distances.  The result is point to point linear coordinated move for the
 axes, specified by a target "position" for each axis and a single vector
 "trajectory" for the axes.

During motion, the motion status is polled from the controller.  When both
 axes complete their motions (state = IDLE), the command and actual positions,
 and motion status information is displayed.

If an error condition occurs during motion, the program clears the error
 using mpiMotionAction(motion, MPIActionRESET).

Note:  When multiple axes are associated with a motion supervisor, the
 controller automatically combines the individual axis and motor status
 into the motion status.  Thus, if a Stop, E-Stop or Abort action occurs
 on one axis, the event will be propogated automatically to the other axes.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motion2Main

argMainRENAME(main, motion2)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Motion Parameters */
double position[MOTION_COUNT][AXIS_COUNT] = {
    { 2000.0,   20000.0,    },
    { 0.0,      0.0,        },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

long
    motionIdle(MPIMotion    motion,
               MPIStatus    *status);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axisX;      /* X axis */
    MPIAxis     axisY;      /* Y axis */
    MPIMotion   motion;     /* motion object */

    long    returnValue;    /* return value from library */

    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create X axis object using axis number 0 on controller*/
    axisX =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axisX));

    /* Create Y axis object using axis number 1 on controller */
    axisY =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axisY));

    /* Create motion object */
    /* Append X axis to motion */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axisX);
    msgCHECK(mpiMotionValidate(motion));

    /* Append Y axis to motion */
    returnValue =
        mpiMotionAxisAppend(motion,
                            axisY);
    msgCHECK(returnValue);

    /* Loop repeatedly */
    index = 0;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        long    motionDone;

        if (returnValue == MPIMessageOK) {
            MPIMotionType   type;
            MPIMotionParams motionParams;

            type = motionType;

            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    if (index == 0) {
                        type = (MPIMotionType)(type | MPIMotionAttrMaskSYNC_START);
                    }
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    if (index == 0) {
                        type = (MPIMotionType)(type | MPIMotionAttrMaskSYNC_START);
                    }
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            printf("\nMotionStart...");

            returnValue =
                mpiMotionStart(motion,
                               type,
                               &motionParams);

            if (returnValue != MPIMessageOK) {
                printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                       motion,
                       type,
                       &motionParams,
                       returnValue,
                       mpiMessage(returnValue, NULL));
            }
        }

        /* Poll status until motion done */
        motionDone = FALSE;
        while (motionDone == FALSE) {
            MPIStatus   status;

            returnValue =
                mpiMotionStatus(motion,
                                &status,
                                NULL);
            msgCHECK(returnValue);

            switch (status.state) {
                case MPIStateIDLE: {
                    motionDone = TRUE;

                    motionIdle(motion,
                               &status);

                    /* Wait for the motor to settle */
                    meiPlatformSleep(300);  /* msec */

                    break;
                }
                case MPIStateERROR: {
                    motionDone = TRUE;

                    /* Clear any error condition(s) */
                    returnValue =
                        mpiMotionAction(motion,
                                        MPIActionRESET);
                    msgCHECK(returnValue);

                    /* Wait for reset to take effect */
                    meiPlatformSleep(100);      /* msec */

                    break;
                }
                default: {
                    break;
                }
            }
        }

        if (++index >= MOTION_COUNT) {
            index = 0;
        }
    }

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisX);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long motionIdle(MPIMotion motion,
                MPIStatus *status)
{
    long    returnValue;

    double  actual[AXIS_COUNT];
    double  command[AXIS_COUNT];

    long    index;

    printf("MotionDone: status: state %d action %d eventMask 0x%x\n"
           "\tatTarget %d settled %d %s\n",
            status->state,
            status->action,
            status->eventMask,
            status->atTarget,
            status->settled,
            (status->settled == FALSE)
                    ? "=== NOT SETTLED ==="
                    : "");

    returnValue =
        mpiMotionPositionGet(motion,
                             actual,
                             command);
    msgCHECK(returnValue);

    /* Display axis positions */
    for (index = 0; index < AXIS_COUNT; index++) {
        printf("\taxis[%d]    position: command %11.3lf\tactual %11.3lf\n",
                index,
                command[index],
                actual[index]);
    }

    return (returnValue);
}


motion3.c -- Custom point to point S-curve motion with velocity specified

.

motion3.c -- Custom point to point S-curve motion with velocity specified using position.
/* motion3.c */

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

/*

:Custom point to point S-curve motion with velocity specified using position.

This program demonstrates how to generate a point to point move using a custom
 velociy profile. The motion profile is specified by a structure called
 moveData[...] containing positions, velocities, and jerk percents.
 The motion is commanded using:

  1) mpiMotionStart(...) with the FINAL_VEL attribute, which loads the first
     point and begins motion.

  2) mpiMotionModify(...) with the FINAL_VEL and APPEND attribute, which adds
     the rest of the motion profiles to the end of the first profile.

The resultant motion profile will reach the "midVelocity" at the specified
 "midPosition" and the "endVelocity" at the specified "endPosition."
 MOVE_SEGMENTS is defined by the size of moveData[...].

The following equation was used to determine accelerations and decelerations.

  acceleration = (velocity1^2 - velocity0^2) / (2 * (position1 - position2))

There is a minimal error checking in this sample.

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 <math.h>

#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motion3Main

argMainRENAME(main, motion3)
#endif

#define AXIS_NUMBER         (0)     /* Axis to be moved */
#define MOTION_NUMBER       (0)     /* Motion supervisor number */
#define JERK_PERCENT        (100.0)

long    axisNumber      = 0;
long    motionNumber    = 0;

struct {
    double  midposition;
    double  endPosition;
    double  midVelocity;
    double  endVelocity;
    double  jerkPercent;

} moveData[] =  {

/*  midposition,    endPosition,    midVel,     endVel, jerkPercent */
    {1200,          3000,           27000.0,    3000.0,     JERK_PERCENT,   },
    {4200,          6000,           15000.0,    3000.0,     JERK_PERCENT,   },
    {8900,          11300,          44000.0,    0.0,        JERK_PERCENT,   },

/*
    {6000,          0,              15000.0,    0.0,        JERK_PERCENT,   },
   Add additional points like the above line
*/

};

Arg argList[] = {
    {   NULL,       ArgTypeINVALID, NULL,   }
};

#define MOVE_SEGMENTS (sizeof(moveData)/sizeof(moveData[0]))

long    parseCommandLine(int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress);

long    createObjects(MPIControl            *control,
                      MPIAxis               *axis,
                      MPIMotion             *motion,
                      MPIControlType        *controlType,
                      MPIControlAddress     *controlAddress,
                      long                  axisNumber);

long    deleteObjects(MPIControl    *control,
                      MPIAxis       *axis,
                      MPIMotion     *motion);

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

    MPIControl          control;        /* Motion controller object handle */
    MPIMotion           motion;         /* Motion object handle */
    MPIAxis             axis;           /* Axis object handle */
    MPIMotionParams     params;         /* Motion parameters */
    MPITrajectory       trajectory;     /* Motion trajectory */
    MEIMotionAttributes attributes;     /* Motion attributes */
    MPIMotionAttrMask   attrMask;       /* Motion attributes mask */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    returnValue;
    long    segmentCount;
    double  endPosition;

    parseCommandLine(argc,
                     argv,
                     &controlType,
                     &controlAddress);

    createObjects(&control,
                  &axis,
                  &motion,
                  &controlType,
                  &controlAddress,
                  axisNumber);

    segmentCount = 0;
    moveData[-1].endVelocity = 0;
    moveData[-1].endPosition = 0;

    while (segmentCount < MOVE_SEGMENTS){
        /* Setup new motion parameters */
        attrMask =
            MPIMotionAttrMaskAPPEND |
            MEIMotionAttrMaskFINAL_VEL;

        endPosition              =  moveData[segmentCount].endPosition;
        trajectory.velocity      =  moveData[segmentCount].midVelocity;
        attributes.finalVelocity = &moveData[segmentCount].endVelocity;

    /*
       Acceleration = (velocity1^2 - velocity0^2) / (2 * (position1 - position2))
       Point 0 is 'endPosition' of the previous move. Point 1 is 'midposition'.
    */

        trajectory.acceleration  =
            fabs(((pow(moveData[segmentCount].midVelocity, 2) -
            pow(moveData[segmentCount - 1].endVelocity, 2)) /
            (2 * (moveData[segmentCount].midposition -
            moveData[segmentCount - 1].endPosition))));

    /*
       Acceleration = (velocity1^2 - velocity0^2) / (2 * (position1 - position2))
       Point 0 is 'midposition'. Point 1 is 'endPosition'.
    */

        trajectory.deceleration  =
            fabs(((pow(moveData[segmentCount].endVelocity, 2) -
            pow(moveData[segmentCount].midVelocity, 2)) /
            (2 * (moveData[segmentCount].endPosition -
            moveData[segmentCount].midposition))));

        trajectory.jerkPercent   =  moveData[segmentCount].jerkPercent;

        if (!segmentCount){
            /* First point */
            params.sCurve.position   = &endPosition;
            params.sCurve.trajectory = &trajectory;
            params.external = &attributes;
            /* Start motion */
            returnValue =
                mpiMotionStart(motion,
                               MPIMotionTypeS_CURVE | attrMask,
                               &params);
            msgCHECK(returnValue);
        }
        else{   /* Not first point */
            /* Modify motion */
            returnValue =
                mpiMotionModify(motion,
                                MPIMotionTypeS_CURVE | attrMask,
                                &params);
            msgCHECK(returnValue);
        }
        segmentCount++;
    }

    deleteObjects(&control,
                  &axis,
                  &motion);

    return (returnValue);
}

long    parseCommandLine(int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   controlType,
                   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)) ||
        (motionNumber  >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

long    createObjects(MPIControl            *control,
                      MPIAxis               *axis,
                      MPIMotion             *motion,
                      MPIControlType        *controlType,
                      MPIControlAddress     *controlAddress,
                      long                  axisNumber)
{

    long    returnValue;

    /* Create motion controller object*/
    *control =
        mpiControlCreate(*controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the motion controller */
    returnValue = mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Create axis object*/
    *axis =
        mpiAxisCreate(*control,
                      AXIS_NUMBER);     /* Axis number */
    msgCHECK(mpiAxisValidate(*axis));

    /* Create motion object, append axis */
    *motion =
        mpiMotionCreate(*control,
                        MOTION_NUMBER,  /* Motion supervisor number */
                        *axis);         /* Axis object handle */
    msgCHECK(mpiMotionValidate(*motion));

    returnValue =
        mpiMotionAxisListSet(*motion,
                             1,
                             axis);
    msgCHECK(returnValue);

    return returnValue;
}

long    deleteObjects(MPIControl    *control,
                      MPIAxis       *axis,
                      MPIMotion     *motion)
{

    long returnValue;

    /* Object clean-up */
    returnValue = mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(*control);
    msgCHECK(returnValue);

    return returnValue;
}


motmap1.c -- Motion object and Motion Supervisor axis map configuration.

.

motmap1.c -- Motion object and Motion Supervisor axis map configuration.
/* motMap1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Motion object and Motion Supervisor axis map configuration.

The MPI supports Motion objects and Axis objects which reside in the
 host computer.  Several Motion objects can be created and associated
 with single or multiple Axis objects.  Additionally, several Motion
 objects can be configured to share one or more Axis objects.

The XMP controller has Motion Supervisors and Axes.  The controller's
 Motion Supervisors can be associated with a single axis or multiple axes.
 Additionally, several Motion Supervisors can be configured to share
 one or more axes.

When multiple axes are configured for a Motion Supervisor, the controller
 automatically manages the status and error conditions.  For example, if
 a Motion Supervisor is configured with two axes, and one of the axes faults
 with a position error limit, causing an Abort Event, the Motion Supervisor
 will generate Abort Event on the other axis.

Some care must be used with Motion Supervisor axis map configurations when
 axes are shared between Motion Supervisors.  Since the Error conditions
 are automatically proliferated across mapped axes, it is possible to create
 Motion Supervisor axis maps that generate Error conditions that cannot be
 cleared.  For example, if MS#0 is mapped to axes 0 and 1, and MS#1 is mapped
 to axis 0.  MS#1 will NOT be able to clear Error conditions.  Only MS#0 will
 be able to clear Error conditions on axes 0 and 1.

Motion Supervisor axis maps are set with any of the following methods:

1)  mpiMotionAction(...) with the MEIActionMAP or MPIActionRESET
2)  mpiMotionStart(...)
3)  mpiMotionModify(...)
4)  mpiMotionEventNotifySet(...)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motMap1Main

argMainRENAME(main, motMap1)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)
#define MS_COUNT        (4)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber[MS_COUNT] = { 0, 1, 2, 3,  };
MPIMotionType   motionType  = MPIMotionTypeS_CURVE;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber[0],   },
    {   "-type",    ArgTypeLONG,    &motionType,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 10000.0,  20000.0,    },
    { 0.0,      0.0,        },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent  */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

/* Motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

long
    motionDoneWait(MPIMotion motion);

long
    motionIdle(MPIMotion    motion,
               MPIStatus    *status);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* Motion controller handle */
    MPIAxis     axisX;      /* X axis */
    MPIAxis     axisY;      /* Y axis */

    MPIMotion   motion;     /* Motion object for no axes */
    MPIMotion   motionX;    /* Motion object for axisX */
    MPIMotion   motionY;    /* Motion object for axisY */
    MPIMotion   motionXY;   /* Motion object for axisX and axisY */

    enum {
        Motion,
        MotionX,
        MotionY,
        MotionXY,
    };

    long    index;

    long    returnValue;    /* Return value from library */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]   > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber[0] > (MEIXmpMAX_MSs - MS_COUNT)) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - MS_COUNT,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    motionNumber[1] = motionNumber[0] + 1;
    motionNumber[2] = motionNumber[1] + 1;
    motionNumber[3] = motionNumber[2] + 1;

    /* Create control object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create X axis object using AXIS_X number on controller */
    axisX =
        mpiAxisCreate(control,
                      axisNumber[0]);       /* Axis Number */
    msgCHECK(mpiAxisValidate(axisX));

    /* Create Y axis object using AXIS_Y number on controller */
    axisY =
        mpiAxisCreate(control,
                      axisNumber[1]);       /* Axis Number */
    msgCHECK(mpiAxisValidate(axisY));

    /* Create Motion object with NO axes */
    motion =
        mpiMotionCreate(control,
                        motionNumber[Motion],   /* Motion supervisor number */
                        NULL);
    msgCHECK(mpiMotionValidate(motion));

    /* Create Motion object for axisX */
    motionX =
        mpiMotionCreate(control,
                        motionNumber[MotionX],      /* Motion supervisor number */
                        axisX);
    msgCHECK(mpiMotionValidate(motionX));

    /* Create Motion object for axisY */
    motionY =
        mpiMotionCreate(control,
                        motionNumber[MotionY],      /* Motion supervisor number */
                        axisY);
    msgCHECK(mpiMotionValidate(motionY));

    /* Motion object for axisX and axisY */
    motionXY =
        mpiMotionCreate(control,
                        motionNumber[MotionXY],     /* Motion supervisor number */
                        axisX);
    msgCHECK(mpiMotionValidate(motionXY));

    /* Append axisY to motionXY */
    returnValue =
        mpiMotionAxisAppend(motionXY,
                            axisY);
    msgCHECK(returnValue);

    /* Map X axis to Motion Supervisor */
    returnValue =
        mpiMotionAction(motionX,        /* Axis X, using MotionX */
                        (MPIAction)MEIActionMAP);   /* Map axis to Motion Supervisor */
    msgCHECK(returnValue);

    /* Map Y axis to Motion Supervisor */
    returnValue =
        mpiMotionAction(motionY,        /* Axis Y, using MotionY */
                        (MPIAction)MEIActionMAP);   /* Map axis to Motion Supervisor */
    msgCHECK(returnValue);

    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIMotionParams motionParams;

        /* Clear any error conditions on axisX */
        returnValue =
            mpiMotionAction(motionX,
                            (MPIAction)MPIActionRESET);
        msgCHECK(returnValue);

        index = 0;

        /* Move axisX to position #1 */

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        printf("\nMoving X axis...\n");

        returnValue =
            mpiMotionStart(motionX,
                           motionType,
                           &motionParams);

        if (returnValue != MPIMessageOK) {
            printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                   motionX,
                   motionType,
                   &motionParams,
                   returnValue,
                   mpiMessage(returnValue, NULL));
        }

        /* Wait for motion to complete */
        returnValue = motionDoneWait(motionX);
        msgCHECK(returnValue);

        /* Clear any error conditions on axisY */
        returnValue =
            mpiMotionAction(motionY,
                            MPIActionRESET);
        msgCHECK(returnValue);

        /* Move axisY to position #1 */

        printf("\nMoving Y axis...\n");

        returnValue =
            mpiMotionStart(motionY,
                           motionType,
                           &motionParams);

        if (returnValue != MPIMessageOK) {
            printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                   motionY,
                   motionType,
                   &motionParams,
                   returnValue,
                   mpiMessage(returnValue, NULL));
        }

        /* Wait for motion to complete */
        returnValue = motionDoneWait(motionY);
        msgCHECK(returnValue);

        /* Configure Motion Supervisor Map for X,Y */
        returnValue =
            mpiMotionAction(motionXY,       /* Axes X and Y, using MotionXY */
                            (MPIAction)MEIActionMAP);   /* Map axes to Motion Supervisor */
        msgCHECK(returnValue);

        /* Clear any error conditions on AxisX and AxisY */
        returnValue =
            mpiMotionAction(motionXY,
                            MPIActionRESET);
        msgCHECK(returnValue);

        index = 1;

        /* Move axisX and axisY to position #2 */

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams.sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams.trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams.velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        printf("\nMoving X and Y axes...\n");

        returnValue =
            mpiMotionStart(motionXY,
                           motionType,
                           &motionParams);

        if (returnValue != MPIMessageOK) {
            printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                   motionXY,
                   motionType,
                   &motionParams,
                   returnValue,
                   mpiMessage(returnValue, NULL));
        }

        /* Wait for motion to complete */
        returnValue = motionDoneWait(motionXY);
        msgCHECK(returnValue);

        /* Un-configure the controller's XY Motion Supervisor */
        returnValue =
            mpiMotionAction(motion,         /* Motion object has NO axes */
                            (MPIAction)MEIActionMAP);   /* Set a Motion Supervisor map of no axes */
        msgCHECK(returnValue);
    }

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motionX);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motionY);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motionXY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisX);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long
    motionDoneWait(MPIMotion motion)
{
    MPIStatus   status;

    long returnValue;

    long motionDone = FALSE;

    /* Poll status until motion done */
    while (motionDone == FALSE) {
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateIDLE: {
                motionDone = TRUE;

                returnValue =
                    motionIdle(motion,
                               &status);

                meiPlatformSleep(300);  /* msec */

                break;
            }
            case MPIStateERROR: {
                motionDone = TRUE;

                printf("Motion State Error!\n");

                break;
            }
            default: {
                break;
            }
        }
    }

    return (returnValue);
}

long
    motionIdle(MPIMotion    motion,
               MPIStatus    *status)
{
    long    returnValue;

    double          actual[AXIS_COUNT];
    double          command[AXIS_COUNT];
    MPITrajectory   trajectory[AXIS_COUNT];

    long    index;

    printf("MotionDone: status: state %d action %d eventMask 0x%x\n"
           "\tatTarget %d settled %d %s\n",
            status->state,
            status->action,
            status->eventMask,
            status->atTarget,
            status->settled,
            (status->settled == FALSE)
                    ? "=== NOT SETTLED ==="
                    : "");

    returnValue =
        mpiMotionPositionGet(motion,
                             actual,
                             command);
    msgCHECK(returnValue);

    returnValue =
        mpiMotionTrajectory(motion,
                            trajectory);
    msgCHECK(returnValue);

    /* Display axis positions */
    for (index = 0; index < AXIS_COUNT; index++) {
        printf("\taxis[%d]    position: command %11.3lf\tactual %11.3lf\n",
                index,
                command[index],
                actual[index]);
        printf("\t\ttrajectory: velocity %11.3lf\taccel  %11.3lf\tjerk %11.3lf\n",
                trajectory[index].velocity,
                trajectory[index].acceleration,
                trajectory[index].jerkPercent);
    }

    return (returnValue);
}


motmap2.c -- Motion object and Motion Supervisor Axis mapping with

.

motmap2.c -- Motion object and Motion Supervisor Axis mapping with events
/* motMap2.c  */

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

/*

:Motion object and Motion Supervisor Axis mapping with events

This sample code performs the following operation:
 -Map axis 0 to motion object 'motion'.
 -Move axis 0 to position.
 -Wait for an event based upon motion done on axis 0
 -Move axis 1 to position
 -Wait for an event based upon motion done on axis 1
 -Map axis 0 and axis 1 to 'motion'
 -Coordinated move on axis 0 and axis 1 back to position (0,0).

Only one Motion Supervisor and Motion object is used and remapped after
 each move.

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 <windows.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motMap2Main

argMainRENAME(main, motMap2)
#endif

#define AXIS_COUNT      (2)
#define MS_COUNT        (1)
#define MOTION_COUNT    (3)
#define COUNT           (100)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionSupNumber[MS_COUNT] = { 0,};

MPIMotionType   motionType  = MPIMotionTypeS_CURVE;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionSupNumber[0], },
    {   "-type",    ArgTypeLONG,    &motionType, },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 10000.0,},
    { 10000.0,},
    { 0.0,},
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent  */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

/* Motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
    {   &trajectory[2][0],  &position[2][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
    {   &trajectory[2][0],  &position[2][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
    {   &trajectory[2][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;                /* Motion controller handle */
    MPIAxis         axisList[AXIS_COUNT];   /* Axis handle(s) */
    MPIMotion       motion;                 /* Motion object */

    MPIMotionParams motionParams;

    MPINotify       notify;                 /* event notification object */
    MPIEventMgr     eventMgr;               /* event manager handle */

    MPIEventMask    eventMask;
    MPIEventStatus  eventStatus;

    long        returnValue;    /* Return value from library */
    long        argIndex;
    Service     service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]   > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionSupNumber[0] > (MEIXmpMAX_MSs - MS_COUNT)) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - MS_COUNT,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create control object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    axisNumber[1] = axisNumber[0] + 1;

    /* Create axis object using axisNumber on controller */
    axisList[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axisList[0]));

    /* Create axis object using axisNumber on controller  */
    axisList[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axisList[1]));

    /* Create motion object motion for axisList[0] */
    motion =
        mpiMotionCreate(control,
                        0,                  /* Motion supervisor number */
                        axisList[0]);
    msgCHECK(mpiMotionValidate(motion));

    /* Create event notification object for events from all sources */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);
    notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(notify));

    /* Create event manager object */
    eventMgr =
        mpiEventMgrCreate(control);
    msgCHECK(mpiEventMgrValidate(eventMgr));

    /* Flush any existing events */
    returnValue =
        mpiEventMgrFlush(eventMgr);
    msgCHECK(returnValue);

    /* Add notify to event manager's list */
    returnValue =
        mpiEventMgrNotifyAppend(eventMgr,
                                notify);
    msgCHECK(returnValue);

    /* Request notification of events from motion */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create service thread */
    service =
        serviceCreate(eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    meiASSERT(service != NULL);

    /* Clear any error conditions on motion */
    returnValue =
        mpiMotionAction(motion,
                        MPIActionRESET);
    msgCHECK(returnValue);

    /* Move axis 0 */
    switch (motionType) {
        case MPIMotionTypeS_CURVE: {
            motionParams.sCurve = sCurve[0];
            break;
        }
        case MPIMotionTypeTRAPEZOIDAL: {
            motionParams.trapezoidal = trapezoidal[0];
            break;
        }
        case MPIMotionTypeVELOCITY: {
            motionParams.velocity = velocity[0];
            break;
        }
        default: {
            meiASSERT(FALSE);
            break;
        }
    }

    printf("\nMoving axis 0...\n");

    returnValue =
        mpiMotionStart(motion,
                       motionType,
                       &motionParams);

    if (returnValue != MPIMessageOK) {
        printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
               motion,
               motionType,
               &motionParams,
               returnValue,
               mpiMessage(returnValue, NULL));
    }

    /* Wait for motion to complete */
    while (returnValue == MPIMessageOK) {

        /* Wait for axis and motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        fprintf(stderr,
                "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]);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            printf("Finished axis 0 move.\n");
            break;
        }
        else {
            continue;
        }
    }

    /* Map axisList[1] to motion object */
    returnValue =
        mpiMotionAxisListSet(motion,
                             1,
                             &axisList[1]);
    msgCHECK(returnValue);

    /* Request notification of events from motion */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Move axis 1 */
    switch (motionType) {
        case MPIMotionTypeS_CURVE: {
            motionParams.sCurve = sCurve[1];
            break;
        }
        case MPIMotionTypeTRAPEZOIDAL: {
            motionParams.trapezoidal = trapezoidal[1];
            break;
        }
        case MPIMotionTypeVELOCITY: {
            motionParams.velocity = velocity[1];
            break;
        }
        default: {
            meiASSERT(FALSE);
            break;
        }
    }

    printf("\nMoving Axis 1...\n");

    returnValue =
        mpiMotionStart(motion,
                       motionType,
                       &motionParams);

    if (returnValue != MPIMessageOK) {
        printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
               motion,
               motionType,
               &motionParams,
               returnValue,
               mpiMessage(returnValue, NULL));
    }

    /* Wait for motion to complete */
    while (returnValue == MPIMessageOK) {

        /* Wait for axis and motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        fprintf(stderr,
                "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]);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            printf("Finished axis 1 move.\n");
            break;
        }
        else {
            continue;
        }
    }

    /* Map motion for axis 0 and axis 1 */
    returnValue =
        mpiMotionAxisListSet(motion,
                             2,
                             axisList);
    msgCHECK(returnValue);

    /* Request notification of events from motion */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    switch (motionType) {
        case MPIMotionTypeS_CURVE: {
            motionParams.sCurve = sCurve[2];
            break;
        }
        case MPIMotionTypeTRAPEZOIDAL: {
            motionParams.trapezoidal = trapezoidal[2];
            break;
        }
        case MPIMotionTypeVELOCITY: {
            motionParams.velocity = velocity[2];
            break;
        }
        default: {
            meiASSERT(FALSE);
            break;
        }
    }

    printf("\nMoving Axes 0 and 1...\n");

    returnValue =
        mpiMotionStart(motion,
                       motionType,
                       &motionParams);

    if (returnValue != MPIMessageOK) {
        printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
               motion,
               motionType,
               &motionParams,
               returnValue,
               mpiMessage(returnValue, NULL));
    }

    /* Wait for motion to complete */
    while (returnValue == MPIMessageOK) {

        /* Wait for axis and motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        fprintf(stderr,
                "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]);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            printf("Finished axis 0 and 1 move.\n");
            break;
        }
        else {
            continue;
        }
    }

    /* Delete Objects */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisList[0]);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisList[1]);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motmod1.c -- Point to Point trapezoidal profile motion with end point

.

motmod1.c -- Point to Point trapezoidal profile motion with end point modification.
/* motMod1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Point to Point trapezoidal profile motion with end point modification.

This is a simple program to demonstrate how to start a trapezoidal profile
 motion on a single axis.  During the execution of the motion, the target
 position (end point), velocity, accel, decel are modified.  The controller
 automatically re-calculates the motion profile, using the modified
 trajectory parameters.

The mpiMotionModify(...) function modifies a presently executing motion
 profile.  If mpiMotionModify(...) is called when no motion is executing,
 the error code, MPIMotionMessageIDLE will be returned, and no motion
 will be commanded.  This error code let's the application know that there
 was no motion to be modified.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motMod1Main

argMainRENAME(main, motMod1)
#endif

#define MOTION_NUMBER       (0)
#define AXIS_NUMBER         (0)

/* Motion Start Parameters */
#define TARGET_POSITION     (10000.0)
#define VEL                 (10000.0)
#define ACCEL               (100000.0)
#define DECEL               (100000.0)

/* Motion Modify Parameters */
#define MODIFY_POSITION     (-1000.0)   /* new target position */
#define MODIFY_VEL          (5000.0)    /* new velocity */
#define MODIFY_DECEL        (50000.0)   /* new deceleration */

#define WAIT_TIME           (500)       /* delay to modify move, (msec) */

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller object handle */
    MPIMotion   motion;     /* motion object handle */
    MPIAxis     axis;       /* axis object handle */

    long    returnValue;

    MPIMotionParams params;     /* motion parameters */
    MPITrajectory   trajectory; /* motion trajectory */
    double          position;   /* final target position */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

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

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n",
                           argv[0],
                           ArgUSAGE);
        exit(MPIMessagePARAM_INVALID);
    }

    /* Create motion controller object*/
    control =
        mpiControlCreate(MPIControlTypeDEFAULT,
                         NULL);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the motion controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create axis object*/
    axis =
        mpiAxisCreate(control,
                      AXIS_NUMBER);     /* axis number */
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, append axis */
    motion =
        mpiMotionCreate(control,
                        MOTION_NUMBER,  /* motion supervisor number */
                        axis);          /* axis object handle */
    msgCHECK(mpiMotionValidate(motion));

    /* Set up motion parameters */
    trajectory.velocity     = VEL;          /* counts per sec */
    trajectory.acceleration = ACCEL;        /* counts per sec * sec */
    trajectory.deceleration = DECEL;

    position = TARGET_POSITION;     /* target position (counts) */

    params.trapezoidal.trajectory   = &trajectory;
    params.trapezoidal.position     = &position;

    printf("\nMotionStart...\n");

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);

    meiPlatformSleep(WAIT_TIME);    /* delay */

    /* Set up new motion parameters */
    trajectory.velocity     = MODIFY_VEL;       /* counts per sec */
    trajectory.acceleration = ACCEL;            /* use same acceleration */
    trajectory.deceleration = MODIFY_DECEL;     /* counts per sec * sec */

    /* New target position (counts) */
    position = MODIFY_POSITION;

    printf("\nMotionModify...\n");

    /* Modify the executing motion profile */
    returnValue =
        mpiMotionModify(motion,
                        MPIMotionTypeTRAPEZOIDAL,
                        &params);
    msgCHECK(returnValue);

    /* object clean-up */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motorfbak.c -- Read the primary and secondary feedback for a motor

.

motorfbak.c -- Read the primary and secondary feedback for a motor
/* motorfbak.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Read the primary and secondary feedback for a motor.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motorfbakMain

argMainRENAME(main, motorfbak)
#endif

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

Arg argList[] = {
    {   "-motor",   ArgTypeLONG,    &motorNumber,   },
    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller handle */
    MPIMotor            motor;      /* motor handle(s) */
    MPIMotorFeedback    feedback;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

        long    argIndex;
        long    returnValue;    /* return value from library */

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle. */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create motor object using motorNumber on controller */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    meiPlatformConsole("(Press any key to quit)\nMotor %ld \n", motorNumber);

    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
                /* Read the motor's feedback */
                returnValue =
                    mpiMotorFeedback(motor,
                                     &feedback);
                msgCHECK(returnValue);

                meiPlatformConsole("\rPrimary: %12.0lf Secondary: %12.0lf",
                                   feedback[MPIMotorEncoderPRIMARY],
                                   feedback[MPIMotorEncoderSECONDARY]);
    }
        meiPlatformConsole("\n");

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


motorio1.c -- Configure Transceiver as input or output and toggle.

.

motorio1.c -- Configure Transceiver as input or output and toggle.
/* motorIo1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure Transceiver as input or output and toggle.

This sample application configures a single transceiver, on one motor,
for input or output.  If the transceiver is configured for output, the
bit state is configured by changing the user defined XCVR_STATE value.
As a tutorial purpose TRANSCEIVER_ID and TRANSCEIVER_MASK are defined
using MPI definitions.  The MPI definitions must have the same ending
transceiver letter!!(i.e. XCVR_A, XCVR_B, or XCVR_C)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    motorIo1Main

argMainRENAME(main, motorIo1)
#endif

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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* User Settings */
#define IO_CONFIG           (MEIMotorTransceiverConfigOUTPUT) /* INPUT or OUTPUT  */
#define TRANSCEIVER_ID      (MEIMotorTransceiverIdA)  /* A, B, or C               */
#define TRANSCEIVER_MASK    (MEIMotorTransceiverMaskA) /* same as above (A,B,or C) */

#define INVERT_BIT          (FALSE)
#define XCVR_STATE          (TRUE)  /* State of output transceiver */

#define WAIT_TIME           (10)    /* Units are msec */
int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;

    MPIMotor        motor;
    MEIMotorConfig  motorConfigXmp;  /* Contains transceiver configuration */
    MPIMotorIo      io;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    returnValue;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Get handle to motor object */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    returnValue = mpiMotorValidate(motor);
    msgCHECK(returnValue);

    /* Configure selected transceiver */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Transceiver[TRANSCEIVER_ID].Config = IO_CONFIG;
    motorConfigXmp.Transceiver[TRANSCEIVER_ID].Invert = INVERT_BIT;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /*
       Write the output word if the selected transceiver is configured
       for output.
    */
    if (IO_CONFIG == MEIMotorTransceiverConfigOUTPUT) {
        returnValue =
            mpiMotorIoGet(motor,
                          &io);
        msgCHECK(returnValue);

        if (io.output & TRANSCEIVER_MASK) {
            io.output = (io.output & ~TRANSCEIVER_MASK);
        } else {
            io.output = (io.output | TRANSCEIVER_MASK);
        }

        returnValue =
            mpiMotorIoSet(motor,
                          &io);
        msgCHECK(returnValue);
    }

    /* Wait 10ms before reading new configuration */
    meiPlatformSleep(WAIT_TIME);

    /* Read and display the current transceiver IO bit */
    returnValue =
        mpiMotorIoGet(motor,
                      &io);
    msgCHECK(returnValue);

    printf("\n%s: %d\n",
           (IO_CONFIG == MEIMotorTransceiverConfigINPUT)
                ? "Input bit"
                : "Output bit",
           (IO_CONFIG == MEIMotorTransceiverConfigINPUT)
                ? (io.input & TRANSCEIVER_MASK)
                : (io.output & TRANSCEIVER_MASK));

    /* Delete the MOTOR handle */
    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    /* Delete the CONTROL handle */
    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


notify1.c -- Create notify object and wait for events.

.

notify1.c -- Create notify object and wait for events.
/* notify1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Create notify object and wait for events.

Create a thread that uses a notify object to wait for user-defined events
 passed to the notify object from the main thread.

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    notify1Main

argMainRENAME(main, notify1)
#endif

/* Command line arguments and defaults */

Arg argList[] = {
    {   NULL,       ArgTypeINVALID, NULL,   }
};

Static  long    NotifyWaitAwake;

Static long
    notifyWait(MPINotify notify);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;        /* Motion controller handle */
    MPINotify   notify;         /* Event notification object */

    MPIEventMask    eventMask;

    long    returnValue;    /* Return value from library */

    long    eventDone;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    Thread          thread;
    ThreadStatus    status;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) {
        meiPlatformConsole("usage: %s %s\n",
                            argv[0],
                            ArgUSAGE);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Request notification of ALL events */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);

    /* Create event notification object */
    notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(notify));

    if (returnValue == MPIMessageOK) {
        thread = threadCreate();

        returnValue = threadValidate(thread);
    }

    if (returnValue == MPIMessageOK) {
        returnValue =
            threadStart(thread,
                        (THREAD_FUNCTION)notifyWait,
                        notify);
    }

    eventDone = FALSE;

    while ((returnValue == MPIMessageOK) &&
           (eventDone == FALSE)) {
        char    buffer[128];
        long    index;
        long    haveEventNumber;

        /* Wait for notifyWait() to call mpiNotifyEventWait() */
        while (NotifyWaitAwake != FALSE) {
            meiPlatformSleep(1);
        }

        /* Make sure notifyWait() thread is still executing */
        returnValue =
            threadStatus(thread,
                         &status);

        if (returnValue != MPIMessageOK) {
            break;
        }

        if (status.active == FALSE) {
            break;
        }

        meiPlatformConsole("Enter an event number, or ESC to exit ...\n");

        memset(buffer, 0, sizeof(buffer));
        index = 0;

        haveEventNumber = FALSE;
        while (haveEventNumber == FALSE) {
            MPIEventStatus  eventStatus;

            long    key;
            long    eventNumber = 0;

            key = meiPlatformKey(MPIWaitFOREVER);

            if (key <= 0) {
                meiPlatformKey(MPIWaitFOREVER);
                continue;
            }

            switch (key) {
                case 0x1b: {    /* ESC */
                    eventNumber = key;
                    haveEventNumber = TRUE;
                    eventDone = TRUE;
                    break;
                }
                case '\r':
                case '\n': {
                    meiPlatformConsole("\n");

                    eventNumber = meiPlatformAtol(buffer);

                    haveEventNumber = TRUE;
                    break;
                }
                case '\b': {
                    if (index > 0) {
                        meiPlatformConsole("\b \b");
                        buffer[--index] = '\0';
                    }
                    break;
                }
                case '-': {
                    if (index == 0) {
                        buffer[index++] = (char)key;
                        meiPlatformConsole("%c", key);
                    }
                    break;
                }
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9': {
                    buffer[index++] = (char)key;
                    meiPlatformConsole("%c", key);
                    break;
                }
                default: {
                    break;
                }
            }

            if (haveEventNumber != FALSE) {
                NotifyWaitAwake = TRUE;

                eventStatus.type    = MPIEventTypeEXTERNAL;
                eventStatus.source  = NULL;
                eventStatus.info[0] = eventNumber;

                returnValue =
                    mpiNotifyEventWake(notify,
                                       &eventStatus);
            }
        }
    }

    if (thread != NULL) {
        while (returnValue == MPIMessageOK) {
            returnValue =
                threadStatus(thread,
                             &status);
            msgCHECK(returnValue);

            if (status.active == FALSE) {
                returnValue = status.returnValue;
                break;
            }

            meiPlatformSleep(1);
        }

        returnValue = threadDelete(thread);
        msgCHECK(returnValue);
    }

    fprintf(stderr,
            "%s exiting: returnValue 0x%x: %s\n",
            argv[0],
            returnValue,
            mpiMessage(returnValue, NULL));

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

Static long
    notifyWait(MPINotify notify)
{
    long    returnValue;

    MPIWait timeout;
    long    eventDone;

    /* Validate the notify object and its handle */
    returnValue = mpiNotifyValidate(notify);

    timeout = MPIWaitFOREVER;

    eventDone = FALSE;

    while ((returnValue == MPIMessageOK) &&
           (eventDone == FALSE)) {
        MPIEventStatus  eventStatus;

        NotifyWaitAwake = FALSE;

        /* Wait for notify event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               timeout);

        meiPlatformConsole("mpiNotifyEventWait(0x%x, 0x%x, %d) returns 0x%x: %s\n",
                            notify,
                            &eventStatus,
                            timeout,
                            returnValue,
                            mpiMessage(returnValue, NULL));

        switch (returnValue) {
            case MPIMessageOK: {
                meiPlatformConsole("\teventStatus: type %d number %d\n",
                                    eventStatus.type,
                                    eventStatus.info[0]);

                if (eventStatus.info[0] == 0x1b) {
                    eventDone = TRUE;
                }
                break;
            }
            case MPIMessageTIMEOUT: {
                meiPlatformConsole("\tTIMEOUT\n");
                break;
            }
            default: {
                break;
            }
        }
    }

    meiPlatformConsole("notifyWait(0x%x) returning 0x%x: %s\n",
                        notify,
                        returnValue,
                        mpiMessage(returnValue, NULL));

    return (returnValue);
}


path1.c -- Two-axis path motion, around a rectangle with rounded

.

path1.c -- Two-axis path motion, around a rectangle with rounded corners.
/* path1.c */

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

/*

:Two-axis path motion, around a rectangle with rounded corners.

This sample demonstrates how to create a two-axis path motion.

After the Path object has been created, Line and Arc elements are
 appended to the path.  After the path elements have been appended,
 the MotionParams are generated, and the motion is started using
 mpiMotionStart(...).

When the motion has started, the program will wait for a MOTION_DONE event
 to be distributed by the event manager in a separate service thread.

A summary of Path object structures and methods:

    MPIPath -- path object handle
    MPIPathConfig{} -- path config structure
    MPIPathArc{} -- arc from start, angle and radius
    MPIPathLine{} -- point in space

    mpiPathCreate() -- create a path
    mpiPathDelete() -- delete a path
    mpiPathValidate() -- validate a path
    mpiPathConfigGet() -- get the current path configuration
    mpiPathConfigSet() -- set the path configuration
    mpiPathAppend() -- add a path element to the path
    mpiPathMotionParamsGenerate() -- generate the motion parameters

Note:  When multiple axes are associated with a motion supervisor, the
 controller automatically combines the individual axis and motor status
 into the motion status.  Thus, if a Stop, E-Stop or Abort action occurs
 on one axis, the event will be propogated automatically to the other axes.

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 <math.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define AXIS_COUNT          (2)

/* Set the vector values for Vel, Accel, Decel */
#define VELOCITY            (5000.0)
#define ACCEL               (50000.0)
#define DECEL               (50000.0)

/* The practical range for the time slice parameter is from
    10 msec (0.01) to 100 msec (0.1).  The time slice determines
    the spacing of points for the internal algorithm interpolation */
#define TIME_SLICE          (0.050) /* seconds */

/* There must be this many points in the buffer, or the motion
    will E_STOP */
#define EMPTY_COUNT         (5)

/* Ensure that the E_STOP will finish before the points are empty */
#define E_STOP_RATE         (TIME_SLICE * EMPTY_COUNT)

/* Only BSPLINE and BLSPLINE2 are supported for Path motion */
#define MOTION_TYPE         MPIMotionTypeBSPLINE

#define TIMEOUT             (10000) /* ms to wait for MOTION_DONE */

#if defined(ARG_MAIN_RENAME)
#define main    path1Main

argMainRENAME(main, path1)
#endif

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   NULL,       ArgTypeINVALID, NULL,   }
};

void main(int argc, char *argv[])
{
    MPIControl          control;        /* motion controller handle */
    MPIAxis             axis[AXIS_COUNT];       /* axis handle(s) */
    MPIMotion           motion;         /* motion handle */
    MPINotify           notify;         /* event notification handle */
    MPIEventMgr         eventMgr;       /* event manager handle */

    MPIMotionConfig     motionConfig;
    MPIPath             path;
    MPIPathConfig       pathConfig;
    MPIPathElement      element;
    MPIMotionParams     motionParams;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIEventMask        eventMask;

    Service             service;        /* service handle */

    long                returnValue;    /* return value from library */
    long                argIndex;
    double              x_start;
    double              y_start;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create axis objects */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis[0]));

    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion supervisor object using MS number 0 */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create 2-axis motion coordinate system */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Request notification of all MPI events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);

    /* Request notification of all events from motion */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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);  /* default sleep (msec) */
    meiASSERT(service != NULL);

    /* Read current motion supervisor configuration */
    returnValue =
        mpiMotionConfigGet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    /* Set new E_STOP deceleration rates */
    motionConfig.decelTime.eStop = E_STOP_RATE;

    returnValue =
        mpiMotionConfigSet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    returnValue = mpiAxisCommandPositionGet(axis[0], &x_start);
    msgCHECK(returnValue);
    returnValue = mpiAxisCommandPositionGet(axis[1], &y_start);
    msgCHECK(returnValue);

    path = mpiPathCreate();
    msgCHECK(mpiPathValidate(path));

    returnValue = mpiPathConfigGet(path,
                                    &pathConfig,
                                    NULL);
    msgCHECK(returnValue);

    pathConfig.dimension = AXIS_COUNT;
    MPIPathPointX(pathConfig.start) = x_start;
    MPIPathPointY(pathConfig.start) = y_start;
    pathConfig.velocity = VELOCITY;
    pathConfig.acceleration = ACCEL;
    pathConfig.deceleration = DECEL;
    pathConfig.interpolation = MOTION_TYPE;
    pathConfig.timeSlice = TIME_SLICE;

    returnValue = mpiPathConfigSet(path,
                                    &pathConfig,
                                    NULL);
    msgCHECK(returnValue);

    /* Start appending elements to the path */

    element.type = MPIPathElementTypeLINE;

    /* Set blending to TRUE if the corners of the path
        should be rounded.   Set to FALSE if the corners
        should be sharp. The motion will stop at corners when
        blending is FALSE */
    element.blending = TRUE;
    MPIPathPointX(element.params.line.point) = 1800.0;
    MPIPathPointY(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC;
    element.params.arc.angle.start = 270.0;
    /* Included angle is CCW when positive, CW when negative */
    element.params.arc.angle.included = 90.0;
    element.params.arc.radius = 200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = 2000.0;
    MPIPathPointY(element.params.line.point) = 1800.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC;
    element.params.arc.angle.start = 0.0;
    element.params.arc.angle.included = 90.0;
    element.params.arc.radius = 200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = -1800.0;
    MPIPathPointY(element.params.line.point) = 2000.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC;
    element.params.arc.angle.start = 90.0;
    element.params.arc.angle.included = 90.0;
    element.params.arc.radius = 200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = -2000.0;
    MPIPathPointY(element.params.line.point) = 200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC;
    element.params.arc.angle.start = 180.0;
    element.params.arc.angle.included = 90.0;
    element.params.arc.radius = 200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = 0.0;
    MPIPathPointY(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);
    /* Finished appending elements to the path */

    /* Generate motion parameters from the path object */
    returnValue = mpiPathMotionParamsGenerate(path,
                                      &motionParams);
    msgCHECK(returnValue);

    /* Keep the points in memory, in case we need to backup on path */
    motionParams.bspline.point.retain = TRUE;

    /* Specify the minimum number of points required in
        the XMP buffer -- if there are less, motion will E_STOP */
    motionParams.bspline.point.emptyCount = EMPTY_COUNT;

    /* This motion will not be appended */
    motionParams.bspline.point.final = TRUE;

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MOTION_TYPE,
                       &motionParams);
    fprintf(stderr,
            "mpiMotionStart returns 0x%x: %s\n",
            returnValue,
            mpiMessage(returnValue, NULL));

    /* Collect motion events */
    while (returnValue == MPIMessageOK) {
        MPIEventStatus  eventStatus;

        /* Wait for event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               TIMEOUT);
        msgCHECK(returnValue);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            printf("Motion Done\n");
            break;
        }
        else {
            fprintf(stderr,
                "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]);
        }
    }

    fprintf(stderr,
            "%s exiting: returnValue 0x%x: %s\n",
            argv[0],
            returnValue,
            mpiMessage(returnValue, NULL));

    returnValue = mpiPathDelete(path);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis[0]);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis[1]);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);
}


path3d1.c -- Three-axis path motion with velocities, acceleration

.

path3d1.c -- Three-axis path motion with velocities, acceleration and timeSlices
/* path1_3D.c */

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

/*

:Three-axis path motion with velocities, acceleration and timeSlices
defined for each element.

This sample demonstrates how to create a three-axis path motion together wth
different velocities, aceleration and timeSlices for different elements.

The code draws 2 rectangles. The first, larger rectangle has different velocities
and timeSlices, and different z elevations. The second, smaller one is simply
in the xy plane (z = 0) and has one corner with the direction of the arc
value = -1 which means that the motion will be around 270 degrees and not 90.
Even though the second rectangle is 2D, it must have values for z as it is inadvisable
to mix 2D and 3D paths.

After the Path object has been created, Line and Arc elements are
 appended to the path.  After the path elements have been appended,
 the MotionParams are generated, and the motion is started using
 mpiMotionStart(...).

When the motion has started, the program will wait for a MOTION_DONE event
 to be distributed by the event manager in a separate service thread.

A summary of Path object structures and methods:

    MPIPath -- path object handle
    MPIPathParams{} -- path Params structure
    MPIPathArc{} -- arc from start, angle and radius
    MPIPathLine{} -- point in space

    mpiPathCreate() -- create a path
    mpiPathDelete() -- delete a path
    mpiPathValidate() -- validate a path
    mpiPathParamsGet() -- get the current path parameters
    mpiPathParamsSet() -- set the path parameters
    mpiPathAppend() -- add a path element to the path
    mpiPathMotionParamsGenerate() -- generate the motion parameters

Note:  When multiple axes are associated with a motion supervisor, the
 controller automatically combines the individual axis and motor status
 into the motion status.  Thus, if a Stop, E-Stop or Abort action occurs
 on one axis, the event will be propogated automatically to the other axes.

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 <math.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define AXIS_COUNT          (3)

/* Set the vector values for Vel, ACCEL, Decel */
#define VELOCITY            (5000.0)
#define ACCEL               (50000.0)
#define DECEL               (50000.0)

/* The practical range for the time slice parameter is from
    10 msec (0.01) to 100 msec (0.1).  The time slice determines
    the spacing of points for the internal algorithm interpolation */
#define TIME_SLICE          (0.050) /* seconds */

/* There must be this many points in the buffer, or the motion
    will E_STOP */
#define EMPTY_COUNT         (5)

/* Ensure that the E_STOP will finish before the points are empty */
#define E_STOP_RATE         (TIME_SLICE * EMPTY_COUNT)

/* Only BSPLINE and BLSPLINE2 are supported for Path motion */
#define MOTION_TYPE         MPIMotionTypeBSPLINE

#define TIMEOUT             (100000) /* ms to wait for MOTION_DONE */

#if defined(ARG_MAIN_RENAME)
#define main    path1Main

argMainRENAME(main, path1)
#endif

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, 2};
long            motionNumber    = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   NULL,       ArgTypeINVALID, NULL,   }
};

void main(int argc, char *argv[])
{
    MPIControl          control;        /* motion controller handle */
    MPIAxis             axis[AXIS_COUNT];       /* axis handle(s) */
    MPIMotion           motion;         /* motion handle */
    MPINotify           notify;         /* event notification handle */
    MPIEventMgr         eventMgr;       /* event manager handle */

    MPIMotionConfig     motionConfig;
    MPIPath             path;
    MPIPathParams       pathParams;
    MPIPathElement      element;
    MPIMotionParams     motionParams;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIEventMask        eventMask;

    Service             service;        /* service handle */

    long                returnValue;    /* return value from library */
    long                argIndex;
    double              x_start;
    double              y_start;
    double              z_start;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    axisNumber[1] = axisNumber[0] + 1;
    axisNumber[2] = axisNumber[1] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create axis objects */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis[0]));

    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axis[1]));

    axis[2] =
        mpiAxisCreate(control,
                      axisNumber[2]);
    msgCHECK(mpiAxisValidate(axis[2]));

    /* Create motion supervisor object using MS number 0 */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create 2-axis motion coordinate system */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Request notification of all MPI events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);

    /* Request notification of all events from motion */
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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);  /* default sleep (msec) */
    meiASSERT(service != NULL);

    /* Read current motion supervisor Configurationuration */
    returnValue =
        mpiMotionConfigGet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    /* Set new E_STOP deceleration rates */
    motionConfig.decelTime.eStop = E_STOP_RATE;

    returnValue =
        mpiMotionConfigSet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    returnValue = mpiAxisCommandPositionGet(axis[0], &x_start);
    msgCHECK(returnValue);
    returnValue = mpiAxisCommandPositionGet(axis[1], &y_start);
    msgCHECK(returnValue);
    returnValue = mpiAxisCommandPositionGet(axis[2], &z_start);
    msgCHECK(returnValue);

    path = mpiPathCreate();
    msgCHECK(mpiPathValidate(path));

    returnValue = mpiPathParamsGet(path,
                                    &pathParams,
                                    NULL);
    msgCHECK(returnValue);

    pathParams.dimension = AXIS_COUNT;
    MPIPathPointX(pathParams.start) = x_start;
    MPIPathPointY(pathParams.start) = y_start;
    MPIPathPointZ(pathParams.start) = z_start;
    pathParams.velocity = VELOCITY;
    pathParams.acceleration = ACCEL;
    pathParams.deceleration = DECEL;
    pathParams.interpolation = MOTION_TYPE;
    pathParams.timeSlice = TIME_SLICE;

    returnValue = mpiPathParamsSet(path,
                                    &pathParams,
                                    NULL);
    msgCHECK(returnValue);

    /* Start appending elements to the path */

    /* In this element, the path parameters will be used */
    element.type = MPIPathElementTypeLINE ;

    /*
        Set blending to TRUE if the corners of the path
        should be rounded.   Set to FALSE if the corners
        should be sharp. The motion will stop at corners when
        blending is FALSE
    */
    element.blending = TRUE;
    MPIPathPointX(element.params.line.point) = 1800.0;
    MPIPathPointY(element.params.line.point) = 0.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    /*
        The "| MPIPathElementAttrMaskVELOCITY" in the next line states that
        the element has it's own velocity.
    */
    element.type = MPIPathElementTypeARC_END_POINT | MPIPathElementAttrMaskVELOCITY;

    MPIPathPointX(element.params.arcEndPoint.center) = 1800;
    MPIPathPointY(element.params.arcEndPoint.center) = 200;
    MPIPathPointZ(element.params.arcEndPoint.center) = 50;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = 2000;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = 200;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 100;

    element.attributes.velocity = 10 * VELOCITY;

    /*
        The 'direction' is used to describe whether the motion should be around the large,
        or small angle between the start and stop points. direction = 1 means that
        the motion will be through less than 180 degrees, while direction = -1 means that
        the motion will be through more than 180 degrees.
    */
    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    /*
        The "| MPIPathElementAttrMaskTIMESLICE" in the next line states that
        the element has it's own velocity.
    */
    element.type = MPIPathElementTypeLINE | MPIPathElementAttrMaskTIMESLICE;
    MPIPathPointX(element.params.line.point) = 2000.0;
    MPIPathPointY(element.params.line.point) = 1800.0;
    MPIPathPointZ(element.params.line.point) = 100.0;

    element.attributes.timeSlice = 0.1 * TIME_SLICE;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    /* In this element, the path parameters will be used */
    element.type = MPIPathElementTypeARC_END_POINT;
    MPIPathPointX(element.params.arcEndPoint.center) = 1800;
    MPIPathPointY(element.params.arcEndPoint.center) = 1800;
    MPIPathPointZ(element.params.arcEndPoint.center) = 50;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = 1800;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = 2000;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 0;

    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE ;
    MPIPathPointX(element.params.line.point) = -1800.0;
    MPIPathPointY(element.params.line.point) = 2000.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC_END_POINT;
    MPIPathPointX(element.params.arcEndPoint.center) = -1800;
    MPIPathPointY(element.params.arcEndPoint.center) = 1800;
    MPIPathPointZ(element.params.arcEndPoint.center) = -100;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = -2000;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = 1800;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = -200;

    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = -2000.0;
    MPIPathPointY(element.params.line.point) = 200.0;
    MPIPathPointZ(element.params.line.point) = -200.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC_END_POINT;
    MPIPathPointX(element.params.arcEndPoint.center) = -1800;
    MPIPathPointY(element.params.arcEndPoint.center) = 200;
    MPIPathPointZ(element.params.arcEndPoint.center) = -100;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = -1800;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = 0;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 0;

    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = 0.0;
    MPIPathPointY(element.params.line.point) = 0.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE ;
    MPIPathPointX(element.params.line.point) = 0.0;
    MPIPathPointY(element.params.line.point) = -1800.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);

    element.type = MPIPathElementTypeARC_END_POINT ;
    MPIPathPointX(element.params.arcEndPoint.center) = -200;
    MPIPathPointY(element.params.arcEndPoint.center) = -1800;
    MPIPathPointZ(element.params.arcEndPoint.center) = 0;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = -200;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = -2000;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 0;

    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    msgCHECK(returnValue);
        element.type = MPIPathElementTypeLINE ;
    MPIPathPointX(element.params.line.point) = -1800.0;
    MPIPathPointY(element.params.line.point) = -2000.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC_END_POINT ;
    MPIPathPointX(element.params.arcEndPoint.center) = -1800;
    MPIPathPointY(element.params.arcEndPoint.center) = -1800;
    MPIPathPointZ(element.params.arcEndPoint.center) = 0;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = -2000;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = -1800;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 0;

    element.params.arcEndPoint.direction = -1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE ;
    MPIPathPointX(element.params.line.point) = -2000.0;
    MPIPathPointY(element.params.line.point) = -200.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeARC_END_POINT;
    MPIPathPointX(element.params.arcEndPoint.center) = -1800;
    MPIPathPointY(element.params.arcEndPoint.center) = -200;
    MPIPathPointZ(element.params.arcEndPoint.center) = 0;

    MPIPathPointX(element.params.arcEndPoint.endPoint) = -1800;
    MPIPathPointY(element.params.arcEndPoint.endPoint) = 0;
    MPIPathPointZ(element.params.arcEndPoint.endPoint) = 0;

    element.params.arcEndPoint.direction = 1;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    element.type = MPIPathElementTypeLINE;
    MPIPathPointX(element.params.line.point) = 0.0;
    MPIPathPointY(element.params.line.point) = 0.0;
    MPIPathPointZ(element.params.line.point) = 0.0;

    returnValue = mpiPathAppend(path,
                                &element);
    msgCHECK(returnValue);

    /* Finished appending elements to the path */

    /* Generate motion parameters from the path object */
    returnValue = mpiPathMotionParamsGenerate(path,
                                      &motionParams);
    msgCHECK(returnValue);

    /* Keep the points in memory, in case we need to backup on path */
    motionParams.bspline.point.retain = TRUE;

    /* Specify the minimum number of points required in
        the XMP buffer -- if there are less, motion will E_STOP */
    motionParams.bspline.point.emptyCount = EMPTY_COUNT;

    /* This motion will not be appended */
    motionParams.bspline.point.final = TRUE;

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MOTION_TYPE,
                       &motionParams);
    fprintf(stderr,
            "mpiMotionStart returns 0x%x: %s\n",
            returnValue,
            mpiMessage(returnValue, NULL));

    /* Collect motion events */
    while (returnValue == MPIMessageOK) {
        MPIEventStatus  eventStatus;

        /* Wait for event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               TIMEOUT);
        msgCHECK(returnValue);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            printf("Motion Done\n");
            break;
        }
        else {
            fprintf(stderr,
                "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]);
        }
    }

    fprintf(stderr,
            "%s exiting: returnValue 0x%x: %s\n",
            argv[0],
            returnValue,
            mpiMessage(returnValue, NULL));

    returnValue = mpiPathDelete(path);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis[0]);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis[1]);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);
}


PT1.c -- Simple motion path generation, specified by position/time

.

PT1.c -- Simple motion path generation, specified by position/time points.
/* pt1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Simple motion path generation, specified by position/time points.

This sample code demonstrates the motion type, MPIMotionTypePT.  A simple
 trapezoidal velocity profile points list is created, and downloaded to
 the controller.  The time delta between each position is constant and
 the positions are spaced to generate an acceleration, constant velocity,
 and deceleration profile to the final position.

Several motion parameters must be initialized for the PT motion type:

 params.pt.pointCount - Specifies the number of points (position/time).

 params.pt.position - Pointer to a position[...] array.  There is one
    position value per point, per axis.  The length of the array must be
    equal to pointCount multiplied by the number of axes.  The positions
    are interleaved in the array by the axis index.

    For example, a three axis system would have:
        position[0] = position for axis 0
        position[1] = position for axis 1
        position[2] = position for axis 2
        position[3] = position for axis 0
        position[4] = position for axis 1
        etc.

 params.pt.time - Pointer to a time[...] array.  There is one time value
    per point.  The time specifies the number of seconds between the specified
    position, and the next position (point).  The length of the time array must
    be equal to the pointCount.

 params.pt.point.retain - Specifies whether the MPI and XMP should buffer the
    points after they have executed.  If retain = 0, the buffer will destroy
    the points after they have executed.  If retain = 1, the buffer will keep the
    points after they have executed.  This parameter is useful for future backup
    on path capability.

 params.pt.point.final - Specifies if more points will be loaded.  If final = 1,
    no more points will be loaded.  If final = 0, more points can be loaded
    with mpiMotionModify(...) using the APPEND attribute.

 params.pt.point.emptyCount - Specifies how many points the XMP-Series
    controller must have in it's buffer.  If the XMP's point buffer falls
    below the emptyCount, an E-Stop event will be generated by the motion
    supervisor, decelerating all the associated axes to a stop.

When the points are passed to mpiMotionStart(...), the MPI calculates
 constant velocity segments to fit exactly through the specified positions at
 the specified times.  The MPI library automatically handles buffering points
 lists that are larger than the XMP's buffer.  Presently, the XMP-Series
 controller can store 128 Frames per axis.  Each point requires one Frame
 per axis.

Special Considerations:

It is not necesary to specify the initial command position as the first
 position point.  The time[...] values can be constant or vary for each point.
 Constant time[...] values make the programmer's calculations easier.  For
 optimum performance, the number of points can be reduced, with no loss of
 resolution, by replacing the constant velocity sections with longer
 time[...] values.

When creating points lists longer than 64 points, you must create an Event
 Manager.  The Event Manager handles point buffering between the MPI and the XMP
 controller.

For Acceleration/Jerk fits through a points list, use the motion type,
 MPIMotionTypePVT. In this case, position/velocity/time points are specified.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    pt1Main

argMainRENAME(main, pt1)
#endif

#define AXIS_COUNT      (1)
#define POINT_COUNT     (25)    /* Number of points in trajectory */
#define TIME            (.5)    /* Time between points (seconds) */

double position[AXIS_COUNT * POINT_COUNT];
double ptime[POINT_COUNT];

/* Simple trapezoidal profile velocity path */
double point[POINT_COUNT] = {
    0.0,
    10.0,       /* Acceleration */
    30.0,
    60.0,
    100.0,
    150.0,
    210.0,
    280.0,
    360.0,
    450.0,
    550.0,
    650.0,      /* Constant vel */
    750.0,
    850.0,
    950.0,
    1050.0,
    1140.0,     /* Deceleration */
    1220.0,
    1290.0,
    1350.0,
    1400.0,
    1440.0,
    1470.0,
    1490.0,
    1500.0 };

/* Command line arguments and defaults */
long    axisNumber[AXIS_COUNT] = { 0,  };
long    motionNumber = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;                /* Control object */
    MPIAxis         axis[MEIXmpMAX_Axes];   /* Array of axis objects */
    MPIMotion       motion;                 /* Motion object */
    MPINotify       notify;                 /* Event notification handle */
    MPIEventMgr     eventMgr;               /* Event manager handle */
    MPIMotionParams params;                 /* MPI motion parameters */

    Service         service;                /* Event manager service handle */

    long    returnValue;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIEventMask        eventMask;

    long    argIndex;
    long    pointIndex;
    long    axisIndex;
    long    motionDone;

    double  initialPosition[MEIXmpMAX_Axes];

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create Axis objects */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        axis[axisIndex] =
            mpiAxisCreate(control,
                          axisNumber[axisIndex]);
        msgCHECK(mpiAxisValidate(axis[axisIndex]));
    }

    /* Create motion object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        NULL);
    msgCHECK(mpiMotionValidate(motion));

    /* Append axis objects to motion object */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue =
            mpiMotionAxisAppend(motion,
                                axis[axisIndex]);
        msgCHECK(returnValue);

        /* Read initial command position */
        returnValue =
            mpiAxisCommandPositionGet(axis[axisIndex],
                                      &initialPosition[axisIndex]);
        msgCHECK(returnValue);

    }

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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);  /* Default sleep (msec) */
    meiASSERT(service != NULL);

    /* Initialize motion params structure */
    params.pt.pointCount = POINT_COUNT;
    params.pt.position = position;
    params.pt.time = ptime;
    params.pt.point.retain = 0;     /* Flush frame buffer after execution */
    params.pt.point.final = 1;      /* Last point */
    params.pt.point.emptyCount = 5; /* Start E-Stop if frames left to execute
                                        is less than this limit. -1 disables */

    /* Create points */
    for (pointIndex = 0; pointIndex < POINT_COUNT; pointIndex++) {

        ptime[pointIndex] = TIME;   /* Delta time between points */

        for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
            /* Position at point */
            position[(pointIndex * AXIS_COUNT) + axisIndex] =
                point[pointIndex] + initialPosition[axisIndex];
        }
    }

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypePT,
                       &params);
    fprintf(stderr,
        "mpiMotionStart returns 0x%x: %s\n",
        returnValue,
        mpiMessage(returnValue, NULL));
    msgCHECK(returnValue);

    /* Collect motion events */
    motionDone = FALSE;
    while (motionDone != TRUE) {

        MPIEventStatus  eventStatus;

        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        switch(eventStatus.type) {

            case MPIEventTypeMOTION_DONE: {
                motionDone = TRUE;
                break;
            }
            default: {
                break;
            }
        }

        fprintf(stderr,
                "mpiNotifyEventWait() returns 0x%x\n"
                "\teventStatus: type %d source 0x%x info 0x%x\n",
                returnValue,
                eventStatus.type,
                eventStatus.source,
                eventStatus.info[0]);
        msgCHECK(returnValue);

    }

    /* Delete Objects */
    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue = mpiAxisDelete(axis[axisIndex]);
        msgCHECK(returnValue);
    }

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


PTAppend.c -- Simple motion path generation, using position/time

.

PTAppend.c -- Simple motion path generation, using position/time points with Motion Append
/* ptappend.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Simple motion path generation, using position/time points with Motion Append

This sample code demonstrates the motion type, MPIMotionTypePT, with Motion
 Append.  A simple trapezoidal velocity profile points list is created, and
 downloaded to the controller.  The time delta between each position is
 constant and the positions are spaced to generate an acceleration, constant
 velocity, and deceleration profile to the final position.

Several motion parameters must be initialized for the PT motion type:

 params.pt.pointCount - Specifies the number of points (position/time).

 params.pt.position - Pointer to a position[...] array.  There is one
    position value per point, per axis.  The length of the array must be
    equal to pointCount multiplied by the number of axes.  The positions
    are interleaved in the array by the axis index.

    For example, a three axis system would have:
        position[0] = position for axis 0
        position[1] = position for axis 1
        position[2] = position for axis 2
        position[3] = position for axis 0
        position[4] = position for axis 1
        etc.

 params.pt.time - Pointer to a time[...] array.  There is one time value
    per point.  The time specifies the number of seconds between the specified
    position, and the next position (point).  The length of the time array must
    be equal to the pointCount.

 params.pt.point.retain - Specifies whether the MPI and XMP should buffer the
    points after they have executed.  If retain = 0, the buffer will destroy
    the points after they have executed.  If retain = 1, the buffer will keep the
    points after they have executed.  This parameter is useful for future backup
    on path capability.

 params.pt.point.final - Specifies if more points will be loaded.  If final = 1,
    no more points will be loaded.  If final = 0, more points can be loaded
    with mpiMotionModify(...) using the APPEND attribute.

 params.pt.point.emptyCount - Specifies how many points the XMP-Series
    controller must have in it's buffer.  If the XMP's point buffer falls
    below the emptyCount, an E-Stop event will be generated by the motion
    supervisor, decelerating all the associated axes to a stop.

When the points are passed to mpiMotionStart(...), the MPI calculates
 constant velocity segments to fit exactly through the specified positions at
 the specified times.  The MPI library automatically handles buffering points
 lists that are larger than the XMP's buffer.  Presently, the XMP-Series
 controller can store 128 Frames per axis.  Each point requires one Frame
 per axis.

Special Considerations:

It is not necesary to specify the initial command position as the first
 position point.  The time[...] values can be constant or vary for each point.
 Constant time[...] values make the programmer's calculations easier.  For
 optimum performance, the number of points can be reduced, with no loss of
 resolution, by replacing the constant velocity sections with longer
 time[...] values.

When creating points lists longer than 64 points, you must create an Event
 Manager.  The Event Manager handles point buffering between the MPI and the XMP
 controller.

For Acceleration/Jerk fits through a points list, use the motion type,
 MPIMotionTypePVT. In this case, position/velocity/time points are specified.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    ptappendMain

argMainRENAME(main, ptappend)
#endif

#define AXIS_COUNT      (1)
#define POINT_COUNT     (36)    /* Number of points in trajectory */
#define TIME            (0.1)   /* Time between points (seconds) */
#define POSITION_DELTA  (10.0)  /* counts for each point */

double position[AXIS_COUNT * POINT_COUNT];
double time[POINT_COUNT];

double position2[AXIS_COUNT * POINT_COUNT];
double time2[POINT_COUNT];

/* Simple trapezoidal profile velocity path */
double point[POINT_COUNT + 1];

/* Command line arguments and defaults */
long    axisNumber[AXIS_COUNT] = { 0,  };
long    motionNumber = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;                /* Control object */
    MPIAxis         axis[MEIXmpMAX_Axes];   /* Array of axis objects */
    MPIMotion       motion;                 /* Motion object */
    MPINotify       notify;                 /* Event notification handle */
    MPIEventMgr     eventMgr;               /* Event manager handle */
    MPIMotionParams params;                 /* MPI motion parameters */
    MPIMotionParams params2;                    /* MPI motion parameters */

    Service         service;                /* Event manager service handle */

    long    returnValue;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;
    long    pointIndex;
    long    axisIndex;
    long    motionDone;

    MPIEventMask    eventMask;

    double  initialPosition[MEIXmpMAX_Axes];

    double pos = 0.0;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Obtain a Control handle */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

    /* Initialize the controller */
    returnValue = mpiControlInit(control);
    msgCHECK(returnValue);

    /* Create Axis objects */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        axis[axisIndex] =
            mpiAxisCreate(control,
                          axisNumber[axisIndex]);
        msgCHECK(mpiAxisValidate(axis[axisIndex]));
    }

    /* Create motion object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        NULL);
    msgCHECK(mpiMotionValidate(motion));

    /* Append axis objects to motion object */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue =
            mpiMotionAxisAppend(motion,
                                axis[axisIndex]);
        msgCHECK(returnValue);

        /* Read initial command position */
        returnValue =
            mpiAxisCommandPositionGet(axis[axisIndex],
                                      &initialPosition[axisIndex]);
        msgCHECK(returnValue);

    }

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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);  /* Default sleep (msec) */
    meiASSERT(service != NULL);

    /* Initialize motion params structure */
    params.pt.pointCount = POINT_COUNT;
    params.pt.position = position;
    params.pt.time = time;
    params.pt.point.retain = TRUE;      /* Flush frame buffer after execution */
    params.pt.point.final = 0;      /* Last point */
    params.pt.point.emptyCount = 2; /* Start E-Stop if frames left to execute
                                        is less than this limit. -1 disables */

    /* Initialize second motion params structure */
    params2.pt.pointCount = POINT_COUNT;
    params2.pt.position = position2;
    params2.pt.time = time2;
    params2.pt.point.retain = TRUE;     /* Flush frame buffer after execution */
    params2.pt.point.final = 1;     /* Last point */
    params2.pt.point.emptyCount = 5;    /* Start E-Stop if frames left to execute
                                        is less than this limit. -1 disables */

    for(pointIndex = 0; pointIndex < (POINT_COUNT + 1); pointIndex++)
    {
        point[pointIndex] = pos;
        pos += (double) POSITION_DELTA;
    }

    /* Create points */
    for (pointIndex = 0; pointIndex < POINT_COUNT; pointIndex++) {

        time[pointIndex] = TIME;    /* Delta time between points */

        for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
            /* Position at point */
            position[(pointIndex * AXIS_COUNT) + axisIndex] =
                point[(pointIndex + 1)] + initialPosition[axisIndex];
        }
    }

    /* Create secondary points */
    for (pointIndex = 0; pointIndex < POINT_COUNT; pointIndex++) {

        time2[pointIndex] = TIME;   /* Delta time between points */

        for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
            /* Position at point */
            position2[(pointIndex * AXIS_COUNT) + axisIndex] =
                (point[(pointIndex + 1)] + point[POINT_COUNT]) + initialPosition[axisIndex];
        }
    }

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypePT,
                       &params);
    fprintf(stderr,
        "mpiMotionStart returns 0x%x: %s\n",
        returnValue,
        mpiMessage(returnValue, NULL));
    msgCHECK(returnValue);

    /* Modify motion */
    returnValue =
        mpiMotionModify(motion,
                       MPIMotionTypePT | MPIMotionAttrMaskAPPEND,
                       &params2);
    fprintf(stderr,
        "mpiMotionModify returns 0x%x: %s\n",
        returnValue,
        mpiMessage(returnValue, NULL));
    msgCHECK(returnValue);

    /* Collect motion events */
    motionDone = FALSE;
    while (motionDone != TRUE) {

        MPIEventStatus  eventStatus;

        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        switch(eventStatus.type) {

            case MPIEventTypeMOTION_DONE: {
                motionDone = TRUE;
                break;
            }
            default: {
                break;
            }
        }

        fprintf(stderr,
                "mpiNotifyEventWait() returns 0x%x\n"
                "\teventStatus: type %d source 0x%x info 0x%x\n",
                returnValue,
                eventStatus.type,
                eventStatus.source,
                eventStatus.info[0]);
        msgCHECK(returnValue);

    }

    /* Delete Objects */
    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue = mpiAxisDelete(axis[axisIndex]);
        msgCHECK(returnValue);
    }

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


pvt1.c -- Simple motion path generation, specified by position/velocity/time

.

pvt1.c -- Simple motion path generation, specified by position/velocity/time points.
/* pvt1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Simple motion path generation, specified by position/velocity/time points.

This sample code demonstrates the motion type, MPIMotionTypePVT.  A simple
 trapezoidal velocity profile points list is created, and downloaded to
 the controller.  The time delta between each position is constant and
 the positions/velocities are spaced to generate an acceleration, constant
 velocity, and deceleration profile to the final position.

Several motion parameters must be initialized for the PVT motion type:

 params.pvt.pointCount - Specifies the number of points (position/vel./time).

 params.pvt.position - Pointer to a position[...] array.  There is one
    position value per point, per axis.  The length of the array must be
    equal to pointCount multiplied by the number of axes.  The positions
    are interleaved in the array by the axis index.

    For example, a three axis system would have:
        position[0] = position for axis 0
        position[1] = position for axis 1
        position[2] = position for axis 2
        position[3] = position for axis 0
        position[4] = position for axis 1
        etc.

 params.pvt.velocity - Pointer to a velocity[...] array.  There is one
    velocity value per point, per axis.  The length of the array must be
    equal to pointCount multiplied by the number of axes.  The velocities
    are interleaved in the array by the axis index.

    For example, a three axis system would have:
        velocity[0] = velocity for axis 0
        velocity[1] = velocity for axis 1
        velocity[2] = velocity for axis 2
        velocity[3] = velocity for axis 0
        velocity[4] = velocity for axis 1
        etc.

 params.pvt.time - Pointer to a time[...] array.  There is one time value
    per point.  The time specifies the number of seconds between the specified
    position/velocity, and the next position/velocity (point).  The length of
    the time array must be equal to the pointCount.

 params.pvt.point.retain - Specifies whether the MPI and XMP should buffer the
    points after they have executed.  If retain = 0, the buffer will destroy
    the points after they have executed.  If retain = 1, the buffer will keep
    the points after they have executed.  This parameter is useful for future
    backup on path capability.

 params.pvt.point.final - Specifies if more points will be loaded.  If final
    = 1, no more points will be loaded.  If final = 0, more points can be
    loaded with mpiMotionModify(...) using the APPEND attribute.

 params.pvt.point.emptyCount - Specifies how many points the XMP-Series
    controller must have in it's buffer.  If the XMP's point buffer falls
    below the emptyCount, an E-Stop event will be generated by the motion
    supervisor, decelerating all the associated axes to a stop.

When the points are passed to mpiMotionStart(...), the MPI calculates
 accleration/jerk segments to fit exactly through the specified positions at
 the specified times.  The MPI library automatically handles buffering points
 lists that are larger than the XMP's buffer.  Presently, the XMP-Series
 controller can store 128 Frames per axis.  Each point requires one Frame
 per axis.

Special Considerations:

It is not necesary to specify the initial command position as the first
 position point.  The time[...] values can be constant or vary for each point.
 Constant time[...] values make the programmer's calculations easier.  For
 optimum performance, the number of points can be reduced, with no loss of
 resolution, by replacing the constant velocity sections with longer
 time[...] values.

When creating points lists longer than 64 points, you must create an Event
 Manager.  The Event Manager handles point buffering between the MPI and the
 XMP controller.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    pvt1Main

argMainRENAME(main, pvt1)
#endif

#define AXIS_COUNT      (1)
#define POINT_COUNT     (7)
#define TIME            (.2)    /* Time between points (seconds) */

double position[AXIS_COUNT * POINT_COUNT];
double velocity[AXIS_COUNT * POINT_COUNT];
double ptime[POINT_COUNT];

/* Simple trapezoidal profile velocity path, Positions */
double pointPosition[POINT_COUNT] = {
    0.0,
    400.0,      /* Accel to position */
    1200.0,     /* Constant vel to position */
    1600.0,     /* Decel to position */
    1200.0,     /* Move back */
    400.0,
    0.0 };

double pointVelocity[POINT_COUNT] = {
    0.0,
    4000.0,     /* Accel to vel */
    4000.0,     /* Constant vel */
    0.0,        /* Decel to zero vel */
    -4000.0,    /* Move back */
    -4000.0,
    0.0 };

/* Command line arguments and defaults */
long    axisNumber[AXIS_COUNT] = { 0,  };
long    motionNumber = 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);
    }
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIAxis			axis[AXIS_COUNT],
                 MPIMotion			*motion,
                 MPIEventMgr		*eventMgr,
                 MPINotify			*notify,
                 Service			*service)
{
    MPIEventMask eventMask;
    long returnValue;
    long axisIndex;

     /* Obtain a Control handle */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue = mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Create Axis objects */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        axis[axisIndex] =
            mpiAxisCreate(*control,
                          axisNumber[axisIndex]);
        msgCHECK(mpiAxisValidate(axis[axisIndex]));
    }

    /* Create motion object */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        NULL);
    msgCHECK(mpiMotionValidate(*motion));

    /* Append axis objects to motion object */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue =
            mpiMotionAxisAppend(*motion,
                                axis[axisIndex]);
        msgCHECK(returnValue);
    }

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(*motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    *notify =
        mpiNotifyCreate(eventMask,
                        *motion);
    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);  /* Default sleep (msec) */
    meiASSERT(service != NULL);
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl	control,
                    MPIAxis		axis[AXIS_COUNT],
                    MPIMotion	motion,
                    MPINotify	notify,
                    MPIEventMgr	eventMgr,
                    Service	service)
{
    long axisIndex;
    long returnValue;

    /* Delete objects */
    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        returnValue = mpiAxisDelete(axis[axisIndex]);
        msgCHECK(returnValue);
    }

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

}

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;                /* Control object */
    MPIAxis         axis[MEIXmpMAX_Axes];   /* Array of axis objects */
    MPIMotion       motion;                 /* Motion object */
    MPINotify       notify;                 /* Event notification handle */
    MPIEventMgr     eventMgr;               /* Event manager handle */
    MPIMotionParams params;                 /* MPI motion parameters */

    Service         service;                /* Event manager service handle */

    long    returnValue;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    pointIndex;
    long    axisIndex;
    long    motionDone;

    double  initialPosition[MEIXmpMAX_Axes];

     /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                axis,
                &motion,
                &eventMgr,
                &notify,
                &service);

    /* Append axis objects to motion object */
    for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
        /* Read initial command position */
        returnValue =
            mpiAxisCommandPositionGet(axis[axisIndex],
                                      &initialPosition[axisIndex]);
        msgCHECK(returnValue);

    }

    /* Initialize motion params structure */
    params.pvt.pointCount = POINT_COUNT;
    params.pvt.position = position;
    params.pvt.velocity = velocity;
    params.pvt.time = ptime;
    params.pvt.point.retain = 0;    /* Flush frame buffer after execution */
    params.pvt.point.final = 1;     /* Last point */
    params.pvt.point.emptyCount = 5;/* Start E-Stop if frames left to execute
                                        is less than this limit. -1 disables */

    /* Create points */
    for (pointIndex = 0; pointIndex < POINT_COUNT; pointIndex++) {

        ptime[pointIndex] = TIME;   /* Delta time between points */

        for (axisIndex = 0; axisIndex < AXIS_COUNT; axisIndex++) {
            /* Position at point */
            position[(pointIndex * AXIS_COUNT) + axisIndex] =
                pointPosition[pointIndex] + initialPosition[axisIndex];

            /* Velocity at point */
            velocity[(pointIndex * AXIS_COUNT) + axisIndex] =
                pointVelocity[pointIndex];
        }
    }

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypePVT,
                       &params);
    fprintf(stderr,
        "mpiMotionStart returns 0x%x: %s\n",
        returnValue,
        mpiMessage(returnValue, NULL));
    msgCHECK(returnValue);

    /* Collect motion events */
    motionDone = FALSE;
    while (motionDone != TRUE) {

        MPIEventStatus  eventStatus;

        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);

        switch(eventStatus.type) {

            case MPIEventTypeMOTION_DONE: {
                motionDone = TRUE;
                break;
            }
            default: {
                break;
            }
        }

        fprintf(stderr,
                "mpiNotifyEventWait() returns 0x%x\n"
                "\teventStatus: type %d source 0x%x info 0x%x\n",
                returnValue,
                eventStatus.type,
                eventStatus.source,
                eventStatus.info[0]);
        msgCHECK(returnValue);

    }

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(control,
        axis,
        motion,
        notify,
        eventMgr,
        service);

    return ((int)returnValue);
}


quickStart1.c -- Simple point to point motion program for Quick Start

.

quickStart1.c -- Simple point to point motion program for Quick Start procedure.
/* quickStart1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    motion1Main

argMainRENAME(main, motion1)
#endif

/*

:Simple point to point motion program for Quick Start procedure.

This is a simple program to demonstrate how to start a trapezoidal profile
 motion on a single axis.  There is a minimal error checking in this sample.

This program presumes the controller is configured so the motors can move
 safely.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)

#define END_POSITION    (1000)
#define VELOCITY        (1000)
#define ACCELERATION    (5000)
#define DECELERATION    (5000)

/* 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,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber)
{
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,       /* motion supervisor number */
                        *axis);             /* axis object handle */
    msgCHECK(mpiMotionValidate(*motion));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl      *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis)
{
    long    returnValue;

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/* Display positions while waiting for the motion to be done */
void displayPositionsUntilMotionDone(MPIMotion   motion)
{
    MPIStatus   status;
    double      actual;
    double      command;
    long        motionDone;
    long        returnValue;

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        /* Display position */
        mpiMotionPositionGet(motion,
                             &actual,
                             &command);
        msgCHECK(returnValue);
        printf("Axis[0] Positions: Cmd %11.3lf\tAct %11.3lf\r",
            command,
            actual);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 20ms and give up control to other threads */
                meiPlatformSleep(20);
                break;
            }
            case MPIStateIDLE:
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}

/* Perform a trapezoidal move */
void trapMove(MPIMotion      motion,
              MPITrajectory *trajectory,
              double         position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue;

    params.trapezoidal.trajectory   = trajectory;
    params.trapezoidal.position     = &position;

    /* Read motion status */
    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)
    {
        case MPIStateIDLE: {
            /* Start motion */
            returnValue =
                mpiMotionStart(motion,
                               MPIMotionTypeTRAPEZOIDAL,
                               &params);
            msgCHECK(returnValue);

            break;
        }
        case MPIStateSTOPPING:
        case MPIStateMOVING: {
            /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(motion,
                                MPIMotionTypeTRAPEZOIDAL,
                                &params);
            msgCHECK(returnValue);
            break;
        }
        case MPIStateERROR: {
            /* Error State */
            msgCHECK(MPIMotionMessageERROR);
            break;
        }
        default: {
            /* Unknown State */
            fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
            msgCHECK(MPIMessageFATAL_ERROR);
            break;
        }
    }
}

/* setup move parameters, poll until motion done, start move */
void commandMoves(MPIMotion  motion,
                  double     endPosition,
                  double     velocity,
                  double     acceleration,
                  double     deceleration)
{
    MPITrajectory   trajectory;     /* trajectory information */
    double          command;        /* command position */
    double          position;       /* target position  */

    long            returnValue;    /* MPI return value */

    /* Set up trajectory information */
    trajectory.velocity     = velocity;
    trajectory.acceleration = acceleration;
    trajectory.deceleration = deceleration;

    printf("Press any key to exit...\n\n");

    /* Loop until the user presses a key */
    while (meiPlatformKey(MPIWaitPOLL) < 0) {
        /* Get command position */
        returnValue =
            mpiMotionPositionGet(motion,
                                 NULL,
                                 &command);
        msgCHECK(returnValue);

        if (command != 0.0) {
            position = 0.0;

        }
        else    {
            position = endPosition;
        }

        /* Perform a trapezoidal move */
        trapMove(motion,
                 &trajectory,
                 position);

        /* Display positions while waiting for the motion to be done */
        displayPositionsUntilMotionDone(motion);
    }
    printf("\n");
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller object handle */
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;     /* motion object handle */
    MPIAxis             axis;       /* axis object handle */

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER);

    /* Command some moves */
    commandMoves(motion,
                 END_POSITION,
                 VELOCITY,
                 ACCELERATION,
                 DECELERATION);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motion,
                   &axis);

    return MPIMessageOK;
}


record1.c -- Read/display data recorder records from specified axis

.

record1.c -- Read/display data recorder records from specified axis (default 0)
/* record1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Read/display data recorder records from specified axis (default 0)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    record1Main

argMainRENAME(main, record1)
#endif

#define AXIS_COUNT      (1)
#define RECORD_COUNT    (100)

/* Command line arguments and defaults */
long    axisNumber  = 0;
long    period      = 0;    /* every sample */

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handle */
    MPIRecorder recorder;           /* data recorder handle */

    MPIRecorderRecord   records[RECORD_COUNT];
    MEIRecorderRecord   *recordPtr;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    recordCountRemaining;
    long    recordIndex;

    long    returnValue;    /* return value from library */

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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 that the axis number is valid */
    meiASSERT((axisNumber >= 0) &&
              (axisNumber < MEIXmpMAX_Axes));

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis (%d)]\n"
                           "\t\t[-period (%d)]\n"
                           "\t\t[axisNumber ...]\n",
                           argv[0],
                           ArgUSAGE,
                           axisNumber,
                           period);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create and configure recorder object */
    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                (MPIRecorderRecordType)MEIRecorderRecordTypeAXIS,
                                AXIS_COUNT,
                                axis);
    msgCHECK(returnValue);

    /* Start recording the axis */
    returnValue =
        mpiRecorderStart(recorder,
                         RECORD_COUNT,
                         period,    /* period (milliseconds) */
                         0);
    msgCHECK(returnValue);

    /* Fill the record buffer */
    for (recordIndex = 0,
         recordCountRemaining = RECORD_COUNT; recordCountRemaining > 0; ) {
        long    countGet;

        returnValue =
            mpiRecorderRecordGet(recorder,
                                 recordCountRemaining,
                                 &records[recordIndex],
                                 &countGet);
        msgCHECK(returnValue);

        recordCountRemaining -= countGet;
        recordIndex += countGet;
    }

    /* Stop recording */
    returnValue = mpiRecorderStop(recorder);
    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);

    /* Output record buffer to screen */
    for (recordIndex = 0; recordIndex < RECORD_COUNT; recordIndex++) {
        printf("record[%d]:\n",
                recordIndex);

        /* Cast records to MEIRecorderRecord pointer */
        recordPtr = (MEIRecorderRecord *)&records[recordIndex];

        printf("axis %d sample %d\tcommand %d\tactual %d\tdac %.4f\n",
                axisNumber,
                recordPtr->axis[0].sample,
                recordPtr->axis[0].command,
                recordPtr->axis[0].actual,
                recordPtr->axis[0].dac);
    }

    returnValue = mpiRecorderDelete(recorder);
    msgCHECK(returnValue);

    returnValue =
        mpiAxisDelete(axis[0]);
    msgCHECK(returnValue);

    returnValue =
        mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


record2.c -- Record Data and Demonstrate How to Start/Stop/Restart

.

record2.c -- Record Data and Demonstrate How to Start/Stop/Restart Recorder
/* record2.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Record Data and Demonstrate How to Start/Stop/Restart Recorder

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    record2Main

argMainRENAME(main, record2)
#endif

/* Command line arguments and defaults */
long    period      = 0;    /* every sample */
long    recordCount = 100;

Arg argList[] = {
    {   "-period",  ArgTypeLONG,    &period,        },
    {   "-records", ArgTypeLONG,    &recordCount,   },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

long
    recorderMode(MPIRecorder    recorder,
                 long           mode,
                 long           recordCount,
                 long           period);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;                /* motion controller handle */
    MPIRecorder recorder;               /* data recorder handle */

    MEIXmpData  *firmware;

    long    axisCount;
    long    axisNumber[MEIXmpMAX_Axes]; /* axis numbers */

    long    pointCount;
    void    *point[MEIXmpMaxRecSize];

    MPIRecorderRecord   *record;
    register MPIRecorderRecord  *recordPtr;

    long    returnValue;    /* return value from library */

    long    index;

    long    recordCountRemaining;
    long    recordIndex;
    long    recordsRead;

    long    mode;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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;
        }
    }

    if (argIndex >= argc) {
        axisCount       = 1;
        axisNumber[0]   = 0;
    }
    else {
        axisCount = argc - argIndex;

        if (axisCount > MEIXmpMAX_Axes) {
            axisCount = MEIXmpMAX_Axes;
        }

        for (index = 0; index < axisCount; index++) {
            axisNumber[index] = meiPlatformAtol(argv[argIndex++]);
            meiASSERT((axisNumber[index] >= 0) &&
                      (axisNumber[index] < MEIXmpMAX_Axes));
        }
    }

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-period (%d)]\n"
                           "\t\t[-records (%d)]\n"
                           "\t\t[axisNumber ...]\n",
                           argv[0],
                           ArgUSAGE,
                           period,
                           recordCount);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    returnValue =
        mpiControlMemory(control,
                         (void **)&firmware,
                         NULL);
    msgCHECK(returnValue);

    pointCount = 0;

    point[pointCount++] = &firmware->SystemData.SampleCounter;

    for (index = 0; index < axisCount; index++) {
        point[pointCount++] = &firmware->MS[axisNumber[index]].Status;
        point[pointCount++] = &firmware->Axis[axisNumber[index]].Status;
        meiASSERT(pointCount <= MEIXmpMaxRecSize);
    }

    record =
        (MPIRecorderRecord *)meiPlatformAlloc(sizeof(*record) *
                                              recordCount);
    meiASSERT(record != NULL);

    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                MPIRecorderRecordTypePOINT,
                                pointCount,
                                point);
    msgCHECK(returnValue);

    recordPtr = record;

    mode = 0;

    meiPlatformConsole("Press any key to start recording, ESC to quit\n");

    recordCountRemaining = recordCount;

    while (recordCountRemaining > 0) {
        mode =
            recorderMode(recorder,
                         mode,
                         recordCountRemaining,
                         period);

        if (mode > 0) {
            long    countGet;

            returnValue =
                mpiRecorderRecordGet(recorder,
                                     recordCountRemaining,
                                     recordPtr,
                                     &countGet);
            msgCHECK(returnValue);

            recordCountRemaining -= countGet;
            recordPtr += countGet;
        }
        else if (mode < 0) {
            break;
        }
    }

    recordsRead = recordPtr - record;

    for (recordIndex = 0,
            recordPtr = record;
         recordIndex < recordsRead;
         recordIndex++,
             recordPtr++) {
        long    pointIndex;

        pointIndex = 0;

        printf("record[%d]: sample %d\n",
                recordIndex,
                recordPtr->point[pointIndex++]);

        for (index = 0; index < axisCount; index++) {
            printf("%d: motion status 0x%x axis status 0x%x\n",
                    axisNumber[index],
                    recordPtr->point[pointIndex],
                    recordPtr->point[pointIndex + 1]);

            pointIndex += 2;
        }
        meiASSERT(pointIndex == pointCount);
    }

    returnValue = mpiRecorderDelete(recorder);
    msgCHECK(returnValue);

    returnValue =
        meiPlatformFree(record,
                        (sizeof(*record) * recordCount));
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long
    recorderMode(MPIRecorder    recorder,
                 long           mode,
                 long           recordCount,
                 long           period)
{
    long    returnValue;

    long    modeNew;

    long    key;

    key = meiPlatformKey(MPIWaitPOLL);

    if (key <= 0) {
        if (key == 0) {
            key = meiPlatformKey(MPIWaitPOLL);
        }
        modeNew = mode;
    }
    else if (key == 0x1b) {
        modeNew = -1;
    }
    else {
        modeNew = (mode <= 0) ? 1 : 0;
    }

    if (modeNew != mode) {
        if (modeNew <= 0) {
            if (mode > 0) {
                returnValue =
                    mpiRecorderStop(recorder);
                msgCHECK(returnValue);
            }
        }
        else {
            returnValue =
                mpiRecorderStart(recorder,
                                 recordCount,
                                 period,    /* period (milliseconds) */
                                 0);
            msgCHECK(returnValue);
        }

        if (modeNew >= 0) {
            meiPlatformConsole("Press any key to %s recording, ESC to quit\n",
                                (modeNew == 0) ? "start" : "stop ");
        }
    }

    return (modeNew);
}


record3.c -- Interrupt-driven display of data recorder records from

.

record3.c -- Interrupt-driven display of data recorder records from specified axis (default 0)
/* record3.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Interrupt-driven display of data recorder records from specified axis (default 0)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    record3Main

argMainRENAME(main, record3)
#endif

/* Command line arguments and defaults */
long    period      = 0;    /* every sample */
long    recordCount = 100;
long    fullCount   = -1;

Arg argList[] = {
    {   "-period",  ArgTypeLONG,    &period,        },
    {   "-records", ArgTypeLONG,    &recordCount,   },
    {   "-full",    ArgTypeLONG,    &fullCount,     },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;                /* motion controller handle */
    MPIAxis     axis[MEIXmpMAX_Axes];   /* axis handles */
    MPIRecorder recorder;               /* data recorder handle */
    MPINotify   notify;                 /* event notification handle */
    MPIEventMgr eventMgr;               /* event manager handle */

    MPIEventMask    eventMask;

    Service     service;    /* service thread */

    long        axisCount;
    long        axisNumber[MEIXmpMAX_Axes]; /* axis numbers */

    MPIRecorderStatus   recorderStatus;
    MPIRecorderRecord   *record;
    register MEIRecorderRecord  *recordPtr;

    long    returnValue;    /* return value from library */

    long    index;

    long    recordingDone;

    long    recordIndex;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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;
        }
    }

    if (argIndex >= argc) {
        axisCount       = 1;
        axisNumber[0]   = 0;
    }
    else {
        axisCount = argc - argIndex;

        if (axisCount > MEIXmpMAX_Axes) {
            axisCount = MEIXmpMAX_Axes;
        }

        for (index = 0; index < axisCount; index++) {
            axisNumber[index] = meiPlatformAtol(argv[argIndex++]);
            meiASSERT((axisNumber[index] >= 0) &&
                      (axisNumber[index] < MEIXmpMAX_Axes));
        }
    }

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-period (%d)]\n"
                           "\t\t[-records (%d)]\n"
                           "\t\t[-full (%d)]\n"
                           "\t\t[axisNumber ...]\n",
                           argv[0],
                           ArgUSAGE,
                           period,
                           recordCount,
                           fullCount);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    for (index = 0; index < axisCount; index++) {
        axis[index] =
            mpiAxisCreate(control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create and configure recorder object */
    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                (MPIRecorderRecordType)MEIRecorderRecordTypeAXIS,
                                axisCount,
                                axis);
    msgCHECK(returnValue);

    returnValue =
        mpiRecorderStatus(recorder,
                          &recorderStatus,
                          NULL);
    msgCHECK(returnValue);

    if (fullCount < 0) {
        fullCount =
            recorderStatus.recordCountMax -
                (recorderStatus.recordCountMax / 4);
    }

    /* Allocate memory for record buffer */
    record =
        (MPIRecorderRecord *)meiPlatformAlloc(sizeof(*record) *
                                              recordCount);
    meiASSERT(record != NULL);

    /* Request notification of all events from recorder */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskRECORDER(eventMask);    /* macro */
    returnValue =
        mpiRecorderEventNotifySet(recorder,
                                  eventMask,
                                  NULL);
    msgCHECK(returnValue);

    /* Create event notification object for recorder */
    notify =
        mpiNotifyCreate(eventMask,
                        recorder);
    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 */
    meiASSERT(service != NULL);

    /* Start Recorder and wait for Event */
    returnValue =
        mpiRecorderStart(recorder,
                         recordCount,
                         period,    /* period (milliseconds) */
                         fullCount);
    msgCHECK(returnValue);

    recordPtr = (MEIRecorderRecord *)record;
    recordingDone = FALSE;
    while (recordingDone == FALSE) {
        MPIEventStatus  eventStatus;

        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        switch (eventStatus.type) {
            case MPIEventTypeRECORDER_FULL:
            case MPIEventTypeRECORDER_DONE: {
                long    countGet;

                returnValue =
                    mpiRecorderRecordGet(recorder,
                                         recordCount,
                                         (MPIRecorderRecord *)recordPtr,
                                         &countGet);
                msgCHECK(returnValue);

                recordPtr += countGet;

                if (eventStatus.type == MPIEventTypeRECORDER_DONE) {
                    recordingDone = TRUE;
                }
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }
    }

    returnValue = mpiRecorderStop(recorder);
    meiASSERT(returnValue == MPIRecorderMessageSTOPPED);

    /* Ouput all records to console */
    for (recordIndex = 0,
            recordPtr = (MEIRecorderRecord *)record;
         recordIndex < recordCount;
         recordIndex++,
             recordPtr++) {
        printf("record[%d]:\n",
                recordIndex);

        for (index = 0; index < axisCount; index++) {
            printf("axis %d sample %d\tcommand %d\tactual %d\tdac %.4f\n",
                    axisNumber[index],
                    recordPtr->axis[index].sample,
                    recordPtr->axis[index].command,
                    recordPtr->axis[index].actual,
                    recordPtr->axis[index].dac);
        }
    }

    /* Delete recorder */
    returnValue = mpiRecorderDelete(recorder);
    msgCHECK(returnValue);

    /* Free recorder buffer */
    returnValue =
        meiPlatformFree(record,
                        (sizeof(*record) * recordCount));
    meiASSERT(returnValue == MPIMessageOK);

    /* Delete remaining objects */
    for (index = 0; index < axisCount; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


record4.c -- Perform a diagonal two-axis motion and record command

.

record4.c -- Perform a diagonal two-axis motion and record command velocity and status.
/* record4.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a diagonal two-axis motion and record command velocity and status.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    record4Main

argMainRENAME(main, record4)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;
long            period          = 0;    /* every sample */
long            recordCount     = 100;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },
    {   "-period",  ArgTypeLONG,    &period,        },
    {   "-records", ArgTypeLONG,    &recordCount,   },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 200000.0, 200000.0,   },
    { 0.0,      0.0,        },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 100000.0,     1000000.0,  1000000.0,  50.0,   },
        { 100000.0,     1000000.0,  1000000.0,  50.0,   },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 100000.0,     1000000.0,  1000000.0,  50.0,   },
        { 100000.0,     1000000.0,  1000000.0,  50.0,   },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIRecorder recorder;   /* data recorder handle */

    MPIAxis     axisX;      /* X axis */
    MPIAxis     axisY;      /* Y axis */
    MPIMotion   motion;     /* motion object */

    long    returnValue;    /* return value from library */

    long    index;

    MEIXmpData  *firmware;

    long    axisCount;

    long    pointCount;
    void    *point[MEIXmpMaxRecSize];

    MPIRecorderRecord   *record;
    register MPIRecorderRecord  *recordPtr;

    long    recordCountRemaining;
    long    recordIndex;
    long    recordsRead;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n"
                           "\t\t[-period (%d)]\n"
                           "\t\t[-records (%d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIMotionTypeLAST - 1,
                            period,
                            recordCount);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    returnValue =
        mpiControlMemory(control,
                         (void **)&firmware,
                         NULL);
    msgCHECK(returnValue);

    /* Create X axis object using axisNumber on controller*/
    axisX =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axisX));

    /* Create Y axis object using axisNumber + 1 on controller */
    axisY =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axisY));

    /* Create motion object */
    /* Append X axis to motion */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axisX);
    msgCHECK(mpiMotionValidate(motion));

    /* Append Y axis to motion */
    returnValue =
        mpiMotionAxisAppend(motion,
                            axisY);
    msgCHECK(returnValue);

    axisCount   = AXIS_COUNT;
    pointCount  = 0;

    point[pointCount++] = &firmware->SystemData.SampleCounter;

    for (index = 0; index < axisCount; index++) {
        point[pointCount++] = &firmware->Axis[index].Status;
        point[pointCount++] = &firmware->Axis[index].TC.Velocity;
        meiASSERT(pointCount <= MEIXmpMaxRecSize);
    }

    record =
        (MPIRecorderRecord *)meiPlatformAlloc(sizeof(*record) *
                                              recordCount);
    meiASSERT(record != NULL);

    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                MPIRecorderRecordTypePOINT,
                                pointCount,
                                point);
    msgCHECK(returnValue);

    recordPtr = record;

    recordCountRemaining = recordCount;

    returnValue =
        mpiRecorderStart(recorder,
                         recordCount,
                         period,    /* period (milliseconds) */
                         0);
    msgCHECK(returnValue);

    /* Loop repeatedly */
    index = 0;
    {
        long    motionDone;

        if (returnValue == MPIMessageOK) {
            MPIMotionParams motionParams;

            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            returnValue =
                mpiMotionStart(motion,
                               motionType,
                               &motionParams);

            if (returnValue != MPIMessageOK) {
                printf("mpiMotionStart(0x%x, %d, 0x%x) returns 0x%x: %s\n",
                       motion,
                       motionType,
                       &motionParams,
                       returnValue,
                       mpiMessage(returnValue, NULL));
            }
        }

        while (recordCountRemaining > 0) {
            long    countGet;

            returnValue =
                mpiRecorderRecordGet(recorder,
                                     recordCountRemaining,
                                     recordPtr,
                                     &countGet);
            msgCHECK(returnValue);

            recordCountRemaining -= countGet;
            recordPtr += countGet;
        }

        /* Poll status until motion done */
        motionDone = FALSE;
        while (motionDone == FALSE) {
            MPIStatus   status;

            returnValue =
                mpiMotionStatus(motion,
                                &status,
                                NULL);
            msgCHECK(returnValue);

            switch (status.state) {
                case MPIStateMOVING: {
                    break;
                }
                case MPIStateIDLE: {
                    motionDone = TRUE;
                    break;
                }
                case MPIStateERROR: {
                    motionDone = TRUE;

                    returnValue =
                        mpiMotionAction(motion,
                                        MPIActionRESET);
                    msgCHECK(returnValue);

                    /* Wait for reset to take effect */
                    meiPlatformSleep(100);

                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }
        }

        if (++index >= MOTION_COUNT) {
            index = 0;
        }
    }

    recordsRead = recordPtr - record;

    printf("Record\tSample\tStat 0\tVel 0\tStat 1\tVel 1\n");

    for (recordIndex = 0,
            recordPtr = record;
         recordIndex < recordsRead;
         recordIndex++,
             recordPtr++) {

        printf("%d\t%d\t0X%X\t%f\t0X%X\t%f\n",
                recordIndex,
                recordPtr->point[0],
                recordPtr->point[1],
                (float)*((float *)&recordPtr->point[2]),
                recordPtr->point[3],
                (float)*((float *)&recordPtr->point[4]));

    }

    returnValue = mpiRecorderDelete(recorder);
    msgCHECK(returnValue);

    returnValue =
        meiPlatformFree(record,
                        (sizeof(*record) * recordCount));
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisY);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axisX);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


scclose.c -- Transition control from open-loop to closed-loop mode.

.

scclose.c -- Transition control from open-loop to closed-loop mode.
/* ScClose.C */

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

/*

:Transition control from open-loop to closed-loop mode.

On all motors specified by MOTOR_COUNT
 and set origin on axes specified by AXIS_COUNT (note - assumes a linear
 map of motors and axes).

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main ScClose

argMainRENAME(main, ScClose)
#endif

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

void SetPositionZero(MPIAxis axis);

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;/*  motion controller handle  */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIAxis     axis;   /* axis handle */
    MPIMotor    motor;  /* motor handle */

    MEIMotorConfig  motorConfigXmp;

    long    returnValue;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    printf("Going to closed loop (zeroing position) ...");

    /* Create device driver motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis objects and zero position */

    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    SetPositionZero(axis);

    /* Create motor objects and transition to closed-loop control */

    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Commutation.Mode = MEIXmpCommModeCLOSED_LOOP;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Delete objects */
    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    meiASSERT(returnValue == MPIMessageOK);

    return ((int)returnValue);
}

void SetPositionZero(MPIAxis axis)
{
    double  actualPosition;
    double  origin;

    long    returnValue;

    returnValue =
        mpiAxisActualPositionGet(axis,
                                 &actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    returnValue =
        mpiAxisOriginGet(axis,
                         &origin);
    meiASSERT(returnValue == MPIMessageOK);

    actualPosition += origin;

    returnValue =
        mpiAxisOriginSet(axis,
                         actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    meiPlatformSleep(15);

    actualPosition = 0;

    returnValue =
        mpiAxisCommandPositionSet(axis,
                                  actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    meiPlatformSleep(15);
};


scdither.c -- Sinusoidal Commutation Initialization Using the Dithering

.

scdither.c -- Sinusoidal Commutation Initialization Using the Dithering Method
/* ScDither.C   */

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

/*

: Sinusoidal Commutation Initialization Using the Dithering Method

Uses Dithering initialization for one axis. Axis remains in open-loop
  mode with amplifier enabled.

Note -
  #define provided for reversing encoder and DAC phasing. Program disables
  HW Limits, Amp Fault, Home and Error Limit.

The commutation configuration parameters will be different
  for your application.  Take particular care in setting the open-loop
  continuous DAC OutputLevel as this must be a safe level for your specific
  drive and motor combination.  Please read Sinusoidal Commutation Documentation
  in the MPI/MEI Software Reference Manual for further information.

Successful initialization with "Dithering" requires a system with minimal
  influence from external forces (e.g., gravitational force, cable carrier, etc)
  and static friction.

The parameters DAC level ("OutputLevel") and time delay ("VEL_DELAY" and
  "ACC_DELAY")  should be set for optimum performance with the user's specific system.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    ScDither

argMainRENAME(main, ScDither)
#endif

#define VEL_DELAY           (5)                     /* servo samples */
#define ACC_DELAY           (5)                     /* servo samples */
#define RECORD_COUNT_MAX    (VEL_DELAY + ACC_DELAY) /* number of data recorder points */

/* Command line arguments and defaults */
long    axisNumber      = 0;
long    motionNumber    = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Option to reverse encoder phasing */
#undef ReverseEncPhasing
/* Option to reverse DAC phasing */
#undef ReverseDACPhasing

MEIRecorderRecord   Record[RECORD_COUNT_MAX];

double
    accelActualGet(MPIRecorder  recorder,
                   MPIAxis      axis);

void
    setPositionZero(MPIAxis axis);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis handles */
    MPIFilter   filter;     /* filter handles */
    MPIMotor    motor;      /* motor handles  */
    MPIMotion   motion;     /* coordinated motion object handles */
    MPIRecorder recorder;   /* data recorder handle */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIControlConfig    controlConfig;      /* motion controller configuration */
    MPIAxisConfig       axisConfig;         /* axis configuration */
    MPIMotorConfig      motorConfig;
    MEIMotorConfig      motorConfigXmp;
    MPIFilterGain       gain;
    MEIFilterGainPID    *pid;

    MEIXmpData  *firmware;

    MEIXmpCommutationBlock  *commutation;

    long    nEncCountPerCycle = 4096; /* number of encoder counts per motor revolution */
    float   OpenDAC_Level   =   (float)3277.0;  /* Open Loop DAC Level where 32767. = 10V) */
    float   N_CYCLES    =       (float)3.0;     /* number of elec. cycles per motor rev. */

    long    returnValue;    /* return value from library */

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    returnValue =
        mpiControlMemory(control,
                         (void**)&firmware,
                         (void**)NULL);
    msgCHECK(returnValue);

    /*  Create a Data Recorder for future use   */
    recorder =
        mpiRecorderCreate(control);
    msgCHECK(mpiRecorderValidate(recorder));

    /*
        Configure motion controller
        Set Sample Rate = 2 kHz
        configure for commutation B phase DACs and ADCs
     */
    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    controlConfig.sampleRate = 2000;

    /*
        When supporting commutation,
        Cmd and Aux DACs must be enabled.
        Enabling the same number of Cmd and Aux DACs as there are motors.
     */
    controlConfig.cmdDacCount = controlConfig.motorCount;
    controlConfig.auxDacCount = controlConfig.motorCount;

    /*  Configure required number of A/Ds   */
    controlConfig.adcCount = 8;

    returnValue =
        mpiControlConfigSet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    /*  Create axis, filter and motor controller objects    */

    /*  Create axis */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    /*  Create filter   */
    filter =
        mpiFilterCreate(control,
                        axisNumber);
    msgCHECK(mpiFilterValidate(filter));

    /*  Create motor    */
    motor =
        mpiMotorCreate(control,
                       axisNumber);
    msgCHECK(mpiMotorValidate(motor));

    /*  Disable the amplifier   */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                             FALSE);
    msgCHECK(returnValue);

    /*  Configure axis  */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /*  Set inPositionLimit */
    axisConfig.inPosition.tolerance.positionFine = (float)1.0e10;

    returnValue =
        mpiAxisConfigSet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /*  Configure Motor */
    returnValue =
        mpiMotorConfigGet(motor,
                          &motorConfig,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /*
        Disable limit error, home, amp fault & H/W Limits
        Set encoder phase
     */

    /*  Disable limit error */
    motorConfig.event[MPIEventTypeLIMIT_ERROR].action           = MPIActionNONE;
    motorConfig.event[MPIEventTypeLIMIT_ERROR].trigger.error    = (float)50000;

    /*  Disable home event  */
    motorConfig.event[MPIEventTypeHOME].action  = MPIActionNONE;

    /*  Disable amp fault event */
    motorConfig.event[MPIEventTypeAMP_FAULT].action = MPIActionNONE;

    /*  Disable neg. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_NEG].action  = MPIActionNONE;

    /*  Disable pos. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_POS].action  = MPIActionNONE;

    /*
            Set encoder phase:

            0 - for normal
            1 - for reversed
     */
#if defined(ReverseEncPhasing)
    motorConfig.encoderPhase = 1;
#else
    motorConfig.encoderPhase = 0;
#endif

    /* Setup commutation  */
    commutation = &motorConfigXmp.Commutation;

    /* Motor Controller commutation parameters */
    commutation->Mode        = MEIXmpCommModeOPEN_LOOP;
    commutation->Length      = nEncCountPerCycle;
    commutation->Scale       = (float)MEIXmpCOMM_TABLE_SIZE * N_CYCLES /
                               (float)commutation->Length;
    commutation->PhaseDelta  = MEIXmpCOMM_120DEGREES;
    commutation->OutputLevel = OpenDAC_Level;
    commutation->Offset      = (long)0;

#if defined(ReverseDACPhasing)
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseINVERTED;
#else
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseNORMAL;
#endif

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                          &motorConfig,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Get current configuration */
    returnValue =
        mpiFilterGainGet(filter,
                         MEIFilterGainIndexDEFAULT,
                         &gain);
    msgCHECK(returnValue);

    pid = (MEIFilterGainPID *)&gain;

    /* Filter Controller control parameters */
    pid->gain.proportional          = (float)50.0;
    pid->gain.integral              = (float)0.0;
    pid->gain.derivative            = (float)200.0;
    pid->feedForward.velocity       = (float)0.0;
    pid->feedForward.acceleration   = (float)0.0;
    pid->feedForward.friction       = (float)0.0;
    pid->integrationMax.moving      = (float)0.0;
    pid->integrationMax.rest        = (float)0.0;
    pid->output.limit               = (float)26213.6;
    pid->output.offset              = (float)0.0;

    /* Set filter configuration  */
    returnValue =
        mpiFilterGainSet(filter,
                         MEIFilterGainIndexDEFAULT,
                         &gain);
    msgCHECK(returnValue);

    /*
        Create a Motion Object and append an Axis
        Note 1 - separate axis appends will be required for coordinated motion
        Note 2 - Axis Map does not take effect until motion is commanded
     */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Clear out any previous errors */
    returnValue =
        mpiMotionAction(motion,
                        MPIActionRESET);
    msgCHECK(returnValue);

    /*  Immediately send Map to controller  */
    returnValue =
        mpiMotionAction(motion,
                        (MPIAction)MEIActionMAP);
    msgCHECK(returnValue);

    /*  Enable the amplifier    */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                             TRUE);
    msgCHECK(returnValue);

    /*  Begin "Dither" phase-finding based on motor acceleration sequence   */
    {
        double  angle;
        double  delta;

        long    index;

        angle = 0.0;
        delta = 256.0;

        /*
            Find Field magnetic vector by dithering Stator vector (monitor
            direction of acceleration
         */
        for (index = 0; index < 8; index++) {
            double  accel;

            long    angleSet;

            accel =
                accelActualGet(recorder,
                               axis);

            if (accel < 0.0) {
                angle += delta;
            }
            else {
                angle -= delta;
            }

            angleSet = (long)angle;

            returnValue =
                mpiMotorMemorySet(motor,
                                  &firmware->Motor[axisNumber].Commutation.Offset,
                                  &angleSet,
                                  sizeof(firmware->Motor[axisNumber].Commutation.Offset));
            msgCHECK(returnValue);

            delta *= .75;

            /* Avoid dual null position issue with first dither */
            if ((index == 0) &&
                (accel == 0.0)) {
                delta *= 2;
            }
        }
    }

    /*  Zero Position   */
    setPositionZero(axis);

    /*  Go Closed Loop  */
#if 0
    returnValue =
        meiMotorCommutationModeSet(motor,
                                   MEIXmpCommModeCLOSED_LOOP);
    msgCHECK(returnValue);
#endif

    /*  Delete Objects  */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiFilterDelete(filter);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiRecorderDelete(recorder);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

double
    accelActualGet(MPIRecorder  recorder,
                   MPIAxis      axis)
{
    long    returnValue;    /* return value from library */

    MEIRecorderRecord   *recordPtr;

    long    recordsRemaining;

    long    v1;
    long    v2;

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                (MPIRecorderRecordType)MEIRecorderRecordTypeAXIS,
                                1,
                                &axis);
    msgCHECK(returnValue);

    returnValue =
        mpiRecorderStart(recorder,
                         RECORD_COUNT_MAX,  /* number of records */
                         0,                 /* period (milliseconds) */
                         0);
    msgCHECK(returnValue);

    recordPtr = Record;
    recordsRemaining = RECORD_COUNT_MAX;

    while (recordsRemaining > 0) {
        long    recordsRead;

        returnValue =
            mpiRecorderRecordGet(recorder,
                                 recordsRemaining,
                                 (MPIRecorderRecord *)recordPtr,
                                 &recordsRead);
        msgCHECK(returnValue);

        recordsRemaining -= recordsRead;
        recordPtr        += recordsRead;
    }

    returnValue = mpiRecorderStop(recorder);

    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);

    v1 =
        Record[VEL_DELAY - 1].axis[0].actual -
        Record[0].axis[0].actual;

    v2 =
        Record[RECORD_COUNT_MAX - 1].axis[0].actual -
        Record[RECORD_COUNT_MAX - VEL_DELAY].axis[0].actual;

    return ((double)(v2 - v1));
}

void
    setPositionZero(MPIAxis axis)
{
    double  actualPosition;
    double  origin;

    long    returnValue;

    returnValue =
        mpiAxisActualPositionGet(axis,
                                 &actualPosition);
    msgCHECK(returnValue);

    returnValue =
        mpiAxisOriginGet(axis,
                         &origin);
    msgCHECK(returnValue);

    actualPosition += origin;

    returnValue =
        mpiAxisOriginSet(axis,
                         actualPosition);
    msgCHECK(returnValue);

    meiPlatformSleep(15);

    actualPosition = 0;

    returnValue =
        mpiAxisCommandPositionSet(axis,
                                  actualPosition);
    msgCHECK(returnValue);

    meiPlatformSleep(15);
}


schall.c -- Single-Axis Sinusoidal Commutation Sample Program with

.

schall.c -- Single-Axis Sinusoidal Commutation Sample Program with Hall Initialization
/* ScHall.C */

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

/*

:Single-Axis Sinusoidal Commutation Sample Program with Hall Initialization

This program reads the Hall - I/O bit state, then sets the commutation
 table entry point to match the active Hall sensor.  This version latches
 position and up-dates the commutation entry point based on the first
 Hall transition (latches upon a single I/O with a specific edge).

        Axis 0:     Uses Hall-type initialization with a small trapezoidal
                    move (closed-loop) to the first Hall transition. Updates
                    commutation position based on the Hall transition location.

    Background:     The initial state of the three Hall sensors provides six
                    possible magnetic sectors of 60 degrees which may contain
                    the motor field vector (i.e., rotor magnetic position).
                    This program uses the following logic table:

 Mag.Phase Angle:    0 - 60 60 - 120 120 - 180  180 - 240 240 - 300  300 - 360
                    -----------------------------------------------------------
                    |       |       |         |          |          |         |
    Hall A Sensor   |  On   |   On  |   On    |    Off   |   Off    |    Off  |
                    |       |       |         |          |          |         |
    Hall B Sensor   |  Off  |   Off |   On    |    On    |   On     |    Off  |
                    |       |       |         |          |          |         |
    Hall C Sensor   |  On   |   Off |   Off   |    Off   |   On     |    On   |
                    -----------------------------------------------------------

 Hall Logic (C,B,A) (101)     (001)    (011)      (010)     (110)      (100)

 Hall Region            5       1        3          2         6          4

            The rotor magnetic field vector will initially be located within
            one of these six regions.  Sufficient accuracy for closed-loop control
            is obtained by assigning the magnetic location to the mid-point of
            the active region.  Thus, the actual commutation accuracy will be +/- 30
            electrical degrees (assuming the halls have been accurately located on your
            motor).  The motor is configured under closed-loop control and a slow
            trapezoidal move is implemented to the first observed Hall transition.
            The commutation position is then corrected to reflect the exact magnetic
            position of the Hall transition point.

            Note -  The XMP calculates: A Phase DAC Output = sin(Theta + 120)
                                        B Phase DAC Output = sin(Theta)

            Note -  See the XMP Installation Manual for information on wiring the
                    Transceiver I/O to the Hall sensors.

            Note -  #defs are provided to reverse encoder and DAC phasing.  Be aware
                    that the DAC phasing change should be called only once.

 Configure the XMP:

            Axis 0  Filter 0   Motor 0

 Configure Transceivers as input (default state):

            This sample application configures three transceivers on one motor.

Warning!   This program disables the HW Limits, Amp Fault, Home and Error Limit.

Warning!  The commutation configuration parameters will be different
 for your application.  Take particular care in setting the open-loop
 continuous DAC OutputLevel as this must be a safe level for your specific
 drive and motor combination.  Please read the MEI Sinusoidal Commutation
 Documentation.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main ScHall

argMainRENAME(main, ScHall)
#endif

#define AXIS_CNT    (1)
#define SLOW        (5.E2)      /* velocity to first Hall transition, cts/sec */
#define SLOW_ACCEL  (1.E4)      /* acceleration to first Hall transition cts/sec */
#define FAST        (5.E4)      /* velocity to shift commutation pointer, cts/sec */
#define FAST_ACCEL  (5.E5)      /* acceleration to shift comm. pointer cts/sec */

#undef USERIO

#if defined USERIO    /* Toggle the user bit associated with the motor */
#define BIT_MASK MEIXmpMotorIOMaskUSER   /* user IO Bit Mask */
#define BIT_IO   MEIXmpMotorIOBitUSER   /* user IO Bit */
#endif

/* User Settings MotorIO transceivers */
#define IO_CONFIG_IN        (MEIMotorTransceiverConfigINPUT) /* INPUT or OUTPUT   */
#define TRANSC_A_ID         (MEIMotorTransceiverIdA)
#define TRANSC_A_MASK       (MEIMotorTransceiverMaskA)
#define TRANSC_B_ID         (MEIMotorTransceiverIdB)
#define TRANSC_B_MASK       (MEIMotorTransceiverMaskB)
#define TRANSC_C_ID         (MEIMotorTransceiverIdC)
#define TRANSC_C_MASK       (MEIMotorTransceiverMaskC)

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

/* Capture Parameters */
#define ACTIVE_LOW_EDGE     (0)
#define ACTIVE_HIGH_EDGE    (1)

long captureActiveEdge = ACTIVE_HIGH_EDGE;      /* capture on high edge */

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Option to reverse encoder phasing */
#undef ReverseEncPhasing
/* Option to reverse DAC phasing */
#undef ReverseDACPhasing
#undef DumpCommParameters

void SetPositionZero(MPIAxis axis);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis handles */
    MPIFilter   filter;     /* filter handles */
    MPIMotor    motor;      /* motor handles  */
    MPICapture  capture;    /* capture handles */

    MPIControlConfig    controlConfig;  /* motion controller configuration */
    MPIAxisConfig       axisConfig;     /* axis configuration */
    MPIFilterGain       gain;
    MPIMotorConfig      motorConfig;    /* motor configuration */
    MPIMotorEventConfig eventConfig;
    MPIMotorIo          io;
    MPICaptureConfig    captureConfig;  /* capture configuration */
    MPICaptureStatus    captureStatus;  /* capture status */

    MEIMotorConfig      motorConfigXmp; /* contains transceiver configuration */
    MEIFilterGainPID    *pid;
    MEIXmpCommutationBlock  *commutation;

    MPIMotion       motion; /* Coordinated motion object handles */
    MPIMotionParams params; /* Motion parameters */
    MPITrajectory   trajectory;

    MPIControlType          controlType;
    MPIControlAddress       controlAddress;

    long    returnValue;    /* return value from library */
    long    iTranState;     /* value of the Hall transceiver word */
    long    iOffset;        /* integer value to move comm. Offset parameter */
    long    nEncCountPerCycle =  4096;          /* number of encoder counts per motor revolution */
    float   OpenDAC_Level     = (float)3277.0;  /* Open Loop DAC Level where 32767. = 10V) */
    float   N_CYCLES          = (float)3.0;     /* number of elec. cycles per motor rev. */

#if defined(ReverseDACPhasing)
    long    dacCount;
    long    dacNumber[MPIMotorDacCountMAX];
    long    number;
#endif

    double          command;
    double          endposition;
    double          LminusTh;
    double          origin;
    double          origLatchPosition, latchedPosition, latchPosChange;

    float   inPositionLimit = (float)1.0e10;

    long    argIndex;
    long    captureNumber;

    /* Parse command line for Control type and address */

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Calculate default capture number for axisNumber */
    captureNumber = (axisNumber/MEIXmpMotorsPerBlock) * MEIXmpMaxLatches +
                    (axisNumber % MEIXmpMotorsPerBlock) * 2;

    /* Create device driver motion controller object  */

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

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

    /*
       Configure motion controller
       Set Sample Rate = 2 kHz (this is the default)
       Configure for commutation B phase DACs
       Configure ADCs
     */
    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    controlConfig.sampleRate = 2000;

    /*
        When supporting commutation,
        Cmd and Aux DACs must be enabled.
        Enabling the same number of Cmd and Aux DACs as there are motors.
     */
    controlConfig.cmdDacCount = controlConfig.motorCount;
    controlConfig.auxDacCount = controlConfig.motorCount;

    /* Configure required number of A/D  */
    controlConfig.adcCount = 8;

    returnValue =
        mpiControlConfigSet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Create axis, filter and motor controller objects */

    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    filter =
        mpiFilterCreate(control,
                      axisNumber);
    msgCHECK(mpiFilterValidate(filter));

    motor =
        mpiMotorCreate(control,
                      motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create capture object for captureNumber */
    capture =
        mpiCaptureCreate(control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(capture));

    /* Disable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            FALSE);

    /* Disable capture */
    returnValue =
        mpiCaptureArm(capture,
                      FALSE);
    msgCHECK(returnValue);

    msgCHECK(returnValue);

    /* Configure axis  */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /* Set inPositionLimit  */
    axisConfig.inPosition.tolerance.positionFine = inPositionLimit;

    returnValue =
        mpiAxisConfigSet(axis,
                        &axisConfig,
                        NULL);
    msgCHECK(returnValue);

    /* Configure Motor */
    returnValue =
        mpiMotorConfigGet(motor,
                         &motorConfig,
                         &motorConfigXmp);
    msgCHECK(returnValue);

    /* Disable limit error, home, amp fault & H/W Limits, set encoder phase */

    /* Disable limit error */
    motorConfig.event[MPIEventTypeLIMIT_ERROR].action           = MPIActionNONE;
    motorConfig.event[MPIEventTypeLIMIT_ERROR].trigger.error    = (float)50000;

    /* Disable home event */
    motorConfig.event[MPIEventTypeHOME].action  = MPIActionNONE;

    /* Disable amp fault event */
    motorConfig.event[MPIEventTypeAMP_FAULT].action = MPIActionNONE;

    /* Disable neg. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_NEG].action  = MPIActionNONE;

    /* Disable pos. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_POS].action  = MPIActionNONE;

    /* Verify that transceivers are configured for input (default) */
    motorConfigXmp.Transceiver[TRANSC_A_ID].Config = IO_CONFIG_IN;
    motorConfigXmp.Transceiver[TRANSC_B_ID].Config = IO_CONFIG_IN;
    motorConfigXmp.Transceiver[TRANSC_C_ID].Config = IO_CONFIG_IN;

    /* Set encoder phase; 0 - for normal; 1 - for reversed */

#ifdef ReverseEncPhasing
    motorConfig.encoderPhase = 1;
#else
    motorConfig.encoderPhase = 0;
#endif

    /* Setup Motor commutation in open-loop mode  */
    commutation = &motorConfigXmp.Commutation;

    commutation->Mode        = MEIXmpCommModeOPEN_LOOP;
    commutation->Length      = nEncCountPerCycle;
    commutation->Scale       = (float)MEIXmpCOMM_TABLE_SIZE * N_CYCLES /
                               (float)commutation->Length;
    commutation->PhaseDelta  = MEIXmpCOMM_120DEGREES;
    commutation->OutputLevel = OpenDAC_Level;   /* Open-loop DAC level */
    commutation->Offset      = (long)0;

#if defined(ReverseDACPhasing)
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseINVERTED;
#else
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseNORMAL;
#endif

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Get current Filter configuration */
    returnValue =
        mpiFilterGainGet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    pid = (MEIFilterGainPID *)&gain;

    /* Filter Controller control parameters */
    pid->gain.proportional          = (float)100.0; /* Kp must be set for your system */
    pid->gain.integral              = (float)0.0;   /* Ki set to zero for initial use */
    pid->gain.derivative            = (float)400.0; /* Kd must be set for your system */
    pid->feedForward.velocity       = (float)0.0;
    pid->feedForward.acceleration   = (float)0.0;
    pid->feedForward.friction       = (float)0.0;
    pid->integrationMax.moving      = (float)0.0;
    pid->integrationMax.rest        = (float)0.0;
    pid->output.limit               = (float)32767.0; /* closed-loop output limit */
    pid->output.offset              = (float)0.0;

    /* Set filter configuration  */
    returnValue =
        mpiFilterGainSet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    /*
       Create a Motion Object and append an Axis
       Note 1 - separate axis appends will be required for coordinated motion
       Note 2 - Axis Map does not take effect until motion is commanded!
     */
    motion =
         mpiMotionCreate(control,
                         motionNumber,
                         axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Clear out any previous errors */
    returnValue =
        mpiMotionAction(motion,
                        MPIActionRESET);
    msgCHECK(returnValue);

    /* Immediately send Map to controller */
    returnValue =
        mpiMotionAction(motion,
                        (MPIAction)MEIActionMAP);
    msgCHECK(returnValue);

    /* Display commutation parameters */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

 #ifdef DumpCommParameters

    printf("Motor %ld:\n",
            motorNumber);

    printf("\tCommutation Length before O-L move = %ld\n",
            motorConfigXmp.Commutation.Length);

    printf("\tCommutation Scale = %f\n",
            motorConfigXmp.Commutation.Scale);

    printf("\tCommutation Theta = %ld\n",
            motorConfigXmp.Commutation.Theta);

#endif

    if (motorConfigXmp.Commutation.Length != 0) {

        double  phaseAngle;
        long tableIndex;

        tableIndex =
            ((long)(motorConfigXmp.Commutation.Theta *
              motorConfigXmp.Commutation.Scale)) &
             (MEIXmpCOMM_TABLE_SIZE - 1);

        phaseAngle =
             (double)tableIndex * 360.0/
             (double)MEIXmpCOMM_TABLE_SIZE;

        LminusTh = (double)(motorConfigXmp.Commutation.Length -
              motorConfigXmp.Commutation.Theta);

        printf("\tPhase angle = %lf degrees\n",
                phaseAngle);
    }

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /*
       Implement an open-loop "move" (without drive enabled)to
       allow Trajectory Calculator Delta to move commutation
       Theta to the beginning of the commutation table (w/o motion).
       Therefore, if Theta != 0:

                Move distance = Length - Theta (counts)
     */

    if((long)(motorConfigXmp.Commutation.Theta *
              motorConfigXmp.Commutation.Scale) != 0)
        {

        returnValue =
            mpiAxisCommandPositionGet(axis,
                                  &command);
        msgCHECK(returnValue);

        trajectory.velocity     = FAST;
        trajectory.acceleration = FAST_ACCEL;
        trajectory.deceleration = FAST_ACCEL;

        params.trapezoidal.trajectory = &trajectory;
        endposition =
        command + LminusTh;
        params.trapezoidal.position = &endposition;

        meiPlatformSleep(25);

        /*   Start "virtual" motion  */
        returnValue =
            mpiMotionStart(motion,
                           MPIMotionTypeTRAPEZOIDAL,
                         &params);
        msgCHECK(returnValue);

        /*   Delay to allow "virtual" motion to complete  */
        meiPlatformSleep(500);

        }

    /* Zero command and actual positions */
        SetPositionZero(axis);

    /* Read and display the transceiver IO bit */

    returnValue =
        mpiMotorIoGet(motor,
                      &io);
    msgCHECK(returnValue);

/*
   At this point we are still in open-loop mode with the drive disabled.
   The combined transceiver word provides the basic logic needed to establish
   the commutation Offset (Offset range: 0 to 1023) required for the active
   Hall region.
 */

    iTranState = ((io.input & TRANSC_A_MASK) + (io.input & TRANSC_B_MASK) +
                  (io.input & TRANSC_C_MASK));

    printf("\n%s: %d\n","Trans A Input bit",(io.input & TRANSC_A_MASK));
    printf("\n%s: %d\n","Trans B Input bit",(io.input & TRANSC_B_MASK));
    printf("\n%s: %d\n","Trans C Input bit",(io.input & TRANSC_C_MASK));
    printf("\n%s: %d\n","Trans Input Word",iTranState);

/* Configure capture for Transceiver input trigger */
    returnValue =
        mpiCaptureConfigGet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);

/* Set commutation Offset and expected Hall transition */

    switch (iTranState)
    {

        case 1: /* w/CW rotation: next Hall Region 3, next Hall/Trans. edge B+ */
            {
            iOffset     = 256;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskB;
            captureConfig.trigger.pattern = MEIMotorTransceiverMaskB;
            break;
            }

        case 2: /* w/CW rotation: next Hall Region 6, next Hall/Trans. edge C+ */
            {
            iOffset     =  597;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskC;
            captureConfig.trigger.pattern = MEIMotorTransceiverMaskC;
            break;
            }

        case 3: /* w/CW rotation: next Hall Region 2, next Hall/Trans. edge A- */
            {
            iOffset     =  426;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskA;
            captureConfig.trigger.pattern = 0;
            break;
            }

        case 4: /* w/CW rotation: next Hall Region 5, next Hall/Trans. edge A+ */
            {
            iOffset     =  938;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskA;
            captureConfig.trigger.pattern = MEIMotorTransceiverMaskA;
            break;
            }

        case 5: /* w/CW rotation: next Hall Region 1, next Hall/Trans. edge C- */
            {
            iOffset     =   85;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskC;
            captureConfig.trigger.pattern = 0;
            break;
            }

        case 6: /* w/CW rotation: next Hall Region 4, next Hall/Trans. edge B- */
            {
            iOffset     =  768;
            captureConfig.trigger.mask = MEIMotorTransceiverMaskB;
            captureConfig.trigger.pattern = 0;
            break;
            }

        default:
            {
                printf("\n Incorrect read of Transceivers \n");
                exit(0);
            }
    }

    returnValue =
        mpiCaptureConfigSet(capture,
                            &captureConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Configure Home Event action */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    eventConfig.action = MPIActionNONE;     /* no event */
    eventConfig.trigger.polarity = TRUE;

    returnValue =
        mpiMotorEventConfigSet(motor,
                               MPIEventTypeHOME,
                               &eventConfig,
                               NULL);
    msgCHECK(returnValue);

    /* Arm the capture */
    returnValue =
        mpiCaptureArm(capture,
                      TRUE);
    msgCHECK(returnValue);

    /* Get motor configuration again */
    returnValue =
        mpiMotorConfigGet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Setup commutation with closed-loop control and new Offset */

    commutation->Mode        = MEIXmpCommModeCLOSED_LOOP;
    commutation->Offset      = iOffset;     /* Hall updated Offset */

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Read original position for capture (origin) */

    returnValue =
        mpiAxisOriginGet(axis,
                         &origin);
    meiASSERT(returnValue == MPIMessageOK);

    origLatchPosition = origin;

    returnValue =
        mpiAxisOriginSet(axis,
                         origin);
    meiASSERT(returnValue == MPIMessageOK);

#ifdef DumpCommParameters

    /* Display commutation parameters again*/
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    printf("\tCommutation Length C-L = %ld\n",
            motorConfigXmp.Commutation.Length);

    printf("\tCommutation Theta = %ld\n",
            motorConfigXmp.Commutation.Theta);

    if (motorConfigXmp.Commutation.Length != 0) {

        double  phaseAngle;
        long tableIndex;

        tableIndex =
            ((long)(motorConfigXmp.Commutation.Theta *
              motorConfigXmp.Commutation.Scale)) &
             (MEIXmpCOMM_TABLE_SIZE - 1);

        phaseAngle =
             (double)tableIndex * 360.0/
             (double)MEIXmpCOMM_TABLE_SIZE;

        printf("\tPhase angle = %lf degrees\n",
                phaseAngle);
    }

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

#endif

    /* Enable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            TRUE);
    msgCHECK(returnValue);

    /*
       Stage/motor will servo on position with initial (Hall)
       estimate of commutation position.
       Wait period: 0.5 seconds in this example.
     */

    meiPlatformSleep(500);

    /*
        Implement a closed-loop move to the first Hall transition.
        Upon reaching transition point, latch position and update
        commutation table entry point.

        The move is currently set for +72 elec. degrees. Since the
        commutation max. error is +/- 30 deg based on a 60 deg sector,
        this allows up to 12 electrical degrees of physical mis-alignment
        of the hall sensor.
     */

    returnValue =
        mpiAxisCommandPositionGet(axis,
                                  &command);
    msgCHECK(returnValue);

    trajectory.velocity     = SLOW;
    trajectory.acceleration = SLOW_ACCEL;
    trajectory.deceleration = SLOW_ACCEL;

    params.trapezoidal.trajectory = &trajectory;
    endposition =
        command +
        ((double)(nEncCountPerCycle) / ((double)(N_CYCLES * 5.0)));
    params.trapezoidal.position = &endposition;

    meiPlatformSleep(25);

    /* Start motion */
    returnValue =
        mpiMotionStart(motion,
                       MPIMotionTypeTRAPEZOIDAL,
                       &params);
    msgCHECK(returnValue);

    printf("\n Moving...(hit any key after motion completes)...\n\n");

    /* State Machine - Poll capture status, update display, etc. */
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        returnValue =
            mpiCaptureStatus(capture,
                             &captureStatus,
                             NULL);
        msgCHECK(returnValue);

        if (captureStatus.state == MPICaptureStateCAPTURED) {

            latchedPosition = captureStatus.latch[0];

            /* Re-arm position capture */
            returnValue =
                mpiCaptureArm(capture,
                              TRUE);
            msgCHECK(returnValue);
        }
    }

    latchPosChange = latchedPosition - origLatchPosition;

    printf("\n iOffset(orig.) = %d", iOffset);
    iOffset += (long)((((float)commutation->Length)/(N_CYCLES*12) - latchPosChange)*(commutation->Scale));
    printf("\n iOffset(final) = %d\n\n", iOffset);

    /* Get motor configuration again */
    returnValue =
        mpiMotorConfigGet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Update commutation Offset based on Hall transition location */

    commutation->Offset      = iOffset;     /* Hall updated Offset */

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /*
        Delete Objects
     */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiCaptureDelete(capture);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiFilterDelete(filter);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

void SetPositionZero(MPIAxis axis)
{
    double  actualPosition;
    double  origin;

    long    returnValue;

    returnValue =
        mpiAxisActualPositionGet(axis,
                                 &actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    returnValue =
        mpiAxisOriginGet(axis,
                         &origin);
    meiASSERT(returnValue == MPIMessageOK);

    actualPosition += origin;

    returnValue =
        mpiAxisOriginSet(axis,
                         actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    meiPlatformSleep(15);

    actualPosition = 0;

    returnValue =
        mpiAxisCommandPositionSet(axis,
                                  actualPosition);
    meiASSERT(returnValue == MPIMessageOK);

    meiPlatformSleep(15);
};


scopen.c -- Transition commutation from close-loop to open-loop mode

.

scopen.c -- Transition commutation from close-loop to open-loop mode
/* ScOpen.C */

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

/*

:Transition commutation from close-loop to open-loop mode

Warning! This Sample Program Sets DAC output level = 1.0 Volt

Check your system's safe continuous level (i.e., check amplifier
current gain and safe motor continuous current level)

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main ScOpen

argMainRENAME(main, ScOpen)
#endif

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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle  */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    MPIMotor    motor;  /* motor handle */

    MEIMotorConfig  motorConfigXmp;

    long    returnValue;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    printf("Going to open loop ...");

    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Commutation.Mode = MEIXmpCommModeOPEN_LOOP;

    /* Warning!!!!! Setting DAC output level = 1.0 Volt */
    motorConfigXmp.Commutation.OutputLevel = (float)3277.0;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Delete objects */
    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


scstep.c -- Single Axis Sinusoidal Commutation Sample Configuration

.

scstep.c -- Single Axis Sinusoidal Commutation Sample Configuration Program

/* ScStep.C  */

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

/*

:Single Axis Sinusoidal Commutation Sample Configuration Program

  Axis 0 -  Uses Stepper type initialization with a small
            90 (elec.) degree move.  Axis stays in open-loop mode
            with amplifier enabled.

  Note -    #def provided to reverse encoder and DAC phasing.
            Program disables HW Limits, Amp Fault, Home and
            Error Limit.

  Configure the XMP:

            Axis 0  Filter 0   Motor 0

 Note that the commutation configuration parameters will be different
 for your application.  Take particular care in setting the open-loop
 continuous DAC OutputLevel as this must be a safe level for your specific
 drive and motor combination.  Please read the MEI Sinusoidal Commutation
 Documentation.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main StepSCMain

argMainRENAME(main, StepSC)
#endif

#define AXIS_CNT    (1)

/* Command line arguments and defaults */
long    axisNumber      = 0;
long    motionNumber    = 0;

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber,    },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* option to reverse encoder phasing */
#undef ReverseEncPhasing
/* Option to reverse DAC phasing */
#undef ReverseDACPhasing

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis handles */
    MPIFilter   filter;     /* filter handles */
    MPIMotor    motor;      /* motor handles  */

    MPIControlConfig    controlConfig;  /* motion controller configuration */
    MPIAxisConfig       axisConfig;     /* axis configuration */
    MPIFilterGain       gain;
    MPIMotorConfig      motorConfig;
    MEIMotorConfig      motorConfigXmp;
    MEIFilterGainPID    *pid;
    MEIXmpCommutationBlock  *commutation;

    MPIMotion       motion; /* Coordinated motion object handles */

    MPIControlType          controlType;
    MPIControlAddress       controlAddress;

    long    returnValue;    /* return value from library */

    long    nEncCountPerCycle = 4096; /* number of encoder counts per motor revolution */
    float   OpenDAC_Level   = (float)3277.0;  /* Open Loop DAC Level where 32767. = 10V) */
    float   N_CYCLES    =       (float)3.0;     /* number of elec. cycles per motor rev. */

#if defined(ReverseDACPhasing)
    long    dacCount;
    long    dacNumber[MPIMotorDacCountMAX];
    long    number;
#endif

    float   inPositionLimit = (float)1.0e10;

    long    argIndex, i;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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 + AXIS_CNT) ||
        (motionNumber >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_CNT,
                            MEIXmpMAX_MSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create device driver motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /*
       Configure motion controller
       Set Sample Rate = 2 kHz
       Configure for commutation B phase DACs and ADCs
     */
    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    controlConfig.sampleRate = 2000;

    /*
        When supporting commutation,
        Cmd and Aux DACs must be enabled.
        Enabling the same number of Cmd and Aux DACs as there are motors.
     */
    controlConfig.cmdDacCount = controlConfig.motorCount;
    controlConfig.auxDacCount = controlConfig.motorCount;

    /* Configure required number of A/D */
    controlConfig.adcCount = 8;

    returnValue =
        mpiControlConfigSet(control,
                            &controlConfig,
                            NULL);
    msgCHECK(returnValue);

    /* Create axis, filter and motor controller objects */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    filter =
        mpiFilterCreate(control,
                      axisNumber);
    msgCHECK(mpiFilterValidate(filter));

    motor =
        mpiMotorCreate(control,
                      axisNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Disable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            FALSE);
    msgCHECK(returnValue);

    /*   Configure axis  */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    /* Set inPositionLimit */
    axisConfig.inPosition.tolerance.positionFine = inPositionLimit;

    returnValue =
        mpiAxisConfigSet(axis,
                        &axisConfig,
                        NULL);
    msgCHECK(returnValue);

    /* Configure Motor */
    returnValue =
        mpiMotorConfigGet(motor,
                         &motorConfig,
                         &motorConfigXmp);
    msgCHECK(returnValue);

    /*
       Disable limit error, home, amp fault & H/W Limits
       Set encoder phase
     */

    /* Disable limit error */
    motorConfig.event[MPIEventTypeLIMIT_ERROR].action           = MPIActionNONE;
    motorConfig.event[MPIEventTypeLIMIT_ERROR].trigger.error    = (float)50000;

    /* Disable home event */
    motorConfig.event[MPIEventTypeHOME].action  = MPIActionNONE;

    /* Disable amp fault event */
    motorConfig.event[MPIEventTypeAMP_FAULT].action = MPIActionNONE;

    /* Disable neg. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_NEG].action  = MPIActionNONE;

    /* Disable pos. HW limit event */
    motorConfig.event[MPIEventTypeLIMIT_HW_POS].action  = MPIActionNONE;

    /*
       Set encoder phase:

       0 - for normal
       1 - for reversed
     */

#ifdef ReverseEncPhasing
    motorConfig.encoderPhase = 1;
#else
    motorConfig.encoderPhase = 0;
#endif

    /* Setup commutation  */
    commutation = &motorConfigXmp.Commutation;

    /* Motor Controller commutation parameters */
    commutation->Mode        = MEIXmpCommModeOPEN_LOOP;
    commutation->Length      = nEncCountPerCycle;
    commutation->Scale       = (float)MEIXmpCOMM_TABLE_SIZE * N_CYCLES /
                               (float)commutation->Length;
    commutation->PhaseDelta  = MEIXmpCOMM_120DEGREES;
    commutation->OutputLevel = (float)0.0;   /* level will be ramped after enable */
    commutation->Offset      = (long)0;

#if defined(ReverseDACPhasing)
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseINVERTED;
#else
    motorConfigXmp.Dac.Phase = MEIXmpDACPhaseNORMAL;
#endif

    /* Set configuration */
    returnValue =
        mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    /* Get current configuration */
    returnValue =
        mpiFilterGainGet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    pid = (MEIFilterGainPID *)&gain;

    /* Filter Controller control parameters */
    pid->gain.proportional          = (float)100.;
    pid->gain.integral              = (float)0.0;
    pid->gain.derivative            = (float)400.;
    pid->feedForward.velocity       = (float)0.0;
    pid->feedForward.acceleration   = (float)0.0;
    pid->feedForward.friction       = (float)0.0;
    pid->integrationMax.moving      = (float)0.0;
    pid->integrationMax.rest        = (float)0.0;
    pid->output.limit               = (float)32767.0;
    pid->output.offset              = (float)0.0;

    /* Set filter configuration  */
    returnValue =
        mpiFilterGainSet(filter,
                        MEIFilterGainIndexDEFAULT,
                        &gain);
    msgCHECK(returnValue);

    /*
       Create a Motion Object and append an Axis
       Note 1 - separate axis appends will be required for coordinated motion
       Note 2 - Axis Map does not take effect until motion is commanded
     */
    motion =
         mpiMotionCreate(control,
                         motionNumber,
                         axis);
    msgCHECK(mpiMotionValidate(motion));

    /*  Clear out any previous errors */
    returnValue =
            mpiMotionAction(motion,MPIActionRESET);
    msgCHECK(returnValue);

    /*  Immediately send Map to controller  */
    returnValue =
        mpiMotionAction(motion,
                        (MPIAction)MEIActionMAP);
    msgCHECK(returnValue);

    /*  Enable the amplifier */
    returnValue =
        mpiMotorAmpEnableSet(motor,
                            TRUE);
    msgCHECK(returnValue);

    /*
        DAC output will be ramped and stage will be pulled to a magnetic pole.
        Next, delay for stage to settle.  Implement outbound move,delay, then
        proceed with inbound move and delay.
     */

    returnValue =
        mpiMotorConfigGet(motor,
                        &motorConfig,
                        &motorConfigXmp);
    msgCHECK(returnValue);

    for(i= 1; i <= 100; i++){

        commutation->OutputLevel = (float)(i)*((OpenDAC_Level)/((float)100.0));

        /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);

        meiPlatformSleep(30);
    }

    meiPlatformSleep(1000);

    /* Motor outbound move */

    for(i= 1; i <= 100; i++){

        commutation->Offset      = (long)(i*2.56);

        /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);

        meiPlatformSleep(30);

    }

    meiPlatformSleep(1000);

    /* Motor return move */
    for(i= 1; i <= 100; i++){

        commutation->Offset      = (long)(256 - (i*2.56));

            /* Set configuration */
        returnValue =
            mpiMotorConfigSet(motor,
                        &motorConfig,
                        &motorConfigXmp);
        msgCHECK(returnValue);

        meiPlatformSleep(30);
    }

    meiPlatformSleep(1000);

    /* Delete Objects */
    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiFilterDelete(filter);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


scview.c -- Display commutation parameters

.

scview.c -- Display commutation parameters
/* ScView.c */

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

/*

:Display commutation parameters

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    ScView

argMainRENAME(main, ScView)
#endif

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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

char *modeLabel[] = {
    "MEIXmpCommModeNONE",
    "MEIXmpCommModeCLOSED_LOOP",
    "MEIXmpCommModeOPEN_LOOP",
    "MEIXmpCommModeSIMULATE",
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;        /* motion controller handle */
    MPIMotor        motor;          /* motor */
    MEIMotorConfig  motorConfig;    /* motor config structure */

    long    returnValue;    /* return value from library */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motor object using motorNumber */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

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

    printf("Motor %ld:\n",
            motorNumber);

    printf("\tCommutation Mode = %ld (%s)\n",
            motorConfig.Commutation.Mode,
            modeLabel[motorConfig.Commutation.Mode]);

    printf("\tCommutation Length = %ld\n",
            motorConfig.Commutation.Length);

    printf("\tCommutation Scale = %f\n",
            motorConfig.Commutation.Scale);

    printf("\tCommutation Phase Delta = %ld\n",
            motorConfig.Commutation.PhaseDelta);

    printf("\tCommutation Theta = %ld\n",
            motorConfig.Commutation.Theta);

    if (motorConfig.Commutation.Length != 0) {

        double  phaseAngle;
        long tableIndex;

        tableIndex =
            ((long)(motorConfig.Commutation.Theta *
              motorConfig.Commutation.Scale)) &
             (MEIXmpCOMM_TABLE_SIZE - 1);

        phaseAngle =
             (double)tableIndex * 360.0/
             (double)MEIXmpCOMM_TABLE_SIZE;

        printf("\tPhase angle = %lf degrees\n",
                phaseAngle);
    }

    /* Delete objects */
    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


seq1.c -- Perform a repeated multi-axis motion command sequence

.

seq1.c -- Perform a repeated multi-axis motion command sequence
/* seq1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a repeated multi-axis motion command sequence

This sample program creates a program sequencer that will generate a multi-axis
 motion beween two points.  The program sequencer waits for the motion to
 complete in between moves.  After commanding the two motions the program
 sequencer loops back to the beginning of the motion command sequence, and
 repeats the motion until the user presses a key.  The program execution is
 handled entirely on the controller, with no host computer intervention.  The
 motion can be viewed by the Motion Console and Motion Scope utilities.

The XMP program sequencer controls the execution of a single command or a
 series of commands on the XMP controller.  The program sequencer provides the
 ability to execute programs directly on the XMP controller without host
 intervention.  Examples of individual commands that can be executed by the
 program sequencer are motion, looping, conditional branching, computation,
 reading and writing of memory, time delays, waiting for conditions, setting
 inputs/outputs, and generation of events.  This rich command set provides
 capability similar to, and beyond, that provided by Programmable Logic
 Controller (PLC) programs.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    seq1Main

argMainRENAME(main, seq1)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
long            sequenceNumber  = 0;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",        ArgTypeLONG,    &axisNumber[0],     },
    {   "-motion",      ArgTypeLONG,    &motionNumber,      },
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,    },
    {   "-type",        ArgTypeLONG,    &motionType,        },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 200000.0, 0.0,        },
    { 0.0,      200000.0,   },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
};

/* Motion Parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

/* 2 => START + MOTION_DONE 1 => BRANCH */
MPICommand  CommandTable[(MOTION_COUNT * 2) + 1];
#define COMMAND_COUNT   (sizeof(CommandTable) / sizeof(MPICommand))

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIMotion   motion;             /* motion handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handles */
    MPISequence sequence;           /* sequence handle */

    MPICommandParams    commandParams;  /* command parameters */

    long    returnValue;    /* return value from library */

    long    commandIndex;   /* CommandTable[] index */
    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]  > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber   >= MEIXmpMAX_MSs) ||
        (sequenceNumber >= MEIXmpMAX_PSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_PSs - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motion object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create axis object for axis #0 */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);   /* axis #0 */
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create axis object for axis #1 */
    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);   /* axis #1 */
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion axis list */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          -1);
    msgCHECK(mpiSequenceValidate(sequence));

    /* CommandTable[commandIndex] */
    commandIndex = 0;

    /* Create motion Commands */
    for (index = 0; index < MOTION_COUNT; index++) {
        MPIMotionParams *motionParams;

        /* mpiMotionStart(motion, type, params); */
        commandParams.motion.motionCommand  = MPICommandMotionSTART;
        commandParams.motion.motion         = motion;
        commandParams.motion.type           = motionType;

        motionParams = &commandParams.motion.params;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams->sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams->trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams->velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeMOTION,
                             &commandParams,
                             (commandIndex == 0) ? "First" : NULL);

        returnValue = mpiCommandValidate(CommandTable[commandIndex]);
        msgCHECK(returnValue);

        commandIndex++;

        commandParams.waitEvent.handle  = motion;
        commandParams.waitEvent.oper    = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.waitEvent.mask);
        mpiEventMaskSET(commandParams.waitEvent.mask, MPIEventTypeMOTION_DONE);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_EVENT,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;
    }

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Create sequence command list */
    returnValue =
        mpiSequenceCommandListSet(sequence,
                                  commandIndex,
                                  CommandTable);
    msgCHECK(returnValue);

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    meiPlatformConsole("Press any key to stop sequence\n");
    meiPlatformKey(MPIWaitFOREVER);

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    /* Delete Objects */
    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


seq2.c-- Perform a repeated multi-axis motion command sequence,

.

seq2.c -- Perform a repeated multi-axis motion command sequence, wait for an I/O bit
/* seq2.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a repeated multi-axis motion command sequence, wait for an I/O bit

This sample program creates a program sequencer that will generate a multi-axis
 motion beween two points.  The program sequencer waits for the motion to
 complete in between moves.  After commanding the two motions the program
 sequencer waits for a transceiver I/O bit to change state (defined by
 TRANSCEIVER_ID and TRIGGER_STATE at the top of the program).  Then the sequence
 loops back to the beginning of the motion command sequence, and repeats the
 motion until the user presses a key.  The program execution is handled entirely
 on the controller, with no host computer intervention.  The motion can be
 viewed by the Motion Console and Motion Scope utilities.

The XMP program sequencer controls the execution of a single command or a
 series of commands on the XMP controller.  The program sequencer provides the
 ability to execute programs directly on the XMP controller without host
 intervention.  Examples of individual commands that can be executed by the
 program sequencer are motion, looping, conditional branching, computation,
 reading and writing of memory, time delays, waiting for conditions, setting
 inputs/outputs, and generation of events.  This rich command set provides
 capability similar to, and beyond, that provided by Programmable Logic
 Controller (PLC) programs.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    seq2Main

argMainRENAME(main, seq2)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Define the transceiver to wait for in between motion sequences */
#define TRANSCEIVER_ID  (MEIMotorTransceiverIdA)  /* A, B, or C */

/* Define the trigger value for the transceiver,
   MPICommandOperatorBIT_SET or MPICommandOperatorBIT_CLEAR
*/
#define TRIGGER_STATE   (MPICommandOperatorBIT_SET)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
long            motorNumber     = 0;
long            sequenceNumber  = 0;
long            sequenceSize    = -1;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",        ArgTypeLONG,    &axisNumber[0],     },
    {   "-motion",      ArgTypeLONG,    &motionNumber,      },
    {   "-motor",       ArgTypeLONG,    &motorNumber,       },
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,    },
    {   "-size",        ArgTypeLONG,    &sequenceSize,      },
    {   "-type",        ArgTypeLONG,    &motionType,        },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  0.0,        },
    { 0.0,      20000.0,    },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

                        /* 3 => START + MOTION_DONE + I/O 1 => BRANCH */
MPICommand  CommandTable[(MOTION_COUNT * 3) + 1];
#define COMMAND_COUNT   (sizeof(CommandTable) / sizeof(MPICommand))

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIMotion   motion;             /* motion handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handles */
    MPIMotor    motor;              /* motor handle */

    MPISequence sequence;           /* sequence handle */

    MPICommandParams    commandParams;  /* command parameters */

    long    returnValue;    /* return value from library */

    long    commandIndex;   /* CommandTable[] index */
    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]  > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber   >= MEIXmpMAX_MSs) ||
        (motorNumber    >= MEIXmpMAX_Motors) ||
        (sequenceNumber >= MEIXmpMAX_PSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[-size # (%d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1,
                            MEIXmpMAX_PSs - 1,
                            sequenceSize,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motion object for MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create axis object for X_AXIS */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create axis object for Y_AXIS */
    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion axis list */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

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

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          sequenceSize);
    msgCHECK(mpiSequenceValidate(sequence));

    /* CommandTable[commandIndex] */
    commandIndex = 0;

    /* Create motion Commands */
    for (index = 0; index < MOTION_COUNT; index++) {
        MPIMotionParams *motionParams;

        /* mpiMotionStart(motion, type, params); */
        commandParams.motion.motionCommand  = MPICommandMotionSTART;
        commandParams.motion.motion         = motion;
        commandParams.motion.type           = motionType;

        motionParams = &commandParams.motion.params;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams->sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams->trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams->velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeMOTION,
                             &commandParams,
                             (commandIndex == 0) ? "First" : NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        commandParams.waitEvent.handle  = motion;
        commandParams.waitEvent.oper    = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.waitEvent.mask);
        mpiEventMaskSET(commandParams.waitEvent.mask, MPIEventTypeMOTION_DONE);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_EVENT,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        /* while (mpiControlUserIoGet(control, &io), (io.input[0] & mask) == 0); */
        commandParams.waitIO.type           = MPIIoTypeMOTOR;
        commandParams.waitIO.source.motor   = motor;
        commandParams.waitIO.oper           = TRIGGER_STATE;
        commandParams.waitIO.mask           = 0x1 << TRANSCEIVER_ID;    /* bit 0 */

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_IO,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;
    }

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Create sequence command list */
    returnValue =
        mpiSequenceCommandListSet(sequence,
                                  commandIndex,
                                  CommandTable);
    msgCHECK(returnValue);

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);

    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiSequenceStart() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(2);
    }

    meiPlatformConsole("Press any key to stop sequence\n");
    meiPlatformKey(MPIWaitFOREVER);

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


seq3.c -- Wait for an I/O bit to Toggle Before Commanding Motion

.

seq3.c -- Wait for an I/O bit to Toggle Before Commanding Motion with a Sequencer
/* seq3.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Wait for an I/O bit to Toggle Before Commanding Motion with a Sequencer

Wait for an I/O bit between moves.
This program will wait for motor 0's Transceiver A to go high.
Use an event manager to handle flow control.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    seq3Main

argMainRENAME(main, seq3)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
long            motorNumber     = 0;
long            sequenceNumber  = 0;
long            sequenceSize    = -1;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",        ArgTypeLONG,    &axisNumber[0],     },
    {   "-motion",      ArgTypeLONG,    &motionNumber,      },
    {   "-motor",       ArgTypeLONG,    &motorNumber,       },
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,    },
    {   "-size",        ArgTypeLONG,    &sequenceSize,      },
    {   "-type",        ArgTypeLONG,    &motionType,        },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  0.0,        },
    { 0.0,      20000.0,    },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

                        /* 4 => START + MOTION_DONE + I/O + EVENT 1 => BRANCH */
MPICommand  CommandTable[(MOTION_COUNT * 4) + 1];
#define COMMAND_COUNT   (sizeof(CommandTable) / sizeof(MPICommand))

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIMotion   motion;             /* motion handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handles */
    MPIMotor    motor;              /* motor handle */

    MPISequence sequence;           /* sequence handle */
    MPIEventMgr eventMgr;           /* event manager handle */

    Service service;

    MPICommandParams    commandParams;  /* command parameters */

    long    returnValue;    /* return value from library */

    long    commandIndex;   /* CommandTable[] index */

    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]  > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber   >= MEIXmpMAX_MSs) ||
        (motorNumber    >= MEIXmpMAX_Motors) ||
        (sequenceNumber >= MEIXmpMAX_PSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[-size # (%d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1,
                            MEIXmpMAX_PSs - 1,
                            sequenceSize,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motion object for MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create axis object for X_AXIS number */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create axis object for Y_AXIS number */
    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion axis list */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Create motor objects */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          sequenceSize);
    msgCHECK(mpiSequenceValidate(sequence));

#if defined(_DEBUG)
    returnValue =
        meiObjectTraceSet(sequence,
                          MEISequenceTraceLOAD);
    msgCHECK(returnValue);
#endif

    /* CommandTable[commandIndex] */
    commandIndex = 0;

    /* Create motion Commands */
    for (index = 0; index < MOTION_COUNT; index++) {
        MPIMotionParams *motionParams;

        /* mpiMotionStart(motion, type, params); */
        commandParams.motion.motionCommand  = MPICommandMotionSTART;
        commandParams.motion.motion         = motion;
        commandParams.motion.type           = motionType;

        motionParams = &commandParams.motion.params;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams->sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams->trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams->velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeMOTION,
                             &commandParams,
                             (commandIndex == 0) ? "First" : NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        commandParams.waitEvent.handle  = motion;
        commandParams.waitEvent.oper    = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.waitEvent.mask);
        mpiEventMaskSET(commandParams.waitEvent.mask, MPIEventTypeMOTION_DONE);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_EVENT,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        commandParams.branchEvent.label     = NULL;
        commandParams.branchEvent.handle    = motion;
        commandParams.branchEvent.oper      = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.branchEvent.mask);
        mpiEventMaskMOTOR(commandParams.branchEvent.mask);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeBRANCH_EVENT,
                             &commandParams,
                             NULL);

        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        /* while (mpiControlUserIoGet(control, &io), (io.input[0] & mask) == 0); */
        commandParams.waitIO.type           = MPIIoTypeMOTOR;
        commandParams.waitIO.source.motor   = motor;

        commandParams.waitIO.oper           = MPICommandOperatorBIT_SET;
        commandParams.waitIO.mask           = 0x1 << 0; /* bit 0 */

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_IO,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;
    }

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Create sequence command list */
    returnValue =
        mpiSequenceCommandListSet(sequence,
                                  commandIndex,
                                  CommandTable);
    msgCHECK(returnValue);

    /* Create event manager object */
    eventMgr = mpiEventMgrCreate(control);
    msgCHECK(mpiEventMgrValidate(eventMgr));

    /* Create service thread */
    service =
        serviceCreate(eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    meiASSERT(service != NULL);

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);

    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiSequenceStart() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(2);
    }

    meiPlatformConsole("Press any key to stop sequence\n");
    meiPlatformKey(MPIWaitFOREVER);

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


seq4.c -- Perform a repeated multi-axis motion sequence, wait for

.

seq4.c -- Perform a repeated multi-axis motion sequence, wait for I/O, & monitor location
/* seq4.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Perform a repeated multi-axis motion sequence, wait for I/O, & monitor location

This sample program creates a program sequencer that will generate a multi-axis
 motion beween two points.  The program sequencer waits for the motion to
 complete in between moves.  After commanding the two motions the program
 sequencer waits for a transceiver I/O bit to change state (defined by
 TRANSCEIVER_WAIT_ID and TRIGGER_STATE at the top of the program).  Then the
 sequence loops back to the beginning of the motion command sequence, and
 repeats the motion until the user presses a key.

In addition there is a second program sequencer that monitors the position of
 the X and Y axes.  If their positions fall within a rectangle, defined by the
 position array, then a transceiver bit is set (defined by TRANSCEIVER_SET_ID).
 This can be used to signal process or inspection equipment to begin their
 actions.

The program execution is handled entirely on the controller, with no host
 computer intervention.  The motion can be viewed by the Motion Console and
 Motion Scope utilities.

The XMP program sequencer controls the execution of a single command or a
 series of commands on the XMP controller.  The program sequencer provides the
 ability to execute programs directly on the XMP controller without host
 intervention.  Examples of individual commands that can be executed by the
 program sequencer are motion, looping, conditional branching, computation,
 reading and writing of memory, time delays, waiting for conditions, setting
 inputs/outputs, and generation of events.  This rich command set provides
 capability similar to, and beyond, that provided by Programmable Logic
 Controller (PLC) programs.

 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 <math.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    seq4Main

argMainRENAME(main, seq4)
#endif

#define MOTION_COUNT    (2)
#define AXIS_COUNT      (2)

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0, 1, };
long            motionNumber    = 0;
long            motorNumber     = 0;
long            sequenceNumber  = 0;
long            sequenceSize    = 128;
MPIMotionType   motionType      = MPIMotionTypeTRAPEZOIDAL;

Arg argList[] = {
    {   "-axis",        ArgTypeLONG,    &axisNumber[0],     },
    {   "-motion",      ArgTypeLONG,    &motionNumber,      },
    {   "-motor",       ArgTypeLONG,    &motorNumber,       },
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,    },
    {   "-size",        ArgTypeLONG,    &sequenceSize,      },
    {   "-type",        ArgTypeLONG,    &motionType,        },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT][AXIS_COUNT] = {
    { 20000.0,  0.0,        },
    { 0.0,      20000.0,    },
};

MPITrajectory trajectory[MOTION_COUNT][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      100000.0,   100000.0,   50.0,   },
        { 10000.0,      100000.0,   100000.0,   50.0,   },
    },
};

/* motion parameters */

MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

typedef enum {
    ExternalEventSEQUENCE_DONE,
} ExternalEvent;

                        /* 4 => START + MOTION_DONE + I/O + EVENT */
                        /* 2 => EXTERNAL_EVENT + BRANCH */
MPICommand  CommandTable[(MOTION_COUNT * 4) + 2];
#define COMMAND_COUNT   (sizeof(CommandTable) / sizeof(MPICommand))

#define IO_CONFIG   (MEIMotorTransceiverConfigOUTPUT) /* INPUT or OUTPUT  */
#define INVERT_BIT  (FALSE)

/* Toggle the transceiver associated with the motor.  In this case, toggle
   transceiver B
*/
#define TRANSCEIVER_SET_ID  (MEIMotorTransceiverIdB)  /* A, B, or C, */
/* Define the transceiver to wait for in between motion sequences */
#define TRANSCEIVER_WAIT_ID (MEIMotorTransceiverIdA)  /* A, B, or C */

/* Define the trigger value for the transceiver,
   MPICommandOperatorBIT_SET or MPICommandOperatorBIT_CLEAR
*/
#define TRIGGER_STATE   (MPICommandOperatorBIT_SET)

MPISequence
    monitorPosition(MPIControl  control,
                    MPIMotor    motor,
                    MPIAxis     axisX,
                    MPIAxis     axisY,
                    double      *limitX,
                    double      *limitY);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;            /* motion controller handle */
    MPIMotion   motion;             /* motion handle */
    MPIAxis     axis[AXIS_COUNT];   /* axis handles */
    MPIMotor    motor;              /* motor handle */

    MPISequence sequence;           /* sequence handle */
    MPISequence sequenceMonitor;    /* sequence handle */
    MPINotify   notify;             /* notification handle */
    MPIEventMgr eventMgr;           /* event manager handle */

    MPIEventMask    eventMask;

    Service service;

    MPICommandType      type;           /* command type */
    MPICommandParams    commandParams;  /* command parameters */

    double  limitX[AXIS_COUNT];
    double  limitY[AXIS_COUNT];
    double  limit;

    long    returnValue;    /* return value from library */

    long    commandIndex;   /* CommandTable[] index */
    long    index;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0]  > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber   >= MEIXmpMAX_MSs) ||
        (motorNumber    >= MEIXmpMAX_Motors) ||
        (sequenceNumber >= MEIXmpMAX_PSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[-size # (%d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - AXIS_COUNT,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1,
                            MEIXmpMAX_PSs - 1,
                            sequenceSize,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    axisNumber[1] = axisNumber[0] + 1;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motion object for MS number */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Create axis object for X_AXIS number */
    axis[0] =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis[0]));

    /* Create axis object for Y_AXIS number */
    axis[1] =
        mpiAxisCreate(control,
                      axisNumber[1]);
    msgCHECK(mpiAxisValidate(axis[1]));

    /* Create motion axis list */
    returnValue =
        mpiMotionAxisListSet(motion,
                             AXIS_COUNT,
                             axis);
    msgCHECK(returnValue);

    /* Request notification of all events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create motor objects */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          sequenceSize);
    msgCHECK(mpiSequenceValidate(sequence));

#if defined(_DEBUG)
    returnValue =
        meiObjectTraceSet(sequence,
                          MEISequenceTraceLOAD);
    msgCHECK(returnValue);
#endif

    /* Request notification of all events from sequence */
    returnValue =
        mpiSequenceEventNotifySet(sequence,
                                  eventMask,
                                  NULL);
    msgCHECK(returnValue);

    /* CommandTable[commandIndex] */
    commandIndex = 0;

    /* Create motion Commands */
    for (index = 0; index < MOTION_COUNT; index++) {
        MPIMotionParams *motionParams;

        /* mpiMotionStart(motion, type, params); */
        type = MPICommandTypeMOTION;

        commandParams.motion.motionCommand  = MPICommandMotionSTART;
        commandParams.motion.motion         = motion;
        commandParams.motion.type           = motionType;

        motionParams = &commandParams.motion.params;

        switch (motionType) {
            case MPIMotionTypeS_CURVE: {
                motionParams->sCurve = sCurve[index];
                break;
            }
            case MPIMotionTypeTRAPEZOIDAL: {
                motionParams->trapezoidal = trapezoidal[index];
                break;
            }
            case MPIMotionTypeVELOCITY: {
                motionParams->velocity = velocity[index];
                break;
            }
            default: {
                meiASSERT(FALSE);
                break;
            }
        }

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(type,
                             &commandParams,
                             (commandIndex == 0) ? "First" : NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        commandParams.waitEvent.handle  = motion;
        commandParams.waitEvent.oper    = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.waitEvent.mask);
        mpiEventMaskSET(commandParams.waitEvent.mask, MPIEventTypeMOTION_DONE);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_EVENT,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        commandParams.branchEvent.label     = NULL;
        commandParams.branchEvent.handle    = motion;
        commandParams.branchEvent.oper      = MPICommandOperatorBIT_SET;
        mpiEventMaskCLEAR(commandParams.branchEvent.mask);
        mpiEventMaskMOTOR(commandParams.branchEvent.mask);

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeBRANCH_EVENT,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;

        /* while (mpiControlUserIoGet(control, &io), (io.input[0] & mask) == 0); */
        commandParams.waitIO.type           = MPIIoTypeMOTOR;
        commandParams.waitIO.source.motor   = motor;
        commandParams.waitIO.oper           = TRIGGER_STATE;
        commandParams.waitIO.mask           = 0x1 << TRANSCEIVER_WAIT_ID;   /* bit 0 */

        /* Create Command */
        CommandTable[commandIndex] =
            mpiCommandCreate(MPICommandTypeWAIT_IO,
                             &commandParams,
                             NULL);
        msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

        commandIndex++;
    }

    /* MPIEventTypeEXTERNAL */
    commandParams.event.value = ExternalEventSEQUENCE_DONE;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeEVENT,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Create Command */
    CommandTable[commandIndex] =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(CommandTable[commandIndex]));

    commandIndex++;

    /* Create sequence command list */
    returnValue =
        mpiSequenceCommandListSet(sequence,
                                  commandIndex,
                                  CommandTable);
    msgCHECK(returnValue);

    /* Create event notification object */
    notify =
        mpiNotifyCreate(eventMask,      /* Notify of all MPI events */
                        MPIHandleVOID); /* Notify from all sources */
    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 */
    meiASSERT(service != NULL);

    limit =
        fabs(position[0][0] - position[1][0]) /
        (AXIS_COUNT + 2);

    if (position[0][0] < position[1][0]) {
        limitX[0] = position[0][0] + limit;
        limitX[1] = position[1][0] - limit;
    }
    else {
        limitX[0] = position[1][0] + limit;
        limitX[1] = position[0][0] - limit;
    }

    limit =
        fabs(position[0][1] - position[1][1]) /
        (AXIS_COUNT + 2);

    if (position[0][1] < position[1][1]) {
        limitY[0] = position[0][1] + limit;
        limitY[1] = position[1][1] - limit;
    }
    else {
        limitY[0] = position[1][1] + limit;
        limitY[1] = position[0][1] - limit;
    }

    sequenceMonitor =
        monitorPosition(control,
                        motor,
                        axis[0],
                        axis[1],
                        limitX,
                        limitY);
    msgCHECK(mpiSequenceValidate(sequenceMonitor));

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);

    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiSequenceStart() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(2);
    }

    meiPlatformConsole("Press any key to stop sequence\n");

    while (returnValue == MPIMessageOK) {
        MPIEventStatus  status;

        returnValue =
            mpiNotifyEventWait(notify,
                               &status,
                               MPIWaitFOREVER);

        if (returnValue == MPIMessageOK) {
            MEIEventStatusInfo  *info;

            info = (MEIEventStatusInfo *)status.info;

            switch (status.type) {
                case MPIEventTypeNONE: {    /* ignore */
                    meiPlatformConsole("No event ...\n");
                    break;
                }
                case MPIEventTypeAMP_FAULT:
                case MPIEventTypeHOME:
                case MPIEventTypeLIMIT_ERROR:
                case MPIEventTypeLIMIT_HW_NEG:
                case MPIEventTypeLIMIT_HW_POS:
                case MPIEventTypeLIMIT_SW_NEG:
                case MPIEventTypeLIMIT_SW_POS: {    /* error */
                    long    number;

                    number = info->type.number;

                    meiPlatformConsole("Event %d on motor #%d\n",
                                        status.type,
                                        number);

                    break;
                }
                case MPIEventTypeMOTION_DONE: {
                    meiPlatformConsole("Motion done\n");
                    break;
                }
                case MPIEventTypeEXTERNAL: {
                    switch (info->type.value) {
                        case ExternalEventSEQUENCE_DONE: {
                            meiPlatformConsole("Sequence done\n");
                            break;
                        }
                        default: {
                            meiPlatformConsole("Unknown external event: %d\n",
                                                info->type.value);
                            break;
                        }
                    }

                    break;
                }
                default: {
                    break;
                }
            }
        }

        if (returnValue == MPIMessageOK) {
            if (meiPlatformKey(MPIWaitPOLL) >= 0) {
                break;
            }
        }
    }

    meiPlatformConsole("Exiting ... returnValue 0x%x: %s\n",
                        returnValue,
                        mpiMessage(returnValue, NULL));

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequenceMonitor);
    msgCHECK(returnValue);

    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequenceMonitor);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    for (index = 0; index < AXIS_COUNT; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

MPISequence
    monitorPosition(MPIControl  control,
                    MPIMotor    motor,
                    MPIAxis     axisX,
                    MPIAxis     axisY,
                    double      *limitX,
                    double      *limitY)
{
    MPISequence         sequence;
    MPICommand          command;
    MEIMotorConfig      motorConfigXmp;  /* contains transceiver configuration */
    MPICommandParams    commandParams;

    long        numberX;
    long        numberY;
    MEIXmpAxis  *xmpAxisX;
    MEIXmpAxis  *xmpAxisY;
    long        *positionX;
    long        *positionY;

    long    returnValue;

    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    meiASSERT(returnValue == MPIMessageOK);

    motorConfigXmp.Transceiver[TRANSCEIVER_SET_ID].Config = IO_CONFIG;
    motorConfigXmp.Transceiver[TRANSCEIVER_SET_ID].Invert = INVERT_BIT;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    meiASSERT(returnValue == MPIMessageOK);

    returnValue =
        mpiAxisNumber(axisX,
                      &numberX);
    msgCHECK(returnValue);

    returnValue =
        mpiAxisNumber(axisY,
                      &numberY);
    msgCHECK(returnValue);

    returnValue =
        mpiAxisMemory(axisX,
                      (void **)&xmpAxisX);
    msgCHECK(returnValue);

    returnValue =
        mpiAxisMemory(axisY,
                      (void **)&xmpAxisY);
    msgCHECK(returnValue);

    positionX = &xmpAxisX->ActualPosition;
    positionY = &xmpAxisY->ActualPosition;

    sequence =
        mpiSequenceCreate(control,
                          -1,
                          8);
    msgCHECK(mpiSequenceValidate(sequence));

    commandParams.branch.label              = "IoBitClear";
    commandParams.branch.expr.address.l     = positionX;
    commandParams.branch.expr.oper          = MPICommandOperatorLESS;
    commandParams.branch.expr.by.value.l    = (long)limitX[0];

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         "First");
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.branch.label              = "IoBitClear";
    commandParams.branch.expr.address.l     = positionX;
    commandParams.branch.expr.oper          = MPICommandOperatorGREATER;
    commandParams.branch.expr.by.value.l    = (long)limitX[1];

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.branch.label              = "IoBitClear";
    commandParams.branch.expr.address.l     = positionY;
    commandParams.branch.expr.oper          = MPICommandOperatorLESS;
    commandParams.branch.expr.by.value.l    = (long)limitY[0];

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.branch.label              = "IoBitClear";
    commandParams.branch.expr.address.l     = positionY;
    commandParams.branch.expr.oper          = MPICommandOperatorGREATER;
    commandParams.branch.expr.by.value.l    = (long)limitY[1];

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.computeIO.type            = MPIIoTypeMOTOR;
    commandParams.computeIO.source.motor    = motor;
    commandParams.computeIO.oper            = MPICommandOperatorOR;
    commandParams.computeIO.mask            = 0x1 << TRANSCEIVER_SET_ID;    /* Set bit 1 */

    command =
        mpiCommandCreate(MPICommandTypeCOMPUTE_IO,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.branch.label      = "First";
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.computeIO.type            = MPIIoTypeMOTOR;
    commandParams.computeIO.source.motor    = motor;
    commandParams.computeIO.oper            = MPICommandOperatorAND;
    commandParams.computeIO.mask            = ~(0x1 << TRANSCEIVER_SET_ID); /* Clear bit 1 */

    command =
        mpiCommandCreate(MPICommandTypeCOMPUTE_IO,
                         &commandParams,
                         "IoBitClear");
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    commandParams.branch.label      = "First";
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &commandParams,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    return (sequence);
}


seqKill.c -- Program Sequence to monitor an I/O bit and abort all

.

seqKill.c -- Program Sequence to monitor an I/O bit and abort all axes when active.
/* seqkill.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    seqkillMain

argMainRENAME(main, seqkill)
#endif

/*

:Program Sequence to monitor an I/O bit and abort all axes when active.

This sample program creates a program sequencer that will monitor an I/O bit.
 When this I/O bit is set, it will abort all the axes from 0 to axisCount.  It
 will monitor motor 0's transceiver A to determine when to abort the axes.

The XMP program sequencer controls the execution of a single command or a
 series of commands on the XMP controller.  The program sequencer provides the
 ability to execute programs directly on the XMP controller without host
 intervention.  Examples of individual commands that can be executed by the
 program sequencer are motion, looping, conditional branching, computation,
 reading and writing of memory, time delays, waiting for conditions, setting
 inputs/outputs, and generation of events.  This rich command set provides
 capability similar to, and beyond, that provided by Programmable Logic
 Controller (PLC) programs.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#define MOTION_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define AXIS_COUNT      (8)

#define IO_TRIGGER      (MEIXmpMotorIOMaskXCVR_A)

/*
   Active High: MPICommandOperatorBIT_SET
   Active Low : MPICommandOperatorBIT_CLEAR
*/
#define IO_LEVEL        (MPICommandOperatorBIT_SET)

/* 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,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisCount,
                 MPIMotor           *motor,
                 long                motorNumber)
{
    long            index;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axis objects */
    for (index = 0; index < axisCount; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          index);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

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

    /* Write Motion Supervisor AxisMap[], and clear fault conditions */
    returnValue =
        mpiMotionAction(*motion,
                        MPIActionRESET);
    msgCHECK(returnValue);
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl      *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    long             axisCount,
                    MPIMotor        *motor)
{
    long    index;
    long    returnValue;

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis objects */
    for (index = 0; index < axisCount; index++) {
        returnValue = mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*
   sequenceCommandAdd() creates a command (MPICommand object) and appends it to
   sequence's list of commands.  This function does return MPI error codes so
   that sequence setup code may be more easily debugged.

   Warning:  sequenceCommandAdd() does not keep track of created command objects
   so it is important that before a sequence object is deleted, that each
   command object on sequence's list is itself deleted.  Otherwise, there will
   be memory leaks.  One can use sequenceProgramDelete() to accomplish this.
*/
long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label)
{
    MPICommand  command;
    long        returnValue;

    command =
        mpiCommandCreate(commandType,
                         commandParams,
                         label);
    returnValue =
        mpiCommandValidate(command);

    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiSequenceCommandAppend(sequence,
                                     command);
    }

    return returnValue;
}

/*
   sequenceKillProgramCreate() creates a program that waits for one of motor's
   io lines (represented by trigger) to turn on then commands an E_STOP_ABORT.
*/
MPISequence sequenceKillProgramCreate(MPIMotion             motion,
                                      MPIMotor              motor,
                                      MEIXmpMotorIOMask     trigger,
                                      MPICommandOperator    level)
{
    MPISequence         sequence;
    MPICommandParams    commandParams;
    long                returnValue;

    /* Create sequence object */
    sequence =
        mpiSequenceCreate(mpiMotionControl(motion),
                          -1,   /* Use the next available sequence */
                          3);   /* # of commands in sequence */
    msgCHECK(mpiSequenceValidate(sequence));

    /* Wait for motor 0's bit 0 (transceiver A) to be set */
    commandParams.waitIO.type           = MPIIoTypeMOTOR;
    commandParams.waitIO.source.motor   = motor;
    commandParams.waitIO.oper           = level;
    commandParams.waitIO.mask           = trigger;

    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeWAIT_IO,
                           &commandParams,
                           NULL);
    msgCHECK(returnValue);

    /* command an E_STOP_ABORT */
    commandParams.motion.motionCommand  = MPICommandMotionE_STOP_ABORT;
    commandParams.motion.motion     = motion;

    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeMOTION,
                           &commandParams,
                           NULL);
    msgCHECK(returnValue);

    /* Stop sequence */
    commandParams.branch.label      = NULL;
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeBRANCH,
                           &commandParams,
                           NULL);
    msgCHECK(returnValue);

    /* Return the new sequence handle */
    return sequence;
}

/*
   sequenceProgramDelete() removes and deletes all command objects on sequence's
   command list and then deletes sequence.  This function does return MPI error
   codes so that sequence setup code may be more easily debugged.
*/
long sequenceProgramDelete(MPISequence *sequence)
{
    MPICommand  command;
    long        returnValue = MPIMessageOK;

    /* Remove and delete command objects on sequence list */
    while(TRUE) {
        command = mpiSequenceCommandLast(*sequence);
        if ((returnValue != MPIMessageOK) ||
            (command==MPIHandleVOID)) {
            break;
        }
        returnValue =
            mpiSequenceCommandRemove(*sequence,
                                     command);

        if (returnValue == MPIMessageOK) {
            returnValue =
                mpiCommandDelete(command);
        }
    }

    /* Delete sequence object */
    returnValue =
        mpiSequenceDelete(*sequence);

    if (returnValue == MPIMessageOK) {
        /* Make it obvious that sequence is no longer a valid object */
        *sequence = MPIHandleVOID;
    }

    return returnValue;
}

/*
   Starts a sequence, waits for the user to press a key and then
   stops the sequence.
*/
void sequenceRun(MPISequence sequence)
{
    long returnValue;

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    fprintf(stderr,"Press any key to stop sequence.\n");
    meiPlatformKey(MPIWaitFOREVER);
    fprintf(stderr,"Exiting ...\n");

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    if ((returnValue != MPIMessageOK) &&
        (returnValue != MPISequenceMessageSTOPPED)) {
        msgCHECK(returnValue);
    }
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis[MEIXmpMAX_COORD_AXES];     /* axis handles */
    MPIMotor            motor;
    MPISequence         sequence;

    long    returnValue;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                axis,
                AXIS_COUNT,
                &motor,
                MOTOR_NUMBER);

    /* Create sequence program */
    sequence =
        sequenceKillProgramCreate(motion,
                                  motor,
                                  IO_TRIGGER,
                                  IO_LEVEL);

    /* Run sequence */
    sequenceRun(sequence);

    /* Delete sequence program */
    returnValue =
        sequenceProgramDelete(&sequence);
    msgCHECK(returnValue);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motion,
                   axis,
                   AXIS_COUNT,
                   &motor);

    return ((int)returnValue);
}


seqrec.c -- Track status of specified motion supervisors and enable

.

seqrec.c -- Track status of specified motion supervisors and enable data recorder on any motion.
/* seqrec.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Track status of specified motion supervisors and enable data recorder on any motion.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    seqrecMain

argMainRENAME(main, seqrec)
#endif

/* Command line arguments and defaults */
long    sequenceNumber  = 0;

Arg argList[] = {
    {   "-sequence",    ArgTypeLONG,    &sequenceNumber,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPISequence sequence;   /* sequence handle */

    MPICommand  command;

    MEIXmpData  *firmware;

    MPICommandParams    params;

    long    returnValue;    /* return value from library */

    long    index;

    long            motionCount;
    MPIObjectMap    motionMap;

    long    labelCheckMS;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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 (sequenceNumber >= MEIXmpMAX_PSs) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[motion# (0) ...]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_PSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    mpiObjectMapCLEAR(motionMap);

    /* Create motion map */
    if (argIndex >= argc) {
        motionCount = 1;
        mpiObjectMapBitSET(motionMap, 0, 1);    /* MS[0] default */
    }
    else {
        motionCount = 0;

        while (argIndex < argc) {
            char    *arg;
            long    number;

            arg = argv[argIndex++];

            number = meiPlatformAtol(arg);

            if ((number >= 0) &&
                (number < MEIXmpMAX_MSs)) {
                motionCount++;
                mpiObjectMapBitSET(motionMap, number, 1);
            }
            else {
                fprintf(stderr,
                        "%s: invalid motion number\n",
                        arg);
                exit(1);
            }
        }
    }

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-sequence # (0 .. %d)]\n"
                           "\t\t[motion# (0) ...]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_PSs - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    returnValue =
        mpiControlMemory(control,
                         (void **)&firmware,
                         NULL);
    msgCHECK(returnValue);

    /* Create Sequence */
    sequence =
        mpiSequenceCreate(control,
                          sequenceNumber,
                          2 + motionCount + 2); /* sequence size */
    msgCHECK(mpiSequenceValidate(sequence));

    /* Create Commands */

    /* Branch to "CheckMS" if Recorder is ON (!= 0) */
    params.branch.label             = "CheckMS";
    params.branch.expr.address.l    = &firmware->Recorder.Enable;
    params.branch.expr.oper         = MPICommandOperatorNOT_EQUAL;
    params.branch.expr.by.value.l   = 0;

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &params,
                         "RecorderON");
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    /* Turn Recorder ON */
    params.assign.dst.l     = &firmware->Recorder.Enable;
    params.assign.value.l   = -1;   /* continuous, else # records */

    command =
        mpiCommandCreate(MPICommandTypeASSIGN,
                         &params,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    labelCheckMS = FALSE;

    for (index = 0; index < MEIXmpMAX_MSs; index++) {
        if (mpiObjectMapBitGET(motionMap, index) == 0) {
            continue;
        }

        /* Branch to "RecorderOn" if motion detected */
        params.branch.label             = "RecorderON";
        params.branch.expr.address.l    = (long *)&firmware->MS[index].Status;
        params.branch.expr.oper         = MPICommandOperatorBIT_CLEAR;
        params.branch.expr.by.value.l   = (0x1 << MEIXmpEventDONE);

        command =
            mpiCommandCreate(MPICommandTypeBRANCH,
                             &params,
                             (labelCheckMS == FALSE) ? "CheckMS" : NULL);
        msgCHECK(mpiCommandValidate(command));

        labelCheckMS = TRUE;

        returnValue =
            mpiSequenceCommandAppend(sequence,
                                     command);
        msgCHECK(returnValue);
    }

    /* Turn Recorder OFF */
    params.assign.dst.l     = &firmware->Recorder.Enable;
    params.assign.value.l   = 0;

    command =
        mpiCommandCreate(MPICommandTypeASSIGN,
                         &params,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    /* Branch to "CheckMS" */
    params.branch.label     = "CheckMS";
    params.branch.expr.oper = MPICommandOperatorALWAYS;

    command =
        mpiCommandCreate(MPICommandTypeBRANCH,
                         &params,
                         NULL);
    msgCHECK(mpiCommandValidate(command));

    returnValue =
        mpiSequenceCommandAppend(sequence,
                                 command);
    msgCHECK(returnValue);

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);

    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "%s: mpiSequenceStart() returns 0x%x: %s\n",
                        argv[0],
                        returnValue,
                        mpiMessage(returnValue, NULL));
        exit(returnValue);
    }

    meiPlatformConsole("Press any key to stop sequence\n");
    meiPlatformKey(MPIWaitFOREVER);

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    msgCHECK(returnValue);

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


settle1.c -- Configure in-position tolerance and settling time for

.

settle1.c -- Configure in-position tolerance and settling time for an axis.
/* settle1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure in-position tolerance and settling time for an axis.

A simple settling configuration which sets the Fine Position Tolerance
 and Settling Time for an axis.  Both are required for the
 MEIXmpStatusIN_FINE_POSITION status bit.  The settling criteria are:

    1)  The absolute value of the position error is less than or equal to
        the fine position tolerance.
    2)  The absolute value of the velocity is less than or equal to the
        velocity tolerance.
    3)  Both criteria 1 and 2 above have been satisfied for the settling
        time.  Whenever either criteria 1 or 2 is not satisfied,
        IN_FINE_POSITION is cleared and the settling tier is reset.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    settle1Main

argMainRENAME(main, settle1)
#endif

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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

int
    main(int    argc,
         char   *argv[])
{
    MPIControl      control;        /* Motion controller handle */
    MPIAxis         axis;           /* Axis handle(s) */

    MPIAxisConfig   axisConfig;     /* Axis configuration */

    long    returnValue;            /* Return value from library */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object on controller*/
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    /* Configure axis */
    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    axisConfig.inPosition.tolerance.positionFine = (float)50.0;
    axisConfig.inPosition.tolerance.velocity     = (float)100.0;
    axisConfig.inPosition.settlingTime           = (float)0.5; /* .5 seconds */

    returnValue =
        mpiAxisConfigSet(axis,
                         &axisConfig,
                         NULL);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


settle2.c -- Configure settling criteria and exception event settling

.

settle2.c -- Configure settling criteria and exception event settling conditions.
/* settle2.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure settling criteria and exception event settling conditions.

The MPI supports axis configurations for motion settling criteria to
 determine when motion is complete.  The XMP-Series controller supports
 event notification for Coarse, Fine, and Target positions and motion done.
 Generally, settling criteria is only applicable to normal host commanded
 motion profiles.  The XMP-Series controller can also be configured to
 support settling criteria with Stop and E-Stop events.

The settling criteria is configured set with mpiAxisConfigGet/Set(...),
 using the structures:

typedef struct MPIAxisInPosition {
    struct {
        float   positionFine;
        long    positionCoarse;
        float   velocity;
    } tolerance;
    float   settlingTime;
    long    settleOnStop;
    long    settleOnEstop;
} MPIAxisInPosition;

typedef struct MPIAxisConfig {
    MPIAxisInPosition   inPosition;
    MPIObjectMap    filterMap;
} MPIAxisConfig;

The settling criteria are:

 positionFine - in-position window between command and actual (counts)

 positionCoarse - in-position window between target and actual (counts)

 velocity - actual velocity (counts/second)

 settlingTime - required time for settling (seconds)

The Stop and E-Stop event settling conditions can be enabled/disabled:

 settleOnStop - TRUE or FALSE, enables/disables settling criteria for Stop

 settleOnEstop - TRUE or FALSE, enables/disables settling criteria for E-Stop

The XMP-Series controller sets the appropriate status bits and generates
 the following events based on the settling criteria and logic:

 IN_FINE_POSITION

    1) |command position - actual position| < positionFine tolerance
    2) |command velocity - actual velocity| < velocity tolerance
    3) 1,2 and 3 have been satisfied for the settlingTime tolerance

 IN_COARSE_POSITION

    1) |target position - actual position| < postionCoarse tolerance

 AT_TARGET

    1) The command position = target position.

 DONE

    1) The calculated trajectory is complete.
    2) IN_FINE_POSITION conditions have been satisfied.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    settle2Main

argMainRENAME(main, settle2)
#endif

#define MOTION_COUNT        (1)     /* Number of motion profiles */
#define AXIS_COUNT          (1)     /* Number of axes */

/* Command line arguments and defaults */
long            axisNumber[AXIS_COUNT] = { 0,   };
long            motionNumber    = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;
float           fineTol         = (float)500.0; /* counts */
long            coarseTol       = 200;          /* counts */
float           velocityTol     = (float)1.0;   /* counts/sec */
float           settlingTime    = (float)0.2;   /* seconds */
long            eventDelay      = 1000;         /* milliseconds */

Arg argList[] = {
    {   "-axis",    ArgTypeLONG,    &axisNumber[0], },
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-type",    ArgTypeLONG,    &motionType,    },
    {   "-fine",    ArgTypeFLOAT,   &fineTol,       },
    {   "-coarse",  ArgTypeLONG,    &coarseTol,     },
    {   "-velocity",ArgTypeFLOAT,   &velocityTol,   },
    {   "-settling",ArgTypeFLOAT,   &settlingTime,  },
    {   "-delay",   ArgTypeLONG,    &eventDelay,    },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[][AXIS_COUNT] = {
    { 20000.0,  },
    { 0.0,  },
};

MPITrajectory trajectory[][AXIS_COUNT] = {
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
    {   /* velocity     accel       decel       jerkPercent */
        { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    },
};

/* Motion parameters */

MPIMotionSCurve sCurve[] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionTrapezoidal    trapezoidal[] = {
    {   &trajectory[0][0],  &position[0][0],    },
    {   &trajectory[1][0],  &position[1][0],    },
};

MPIMotionVelocity   velocity[] = {
    {   &trajectory[0][0],  },
    {   &trajectory[1][0],  },
};

#define SETTLE_EVENTS   (2) /* Number of settle configurations */

/* Settle on Stop/E-Stop Events */
long settleEvent[] = {
    FALSE,
    TRUE
};

#define ACTIONS         (5) /* Number of MPI actions */

/* Generate Actions */
MPIAction action[] = {
    MPIActionNONE,
    MPIActionSTOP,
    MPIActionE_STOP,
    MPIActionE_STOP_ABORT,
    MPIActionABORT
};

char * actionString[] = {
    "None",
    "Stop",
    "E-Stop",
    "E-Stop/Abort",
    "Abort"
};

void eventStatusDisplay(MPIEventStatus status);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* Motion controller handle */
    MPIAxis     axis;       /* Axis object */
    MPIMotion   motion;     /* Motion object */
    MPINotify   notify;     /* Event notification object */
    MPIEventMgr eventMgr;   /* Event manager handle */

    MPIAxisConfig   axisConfig; /* Axis configuration object */

    MPIEventMask    eventMask;

    long    returnValue;    /* Return value from library */

    long    index;
    long    actionIndex;    /* Index to action[...] array */
    long    settleIndex;    /* Index to settleEvent[...] array */
    long    motionDone;     /* Flag when Done occurs */
    long    previousEvents; /* Flag to check for previously generated events */

    double  actual;         /* Axis position */
    double  origin;         /* Axis origin */

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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[0] > (MEIXmpMAX_Axes - AXIS_COUNT)) ||
        (motionNumber  >= MEIXmpMAX_MSs) ||
        (motionType <  MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST) ||
        (fineTol < 0.0) ||
        (coarseTol < 0) ||
        (velocityTol < 0.0) ||
        (settlingTime < 0.0) ||
        (eventDelay < 0)) {
        printf("usage: %s %s\n"
               "\t\t[-axis # (0 .. %d)]\n"
               "\t\t[-motion # (0 .. %d)]\n"
               "\t\t[-type # (0 .. %d)]\n"
               "\t\t[-fine # (0.0 .. )]\n"
               "\t\t[-coarse # (0 .. )]\n"
               "\t\t[-velocity # (0.0 .. )]\n"
               "\t\t[-settling # (0.0 .. )]\n"
               "\t\t[-delay # (0 .. )]\n",
                argv[0],
                ArgUSAGE,
                MEIXmpMAX_Axes - AXIS_COUNT,
                MEIXmpMAX_MSs - 1,
                MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber[0]);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);      /* ALL sources */
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    meiPlatformConsole("Press any key to quit ...\n");

    /* Loop repeatedly */
    index       = 0;
    actionIndex = 0;
    settleIndex = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MPIStatus           status;

        if (motionDone) {
            MPIMotionParams     motionParams;       /* Motion parameters */

            /* Fill in the MPIMotionParams structure */
            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            /* Check motion status for any error conditions */
            returnValue =
                mpiMotionStatus(motion,
                                &status,
                                NULL);
            msgCHECK(returnValue);

            if (status.state == MPIStateERROR) {
                returnValue =
                    mpiMotionAction(motion,
                                    MPIActionRESET);
                msgCHECK(returnValue);

                printf("  Error state cleared.\n");
            }

            /* Set origin to current actual position */
            returnValue =
                mpiAxisActualPositionGet(axis,
                                         &actual);
            msgCHECK(returnValue);

            returnValue =
                mpiAxisOriginGet(axis,
                                 &origin);
            msgCHECK(returnValue);

            returnValue =
                mpiAxisOriginSet(axis,
                                 (origin + actual));
            msgCHECK(returnValue);

            /* Configure axis settling criteria */
            returnValue =
                mpiAxisConfigGet(axis,
                                 &axisConfig,
                                 NULL);
            msgCHECK(returnValue);

            axisConfig.inPosition.tolerance.positionFine =
                fineTol;
            axisConfig.inPosition.tolerance.positionCoarse =
                coarseTol;
            axisConfig.inPosition.tolerance.velocity =
                velocityTol;
            axisConfig.inPosition.settlingTime =
                settlingTime;

            /* Configure settling criteria for Stop and E-Stop events
                TRUE = use settling criteria for Stop and E-Stop
                FALSE = do NOT use settling criteria for Stop and E-Stop
            */
            axisConfig.inPosition.settleOnStop = settleEvent[settleIndex];
            axisConfig.inPosition.settleOnEstop = settleEvent[settleIndex];

            returnValue =
                mpiAxisConfigSet(axis,
                                 &axisConfig,
                                 NULL);
            msgCHECK(returnValue);

            /* Check for any previous events (generated by RESET) */
            previousEvents = TRUE;
            while (previousEvents) {
                returnValue =
                    mpiNotifyEventWait(notify,
                                       &eventStatus,
                                       MPIWaitPOLL);
                if (returnValue == MPIMessageTIMEOUT) {
                    previousEvents = FALSE;
                }
                else {
                    msgCHECK(returnValue);
                    eventStatusDisplay(eventStatus);
                }
            }

            meiPlatformConsole("\nMotion Start, Target= %12.0lf  ",
                   position[index][axisNumber[0]]);

            meiPlatformConsole("  Settle on Event: %s",
                   settleEvent[settleIndex] ? "yes" : "no");

            /* Point to point motion (relative to new origin) */
            returnValue =
                mpiMotionStart(motion,
                               motionType,
                               &motionParams);
            msgCHECK(returnValue);

            /* Wait for motion profile to partially execute */
            meiPlatformSleep(eventDelay);

            /* Generate an event */
            returnValue =
                mpiMotionAction(motion,
                                action[actionIndex]);
            msgCHECK(returnValue);

            meiPlatformConsole("  Event:%s.\n", actionString[actionIndex]);

            /* Increment through settleEvent[...] and action[...] */
            if (++actionIndex >= ACTIONS) {
                actionIndex = 0;
                if (++settleIndex >= SETTLE_EVENTS) {
                    settleIndex = 0;
                }
            }
            motionDone = FALSE;
        }

        /* Wait for motion event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        /* Motion Done Event from motion source */
        if  (eventStatus.type == MPIEventTypeMOTION_DONE) {
            motionDone = TRUE;

            if (++index >= MOTION_COUNT) {
                index = 0;
            }
        }
        eventStatusDisplay(eventStatus);
    }

    printf("\n");

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

void eventStatusDisplay(MPIEventStatus status)
{
    MEIEventStatusInfo  *info;

    info = (MEIEventStatusInfo *)status.info;

    switch (status.type) {
        /* In Coarse Event from axis source */
        case MEIEventTypeIN_POSITION_COARSE: {
            meiPlatformConsole("  InCoarse, actual:%ld, sample:0x%x\n",
                   info->data.axis.actualPosition,
                   info->data.axis.sampleCounter);
            break;
        }
        /* In Fine Event from axis source */
        case MEIEventTypeIN_POSITION_FINE: {
            meiPlatformConsole("  InFine, actual:%ld, sample:0x%x\n",
                   info->data.axis.actualPosition,
                   info->data.axis.sampleCounter);
            break;
        }
        /* At Target Event from axis source */
        case MEIEventTypeAT_TARGET: {
            meiPlatformConsole("  AtTarget, actual:%ld, sample:0x%x\n",
                   info->data.axis.actualPosition,
                   info->data.axis.sampleCounter);
            break;
        }
        /* Motion Done Event from motion source */
        case MPIEventTypeMOTION_DONE: {
            meiPlatformConsole("  Done, sample:0x%x\n",
                   info->data.motion.sampleCounter);
            break;
        }
        default: {
            meiPlatformConsole("Event (unexpected): %ld (0x%x)",
                   status.type,
                   info->data.word[0]);
            break;
        }
    }
}


shape.c -- Configure Trajectory Shaping Filters

.

shape.c -- Configure Trajectory Shaping Filters
/* shape.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Configure Trajectory Shaping Filters

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 <ctype.h>

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    shapeMain

argMainRENAME(main, shape)
#endif

typedef struct SHAPER {
    long    Index;
    long    Axis;
    long    Length;
    long    MaxDelay;
    long    MaxAmp;
    double  TimeStep;
    long    Time[MEIXmpMAX_PreCoeffs/2];
    long    Amp[MEIXmpMAX_PreCoeffs/2];
} SHAPER;

long
    loadShaper(MPIControl   control,
               SHAPER       *shaper);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl          control;    /* motion controller handle */
    MPIControlConfig    config;

    SHAPER      shaper;

    char    *fileName;
    FILE    *fp;
    char    buffer[256];
    long    shaperCount;
    long    shaperCountOld;

    long    returnValue;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &controlAddress);

    fileName =
        (argIndex >= argc)
                ? "shape.txt"
                : argv[argIndex++];

    if (argIndex < argc) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[fileName (%s)]\n",
                           argv[0],
                           ArgUSAGE,
                           "shape.txt");
        exit(0);
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    fp = fopen(fileName, "r");

    if (fp == NULL) {
        fprintf(stderr,
                "shape.txt not found.\n");
        exit(2);
    }

    returnValue =
        mpiControlConfigGet(control,
                            &config,
                            NULL);
    msgCHECK(returnValue);

    shaperCount = 0;
    shaperCountOld = -1;

    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        long    axis;
        long    length;
        long    maxAmp;
        long    maxDelay;

        char    *ptr;

        if (shaperCount > shaperCountOld) {
            shaper.Axis     = -1;   /* Make sure all params are read from file */
            shaper.MaxAmp   = -1;
            shaper.Length   =  0;
            shaper.MaxDelay = -1;
            shaper.TimeStep = 1.0 / config.sampleRate;

            shaperCountOld = shaperCount;
        }

        for (ptr = buffer; *ptr != '\0'; ptr++) {
            char    byte = *ptr;

            if (isupper(byte)) {
                *ptr = (char)tolower(byte);
            }
        }

        if (sscanf(buffer, "#AXIS  = %d", &axis) == 1) {
            shaper.Axis = axis;
            continue;
        }

        if (sscanf(buffer, "#IMPULSES = %d", &length) == 1) {
            shaper.Length = length;
            continue;
        }

        if (sscanf(buffer, "#AMPSUM = %d", &maxAmp) == 1) {
            shaper.MaxAmp = maxAmp;
            continue;
        }

        if (sscanf(buffer, "#STEPS = %d", &maxDelay) == 1) {
            shaper.MaxDelay = maxDelay;
            continue;
        }

        if (strncmp(buffer, "#TIME", 5) == 0) {
            long    sum;
            long    maxTime;
            long    index;

            sum = 0;
            maxTime = 0;

            for (index = 0; index < shaper.Length; index++) {
                long    time;
                long    amp;

                if (fgets(buffer, sizeof(buffer), fp) == NULL) {
                    fprintf(stderr,
                            "Unexpected end-of-file\n");
                    return ((int)returnValue);

                }

                if (sscanf(buffer, "%d %d", &time, &amp) == 2) {
                    shaper.Time[index]  = time;
                    shaper.Amp[index]   = amp;
                    sum += amp;

                    if (time > maxTime) {
                        maxTime = time;
                    }
                }
            }

            if (sum != shaper.MaxAmp) {
                fprintf(stderr,
                        "Sum of amplitudes (%d) does not equal AmpSum (%d).\n",
                        sum,
                        shaper.MaxAmp);
                return ((int)returnValue);
            }

            if (maxTime != shaper.MaxDelay) {
                fprintf(stderr,
                        "Maximum time (%d) does not equal Steps (%d).\n",
                        maxTime,
                        shaper.MaxDelay);
                return (returnValue);
            }

            if (axis < 0) {
                fprintf(stderr,
                        "No #Axis statement.\n");
                return (returnValue);
            }
            else {
                shaper.Index = shaperCount;

                if (shaperCount >= MEIXmpMAX_PreFilters) {
                    fprintf(stderr,
                            "Too many shapers.\n");
                    break;
                }
                else {
                    double  scale;

                    /* Rescale for XMP filter normalization */
                    scale = (double)MEIXmpFILTER_SCALE / (double)shaper.MaxAmp;

                    sum = 0;

                    for (index = 0; index < shaper.Length - 1; index++) {
                        shaper.Amp[index] = (long)(shaper.Amp[index] * scale);
                        sum += shaper.Amp[index];
                    }
                    shaper.Amp[shaper.Length - 1] = MEIXmpFILTER_SCALE - sum;

                    loadShaper(control,
                               &shaper);

                    fprintf(stderr,
                            "Axis %d shaper loaded.\n",
                            axis);

                    shaperCount++;
                }
            }
        }
    }
    fclose(fp);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long
    loadShaper(MPIControl   control,
               SHAPER       *shaper)
{
    MEIXmpData          *firmware;
    MEIXmpBufferData    *external;

    MPIAxis axis;

    MPIControlConfig    controlConfig;
    MEIControlConfig    controlConfigXmp;
    MPIAxisConfig       axisConfig;
    MEIAxisConfig       axisConfigXmp;

    long    returnValue;

    long    index;
    long    axisNumber;
    long    length;
    long    delayTime;

    /* Get pointer to XMP firmware */
    returnValue =
        mpiControlMemory(control,
                         (void **)&firmware,
                         (void **)&external);
    msgCHECK(returnValue);

    index      = shaper->Index;
    axisNumber = shaper->Axis;

    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         &axisConfigXmp);
    msgCHECK(returnValue);

    /* Set command position to Filter input (disable filter) */
    axisConfigXmp.Filter.Pointer    = &firmware->Axis[axisNumber].TC.Filter.Input;
    axisConfigXmp.Filter.Delay      = 0;

    returnValue =
        mpiAxisConfigSet(axis,
                         &axisConfig,
                         &axisConfigXmp);
    msgCHECK(returnValue);

    returnValue =
        mpiControlConfigGet(control,
                            &controlConfig,
                            &controlConfigXmp);
    msgCHECK(returnValue);

    controlConfigXmp.PreFilter[index].Type      = MEIXmpFilterTypeSHAPING;
    controlConfigXmp.PreFilter[index].Length    = shaper->Length;
    controlConfigXmp.PreFilter[index].Input     = &firmware->Axis[axisNumber].TC.Filter.Input;
    controlConfigXmp.PreFilter[index].Coeff[0]  = 0;

    for (length = 0; length < shaper->Length; length++) {
        controlConfigXmp.PreFilter[index].Coeff[2 * length + 1] =
            shaper->Time[length];
        controlConfigXmp.PreFilter[index].Coeff[2 * length + 2] =
            shaper->Amp[length];
    }

    if (controlConfigXmp.preFilterCount < (index+1)) {
        controlConfigXmp.preFilterCount = (index + 1);
    }

    returnValue =
        mpiControlConfigSet(control,
                            &controlConfig,
                            &controlConfigXmp);
    msgCHECK(returnValue);

    /* 2x max delay */
    delayTime = 2 * (long)(shaper->MaxDelay * shaper->TimeStep * 1000.0);

    meiPlatformSleep(delayTime);    /* wait for filter to initialize */

    returnValue =
        mpiAxisConfigGet(axis,
                         &axisConfig,
                         &axisConfigXmp);
    msgCHECK(returnValue);

    /* Set command position pointer to Output of shaper */
    axisConfigXmp.Filter.Pointer    = &external->PreFilter[index].Output;
    axisConfigXmp.Filter.Delay      = shaper->MaxDelay;

    returnValue =
        mpiAxisConfigSet(axis,
                         &axisConfig,
                         &axisConfigXmp);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    return (returnValue);
}


SQAlarm1.c -- Check for AMP faults and warnings on all SynqNet drives

.

SQAlarm1.c -- Check for AMP faults and warnings on all SynqNet drives
/* SQAlarm1.c */

/* Copyright(c) 2001-2003 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.
 */

/*

:Check for AMP faults and warnings on all SynqNet drives

This program demonstrates how to retrieve SynqNet amplifier faults
and warnings from all motor objects on SynqNet nodes.

Not all SynqNet amplifiers support faults and warnings.  This code
catches the MEISynqNetMessageSRVC_UNSUPPORTED_FIRST thru LAST return
codes.

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.

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

#include

#include "stdmpi.h"
#include "stdmei.h"

#include "sqNodeLib.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    SQAlarm1Main
argMainRENAME(main, SQAlarm1)
#endif

/* Parse the command line */
long parseCommandLine(int                argc,
                      char               *argv[],
                      long               *synqNetNumber,
                      MPIControlType     *controlType,
                      MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-synqNet", ArgTypeLONG,    &synqNetNumber, },
        {   NULL,       ArgTypeINVALID, NULL,           }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
        argv,
        controlType,
        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) {
        fprintf(stderr,"usage: %s %s\n"
                "\t\t[-synqNet # (0 .. %d)]\n",
                argv[0],
                ArgUSAGE,
                MEIXmpMaxSynqNets - 1);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/* Create and initialize MPI objects */
void programInit(MPIControl        *control,
                 MPIControlType    controlType,
                 MPIControlAddress *controlAddress,
                 MEISynqNet        *synqNet,
                 long              synqNetNumber)
{
    long returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create SynqNet object */
    *synqNet =
        meiSynqNetCreate(*control,
                         synqNetNumber);
    msgCHECK(meiSynqNetValidate(*synqNet));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
                    MEISynqNet *synqNet)
{
    long returnValue;

    returnValue =
        meiSynqNetDelete(*synqNet);
    msgCHECK(returnValue);

    *synqNet = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Report Motor Faults */
void reportMotorFaults(MPIMotor         motor,
                       long             nodeNumber,
                       MEISqNodeInfo    sqNodeInfo)
{
    MEIMotorInfo        motorInfo;
    MEIMotorAmpFaults   faults;
    MEIMotorAmpWarnings warnings;
    long                returnValue;
    long                motorNumber;

    returnValue =
        mpiMotorNumber(motor, &motorNumber);
    msgCHECK(returnValue);

    printf("\n\n"
           "Node[%d] - %s, Motor %d\n"
           "========================================\n",
           nodeNumber,
           sqNodeInfo.id.nodeName,
           motorNumber);

    returnValue =
        meiMotorInfo(motor,
                     &motorInfo);
    msgCHECK(returnValue);

    /* read faults */
    returnValue =
        meiMotorAmpFault(motor, &faults);

    if (returnValue != MPIMessageUNSUPPORTED) {
        if (returnValue == MPIMessageOK) {

            /* display faults */
            if (faults.count != 0) {
                long nodeIndex;

                printf("Faults:\n");
                for (nodeIndex=0; nodeIndex<faults.count; nodeIndex++) {
                   printf("    code %3.3x : Msg: %s\n",
                        faults.code[nodeIndex],
                        faults.message[nodeIndex]);
                }
            }
            else {
                printf("No Faults\n");
            }
        }
    }
    else {
        printf("Fault codes not supported\n");
        returnValue = MPIMessageOK;
    }

    /* read warnings */
    returnValue =
        meiMotorAmpWarning(motor, &warnings);

    if (returnValue != MPIMessageUNSUPPORTED) {

       if (returnValue == MPIMessageOK) {
            /* display warnings */
            if (warnings.count != 0) {
                long nodeIndex;

                printf("Warnings:\n");
                for (nodeIndex=0; nodeIndex<warnings.count; nodeIndex++) {
                    printf("    code %3.3x : Msg: %s\n",
                        warnings.code[nodeIndex],
                        warnings.message[nodeIndex]);
                }
            }
            else {
                printf("No Warnings\n");
            }
        }
    }
    else {
        printf("Warning codes not supported\n");
        returnValue = MPIMessageOK;
    }

    msgCHECK(returnValue);
}

/* For each motor on a SynqNet network, call reportMotorFaults */
void forEachMotorOnSyqnNet_ReportMotorFaults(MPIControl control,
                                             MEISynqNet synqNet)
{
    MPIMotor        motor;
    MEISqNode       sqNode;
    MEISqNodeInfo   sqNodeInfo;
    MEISynqNetInfo  synqNetInfo;
    long            returnValue;
    long            nodeIndex, motorIndex;
    long            motorFirst, motorLast;

    returnValue =
        meiSynqNetInfo(synqNet,
                       &synqNetInfo);
    msgCHECK(returnValue);

    /* loop over nodes */
    for (nodeIndex=0; nodeIndex<synqNetInfo.nodeCount; nodeIndex++) {
      sqNode =
            meiSqNodeCreate(control, nodeIndex);
        msgCHECK(meiSqNodeValidate(sqNode));

        returnValue =
            meiSqNodeInfo(sqNode, &sqNodeInfo);
        msgCHECK(returnValue);

        motorFirst = sqNodeInfo.motorOffset;
        motorLast  = sqNodeInfo.motorOffset + sqNodeInfo.motorCount;

        /* loop over motors */
        for (motorIndex=motorFirst; motorIndex<motorLast; motorIndex++) {

            /* create motor */
            printf("\n  Motor[%d]\n",motorIndex);
            motor =
                mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Report Motor Faults */
            reportMotorFaults(motor, nodeIndex, sqNodeInfo);

            returnValue =
                mpiMotorDelete(motor);
            msgCHECK(returnValue)

        }

        returnValue =
            meiSqNodeDelete(sqNode);
        msgCHECK(returnValue)
    }
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEISynqNet          synqNet;
    long                synqNetNumber = 0;
    long                returnValue;

    /* Parse command line */
    returnValue =
        parseCommandLine(argc,
                         argv,
                         &synqNetNumber,
                         &controlType,
                         &controlAddress);
    msgCHECK(returnValue);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &synqNet,
                synqNetNumber);

    /* For each motor on a SynqNet network, call reportMotorFaults */
    forEachMotorOnSyqnNet_ReportMotorFaults(control,
                                            synqNet);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &synqNet);

    return ((int)returnValue);
}


SQcmd1.c -- How to send a service command to a SynqNet Node

.

SQcmd1.c -- How to send a service command to a SynqNet Node.
/* SQcmd1.c */

/* Copyright(c) 2001-2003 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.
 */

/*

:This sample code demonstrates how to send a service command to a SynqNet Node.

User inputs address and data for the sqNode command, and receives a response.
The response is output to the console.
This routine is useful for configuring node features that are not part of the
general sqNode interface.

    meiSqNodeCommand(MEISqNode              sqNode,
                    MEISqNodeCommand        *command,
                    MEISqNodeResponse       *response);

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    SQcmd1Main
argMainRENAME(main, SQcmd1)
#endif

#define NODE_NUMBER (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);
    }
}

/* Create and initialize MPI objects */
void programInit(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MEISqNode          *sqNode,
                 long                nodeNumber)
{
    long    returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    /* Create SynqNet Node object */
    *sqNode =
        meiSqNodeCreate(*control,
                        nodeNumber);
    msgCHECK(meiSqNodeValidate(*sqNode));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
                    MEISqNode  *sqNode)
{
    long    returnValue;

    /* Delete sqNode handle */
    returnValue =
        meiSqNodeDelete(*sqNode);
    msgCHECK(returnValue);

    *sqNode = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Demonstrate how to perform a SynqNet node command */
void performNodeCommand(MEISqNode sqNode)
{
    MEISqNodeCommand        command;
    MEISqNodeResponse       response;
    long                    returnValue;

    command.address = 0x00010000;   /* READ_ID       */
    command.data    = 0x00;         /* Dev/Vendor ID */

    command.header.channel  = MEISqNodeChannelNODE;
    command.header.memory   = MEISqNodeMemoryDATA;
    command.header.size     = MEISqNodeDataSize32BIT;
    command.header.type     = MEISqNodeCmdTypeREAD;

    /* Send command and get response across SynqNet */
    returnValue =
        meiSqNodeCommand(sqNode,
                         &command,
                         &response);
    msgCHECK(returnValue);

    printf("\n Response: 0x%x\n\n", response.data);
}

int main(int    argc,
         char   *argv[])
{
    MPIControl              control;
    MPIControlType          controlType;
    MPIControlAddress       controlAddress;
    MEISqNode               sqNode;
    long                    nodeNumber = NODE_NUMBER;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &sqNode,
                nodeNumber);

    /* Demonstrate how to perform a SynqNet node command */
    performNodeCommand(sqNode);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &sqNode);

    return 0;
}


SQEStop1.c -- SynqNet Emergency Stop configuration

.

SQEStop1.c -- SynqNet Emergency Stop configuration.
/* SQEStop1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:SynqNet Emergency Stop configuration.

The SynqNet Node User Fault can be configured to trigger from any controller
 memory address.  When the masked value at the specified address matches the
 pattern, the user fault is active.  The User Fault triggers an action for
 all the motors associated with the node.

Typically, the User Fault is configured to monitor the Node Disable input on
 each node or a controller User Input, which are connected to the machine's
 master Emergency Stop button.

The User Fault can also be configured to trigger a node IoAbort if the
 userFault flag in MEISqNodeConfigIoAbort{} is enabled.

This sample demonstrates how to configure the User Fault to trigger from a
 local controller user input.  And it shows how to configure each motor to
 generate an ABORT action when the user input is activated.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define	main	SQEStop1Main

argMainRENAME(main, SQEStop1)
#endif

/* Command line arguments and defaults */
long	nodeCount	= 1;
long	motorCount	= 4;

Arg	argList[] = {
    {   "-nodeCount",      ArgTypeLONG,     &nodeCount,   },
    {   "-motorCount",     ArgTypeLONG,     &motorCount,  },

    {   NULL,              ArgTypeINVALID,  NULL,         }
};

int
        main(int     argc,
        char         *argv[])
{
        MPIControl              control;
        MPIControlType          controlType;
        MPIControlAddress       controlAddress;

        MPIMotor                motor;
        MPIMotorConfig          motorConfig;
        MEIMotorConfig          motorConfigXmp;
        MEIXmpData              *firmware;

        MEISqNode               sqNode;
        MEISqNodeConfig         nodeConfig;

        long                    argIndex;
        long                    returnValue;
        long                    nodeIndex;
        long                    motorIndex;

        /* Parse command line for Control type and address */
        argIndex =
              argControl(argc,
                         argv,
                         &controlType,
                         &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) ||
            (nodeCount >= MEIXmpMaxMotionBlocks) ||
            (motorCount >= MEIXmpMAX_Motors)) {
             meiPlatformConsole("usage: %s %s\n",
                                "\t\t[-nodeCount (0 .. %d)]\n"
                                "\t\t[-motorCount (0 .. %d)]\n",
                                argv[0],
                                ArgUSAGE,
                                MEIXmpMaxMotionBlocks,
                                MEIXmpMAX_Motors);
             exit(MPIMessageARG_INVALID);
        }

        /* Create a control object */
        control =
               mpiControlCreate(controlType,
                                &controlAddress);
        msgCHECK(mpiControlValidate(control));

        /* Initialize the controller */
        returnValue = mpiControlInit(control);
        msgCHECK(returnValue);

        /* Read the controller memory address */
        returnValue =
        mpiControlMemory(control,
                         &firmware,
                         NULL);
        msgCHECK(returnValue);

        /* Configure userFaults for each node to monitor a controller input bit. */
        for (nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) {
               /* Create a sqNode object */
               sqNode =
                    meiSqNodeCreate(control,
                    nodeIndex);
               msgCHECK(meiSqNodeValidate(sqNode));

               returnValue =
                    meiSqNodeConfigGet(sqNode,
                                       &nodeConfig,
                                       NULL);
               msgCHECK(returnValue);

               /* Trigger on Controller's User Input #0 */
               nodeConfig.userFault.addr = firmware->SystemData.IO.Input[0].Ptr;
               nodeConfig.userFault.mask = MEIControlInputUSER_0;
               nodeConfig.userFault.pattern = MEIControlInputUSER_0;

               returnValue =
                     meiSqNodeConfigSet(sqNode,
                                        &nodeConfig,
                                        NULL);
               msgCHECK(returnValue);

               /* Delete object handles */
               returnValue = meiSqNodeDelete(sqNode);
               msgCHECK(returnValue);
        }

        /* Configure the motors associated with each sqNode to generate
        an action when the userFault is activated.
        */
        for (motorIndex = 0; motorIndex < motorCount; motorIndex++ ) {
                /* Create a motor object */
                motor =
                      mpiMotorCreate(control,
                                     motorIndex);
                msgCHECK(mpiMotorValidate(motor));

                returnValue =
                      mpiMotorConfigGet(motor,
                                        &motorConfig,
                                        &motorConfigXmp);
                msgCHECK(returnValue);

                /* ABORT action when userFault is triggered */
                motorConfigXmp.userFaultAction = MEIXmpStatusABORT;
                motorConfig.abortDelay   = 0.5;     /* seconds */

                returnValue =
                      mpiMotorConfigSet(motor,
                                        &motorConfig,
                                        &motorConfigXmp);
                msgCHECK(returnValue);

                /* Delete object handles */
                returnValue = mpiMotorDelete(motor);
                msgCHECK(returnValue);
        }

        /* Delete object handles */
        returnValue = mpiControlDelete(control);
        msgCHECK(returnValue);

    return ((int)returnValue);
}


SQEvent1.c -- Display SynqNet Events

.

SQEvent1.c -- Display SynqNet Events
/* SQEvent1.c */

/* Copyright(c) 2001-2003 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.
 */

/*

:Display SynqNet Events

This is a simple program to demonstrate how to use the EventMgr to catch
 SynqNet events, read the event message and display the event's information.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    SQEvent1Main
argMainRENAME(main, SQEvent1)
#endif

#define WAIT_TIME       (200)   /* msec */

/* Parse the command line */
long parseCommandLine(int                 argc,
                      char               *argv[],
                      long               *synqNetNumber,
                      MPIControlType     *controlType,
                      MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-synqNet", ArgTypeLONG,    &synqNetNumber, },
        {   NULL,       ArgTypeINVALID, NULL,           }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
        argv,
        controlType,
        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) {
        fprintf(stderr,"usage: %s %s\n"
            "\t\t[-synqNet # (0 .. %d)]\n",
            argv[0],
            ArgUSAGE,
            MEIXmpMaxSynqNets - 1);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/* Create and initialize MPI objects */
void programInit(MPIControl        *control,
                 MPIControlType     controlType,
                 MPIControlAddress *controlAddress,
                 MEISynqNet        *synqNet,
                 long               synqNetNumber,
                 MPINotify         *notify,
                 MPIEventMgr       *eventMgr,
                 Service           *service)
{
    MPIEventMask    eventMask;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create SynqNet object */
    *synqNet =
        meiSynqNetCreate(*control,
                         synqNetNumber);
    msgCHECK(meiSynqNetValidate(*synqNet));

    /* Request notification of all events from SynqNet */
    mpiEventMaskCLEAR(eventMask);

    returnValue =
        meiSynqNetEventNotifyGet(*synqNet,
                                 &eventMask,
                                 NULL);
    msgCHECK(returnValue);

    meiEventMaskSYNQNET(eventMask);

    returnValue =
        meiSynqNetEventNotifySet(*synqNet,
                                 eventMask,
                                 NULL);
    msgCHECK(returnValue);

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Create event manager object */
    *eventMgr = mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service == NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl  *control,
                    MEISynqNet  *synqNet,
                    MPINotify   *notify,
                    MPIEventMgr *eventMgr,
                    Service     *service)
{
    long returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    *service = MPIHandleVOID;

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    *eventMgr = MPIHandleVOID;

    /* Delete event notification object */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    *notify = MPIHandleVOID;

    returnValue =
        meiSynqNetDelete(*synqNet);
    msgCHECK(returnValue);

    *synqNet = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Display SynqNet events until the user presses a key */
void displaySynqNetEventsUntilKeyPressed(MEISynqNet   synqNet,
                                         MPINotify    notify)
{
    long returnValue;

    printf("Waiting for SynqNet Events...  \n");

    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus  eventStatus;

        /* Wait for synqNet event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               WAIT_TIME);

        if (returnValue == MPIMessageOK) {
            switch (eventStatus.type) {
                case MEIEventTypeSYNQNET_DEAD: {
                    printf("SynqNet Network Error.\n");
                    break;
                }
                case MEIEventTypeSYNQNET_RX_FAILURE: {
                    printf("SynqNet Rx Failure.\n");
                    break;
                }
                case MEIEventTypeSYNQNET_TX_FAILURE: {
                    printf("SynqNet Tx Failure.\n");
                    break;
                }
                case MEIEventTypeSYNQNET_NODE_FAILURE: {
                    MEISynqNetStatus synqNetStatus;

                    /* Read the network status */
                    returnValue =
                        meiSynqNetStatus(synqNet,
                                        &synqNetStatus);
                    msgCHECK(returnValue);

                    printf("SynqNet Node Failure. Failed Node Mask:0x%X\n",
                           synqNetStatus.failedNodeMask[0]);    /* First 32 nodes */
                    break;
                }
                case MEIEventTypeSYNQNET_RECOVERY: {
                                                    MEISynqNetCableList  idleCable;
                                                    MPIEventMask         eventMask;

                    printf("SynqNet Recovery.\n  WARNING: Network cable failure, data packets redirected.\n");

                    /* Determine cable failure location.  Packets redirected around the idle link. */
                    returnValue =
                        meiSynqNetIdleCableListGet(synqNet,
                                                   &idleCable);

                    msgCHECK(returnValue);
                    printf("  Idle link is cable %ld\n",
                           idleCable.cableNumber[0]);

                    /* Reset recovery event for re-trigger. */
                    mpiEventMaskCLEAR(eventMask);
                    mpiEventMaskSET(eventMask, MEIEventTypeSYNQNET_RECOVERY);
                    returnValue =
                        meiSynqNetEventReset(synqNet,
                                             eventMask);
                    msgCHECK(returnValue);
                    break;
                }
                default: {
                    printf("Unexpected Event  %ld\n", eventStatus.type);
                    break;
                }
            }
        }
        else if (returnValue == MPIMessageTIMEOUT) {   /* ignore timeouts */
            returnValue = MPIMessageOK;
        }
        msgCHECK(returnValue);
    }
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEISynqNet          synqNet;
    MPINotify           notify;
    MPIEventMgr         eventMgr;
    Service             service;
    long                synqNetNumber = 0;
    long                returnValue;

    /* Parse command line */
    returnValue =
        parseCommandLine(argc,
                         argv,
                         &synqNetNumber,
                         &controlType,
                         &controlAddress);
    msgCHECK(returnValue);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &synqNet,
                synqNetNumber,
                &notify,
                &eventMgr,
                &service);

    /* Display SynqNet events until the user presses a key */
    displaySynqNetEventsUntilKeyPressed(synqNet,
                                        notify);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &synqNet,
                   &notify,
                   &eventMgr,
                   &service);

    return ((int)returnValue);
}


SQNodeEvent1.c -- Display SynqNet Node Events

.

SQNodeEvent1.c -- SynqNet Node Events

/* SQNodeEvent1.c */

/* Copyright(c) 2001-2003 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.
 */
/*

:Display SynqNet Node Events

This is a simple program to demonstrate how to use the EventMgr to catch
 SynqNet node events, read the event message and display the event's information.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    SQNodeEvent1Main
argMainRENAME(main, SQNodeEvent1)
#endif

#define WAIT_TIME       (200)   /* msec */

/* Parse the command line */
long parseCommandLine(int                argc,
                      char               *argv[],
                      long               *synqNetNumber,
                      MPIControlType     *controlType,
                      MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-synqNet", ArgTypeLONG,    &synqNetNumber, },
        {   NULL,       ArgTypeINVALID, NULL,           }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
        argv,
        controlType,
        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) {
        fprintf(stderr,"usage: %s %s\n"
            "\t\t[-synqNet # (0 .. %d)]\n",
            argv[0],
            ArgUSAGE,
            MEIXmpMaxSynqNets - 1);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/* Create and initialize MPI objects */
void programInit(MPIControl        *control,
                 MPIControlType    controlType,
                 MPIControlAddress *controlAddress,
                 MEISynqNet        *synqNet,
                 long              synqNetNumber,
                 MEISqNode         *sqNode,
                 long              *nodeCount,
                 MPINotify         *notify,
                 MPIEventMgr       *eventMgr,
                 Service           *service)
{
    MPIEventMask     eventMask;
    MEISynqNetInfo   netInfo;
    long             index;
    long             returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create SynqNet object */
    *synqNet =
        meiSynqNetCreate(*control,
                         synqNetNumber);
    msgCHECK(meiSynqNetValidate(*synqNet));

   /* Read SynqNet Info */
   returnValue =
        meiSynqNetInfo(*synqNet, &netInfo);
    msgCHECK(returnValue);

    *nodeCount = netInfo.nodeCount;

   /* Create SqNode objects */
   if (netInfo.nodeCount) {
       for (index = netInfo.nodeOffset;
            index < netInfo.nodeOffset + netInfo.nodeCount;
            index++) {

            sqNode[index] =
               meiSqNodeCreate(meiSynqNetControl(*synqNet), index);
            msgCHECK(meiSqNodeValidate(sqNode[index]));
        }
    }

   /* Request notification of all events from SqNodes */
   if (netInfo.nodeCount) {
       for (index = netInfo.nodeOffset;
            index < netInfo.nodeOffset + netInfo.nodeCount;
            index++) {

           mpiEventMaskCLEAR(eventMask);
           returnValue =
               meiSqNodeEventNotifyGet(sqNode[index],
                                       &eventMask,
                                       NULL);
           msgCHECK(returnValue);

           meiEventMaskSQNODE(eventMask);

           returnValue =
               meiSqNodeEventNotifySet(sqNode[index],
                                       eventMask,
                                       NULL);
           msgCHECK(returnValue);
       }
   }

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Create event manager object */
    *eventMgr = mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service == NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl  *control,
                    MEISynqNet  *synqNet,
                    MEISqNode   *sqNode,
                    long        nodeCount,
                    MPINotify   *notify,
                    MPIEventMgr *eventMgr,
                    Service     *service)
{
    long index;
    long returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    *service = MPIHandleVOID;

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    *eventMgr = MPIHandleVOID;

    /* Delete event notification object */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    *notify = MPIHandleVOID;

    /* Delete SqNode objects */
    for (index = 0; index < nodeCount; index++) {
         returnValue =
             meiSqNodeDelete(sqNode[index]);
         msgCHECK(returnValue);
    }

    /* Delete SynqNet object */
    returnValue =
        meiSynqNetDelete(*synqNet);
    msgCHECK(returnValue);

    *synqNet = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Display SynqNet events until the user presses a key */
void displaySynqNetEventsUntilKeyPressed(MEISynqNet	synqNet,
                                         MEISqNode     *sqNode,
                                         long          nodeCount,
                                         MPINotify     notify)
{
   MPIEventStatus  eventStatus;
   long nodeNumber;
   long returnValue;

    printf("Waiting for SynqNet Node Events...  \n");

    while (meiPlatformKey(MPIWaitPOLL) <= 0) {

        /* Wait for synqNet event */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               WAIT_TIME);

        if (returnValue == MPIMessageOK) {
           /* find the node number from the event */
           returnValue =
               meiSqNodeNumber(eventStatus.source,
                               &nodeNumber);
           msgCHECK(returnValue);

           printf("SynqNet Node Number: %ld, ", nodeNumber);

            switch (eventStatus.type) {
                case MEIEventTypeSQNODE_IO_ABORT: {
                    printf("Node IO Abort.\n");
                    break;
                }
                case MEIEventTypeSQNODE_NODE_DISABLE: {
                    printf("Node Disable Input.\n");
                    break;
                }
                case MEIEventTypeSQNODE_NODE_ALARM: {
                    printf("Node Alarm Output.\n");
                    break;
                }
                case MEIEventTypeSQNODE_ANALOG_POWER_FAULT: {
                    printf("Node Analog Power Fault.\n");
                    break;
                }
                case MEIEventTypeSQNODE_USER_FAULT: {
                    printf("Node User Fault.\n");
                    break;
                }
                case MEIEventTypeSQNODE_NODE_FAILURE: {
                   MEISynqNetStatus synqNetStatus;

                  /* Read the network status */
                  returnValue =
                       meiSynqNetStatus(synqNet,
                                        &synqNetStatus);
                   msgCHECK(returnValue);

                   printf("Node Failure. Failed Node Mask:0x%X\n",
                          synqNetStatus.failedNodeMask[0]);    /* First 32 nodes */
                   break;
                }
                default: {
                    printf("Unexpected Event  %ld\n", eventStatus.type);
                    break;
                }
            }
        }
        else if (returnValue == MPIMessageTIMEOUT) {     /* ignore timeouts */
            returnValue = MPIMessageOK;
        }
        msgCHECK(returnValue);
    }
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEISynqNet          synqNet;
    MEISqNod            sqNode[MEISynqNetMaxNODE_COUNT];
    MPINotify           notify;
    MPIEventMgr         eventMgr;
    Service             service;
    long                nodeCount = 0;
    long                synqNetNumber = 0;
    long                returnValue;

    /* Parse command line */
    returnValue =
        parseCommandLine(argc,
                         argv,
                         &synqNetNumber,
                         &controlType,
                         &controlAddress);
    msgCHECK(returnValue);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &synqNet,
                synqNetNumber,
                sqNode,
                &nodeCount,
                &notify,
                &eventMgr,
                &service);

    /* Display SynqNet events until the user presses a key */
    displaySynqNetEventsUntilKeyPressed(synqNet,
                                        sqNode,
                                        nodeCount,
                                        notify);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &synqNet,
                   sqNode,
                   nodeCount,
                   &notify,
                   &eventMgr,
                   &service);

    return ((int)returnValue);
}


SQStatus1.c -- Display SynqNet Status

.

SQStatus1.c -- Display SynqNet Status
/* SQStatus1.c */

/* Copyright(c) 2001-2003 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.
 */

/*

:Display SynqNet Status

This is a simple program to demonstrate how to read the SynqNet Status.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    SQStatus1Main
argMainRENAME(main, SQStatus1)
#endif

/* Parse the command line */
long parseCommandLine(int                 argc,
                      char               *argv[],
                      long               *synqNetNumber,
                      MPIControlType     *controlType,
                      MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-synqNet", ArgTypeLONG,    &synqNetNumber, },
        {   NULL,       ArgTypeINVALID, NULL,           }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
        argv,
        controlType,
        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) {
        fprintf(stderr,"usage: %s %s\n"
            "\t\t[-synqNet # (0 .. %d)]\n",
            argv[0],
            ArgUSAGE,
            MEIXmpMaxSynqNets - 1);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/* Create and initialize MPI objects */
void programInit(MPIControl        *control,
                 MPIControlType     controlType,
                 MPIControlAddress *controlAddress,
                 MEISynqNet        *synqNet,
                 long               synqNetNumber)
{
    long returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
        controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create SynqNet object */
    *synqNet =
        meiSynqNetCreate(*control,
        synqNetNumber);
    msgCHECK(meiSynqNetValidate(*synqNet));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
                    MEISynqNet *synqNet)
{
    long returnValue;

    returnValue =
        meiSynqNetDelete(*synqNet);
    msgCHECK(returnValue);

    *synqNet = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

/* Display SynqNet Node Status */
void displaySynqNetNodeStatus(MEISqNode sqNode)
{
    MEISqNodeInfo       nodeInfo;
    MEISqNodeStatus     nodeStatus;
    long                nodeNumber;
    long                returnValue;

    returnValue =
        meiSqNodeInfo(sqNode, &nodeInfo);
    msgCHECK(returnValue);

    returnValue =
        meiSqNodeNumber(sqNode, &nodeNumber);
    msgCHECK(returnValue);

    printf("  Node %ld Information\n"
           "    Motor Count  : %d\n"
           "    Motor Offset : %d\n"
           "    Drive Count  : %d\n",
           nodeNumber,
           nodeInfo.motorCount,
           nodeInfo.motorOffset,
           nodeInfo.driveCount);

    printf("    NodeType     : 0x%8.8X\n"
           "    NodeOption   : 0x%8.8X\n"
           "    Unique Id    : %d\n"
           "    Serial Number: %s\n"
           "    Model Number : %s\n"
           "    Switch Id    : 0x%X\n"

           "    FPGA Number  : 0x%X\n"
           "    FPGA Version : 0x%X\n",
           nodeInfo.id.nodeType,
           nodeInfo.id.option,
           nodeInfo.id.unique,
           nodeInfo.id.serialNumber,
           nodeInfo.id.modelNumber,
           nodeInfo.id.switchId,
           nodeInfo.fpga.vendorDevice,
           nodeInfo.fpga.version);

    returnValue =
        meiSqNodeStatus(sqNode, &nodeStatus);
    msgCHECK(returnValue);

    printf("  Node %ld Status\n"
           "    IoAbort Event            : %s\n"
           "    Node Disable Event       : %s\n"
           "    Node Alarm Event         : %s\n"
           "    Power Failure Event      : %s\n"
           "    User Fault Event         : %s\n"
           "    Node Falure Event        : %s\n"
           "    Up Stream Error Rate     : %d\n"
           "    Up Stream Error Count    : %d\n"
           "    Down Stream Error Rate   : %d\n"
           "    Down Stream Error Count  : %d\n"
           "    Out Port CRC Errors      : %d\n"
           "    In Port CRC Errors       : %d\n\n",
           nodeNumber,
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_IO_ABORT) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_NODE_DISABLE) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_NODE_ALARM) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_ANALOG_POWER_FAULT) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_USER_FAULT) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(nodeStatus.eventMask, MEIEventTypeSQNODE_NODE_FAILURE) ? "TRUE" : "FALSE",
           nodeStatus.upStreamError.rate,
           nodeStatus.upStreamError.count,
           nodeStatus.downStreamError.rate,
           nodeStatus.downStreamError.count,
           nodeStatus.crcError.port[MEINetworkPortOUT0],
           nodeStatus.crcError.port[MEINetworkPortIN0]);
}

/* Display SynqNet Status */
void displaySynqNetStatus(MPIControl control,
                          MEISynqNet synqNet)
{
    MEISynqNetInfo      netInfo;
    MEISynqNetStatus    netStatus;
    MEISqNode           sqNode;
    long                index;
    long                returnValue;

    /* Read SynqNet Info */
    returnValue =
        meiSynqNetInfo(synqNet, &netInfo);
    msgCHECK(returnValue);

    /* Read SynqNet Status */
    returnValue =
        meiSynqNetStatus(synqNet,
                         &netStatus);
    msgCHECK(returnValue);

    /* Display SynqNet Status */
    printf("\nSynqNet Status\n"
           "  State      : %ld\n"
           "  In Port CRC Errors : %ld\n"
           "  Out Port CRC Errors: %ld\n"
           "  Failed Node Mask   : %ld\n"
           "  Network Dead Event : %s\n"
           "  Rx Failure Event   : %s\n"
           "  Tx Failure Event   : %s\n"
           "  Node Failure Event : %s\n"
           "  Recovery Event     : %s\n\n",
           netStatus.state,
           netStatus.crcError.port[MEINetworkPortIN0],
           netStatus.crcError.port[MEINetworkPortOUT0],
           netStatus.failedNodeMask[0],
           mpiEventMaskBitGET(netStatus.eventMask, MEIEventTypeSYNQNET_DEAD) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(netStatus.eventMask, MEIEventTypeSYNQNET_RX_FAILURE) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(netStatus.eventMask, MEIEventTypeSYNQNET_TX_FAILURE) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(netStatus.eventMask, MEIEventTypeSYNQNET_NODE_FAILURE) ? "TRUE" : "FALSE",
           mpiEventMaskBitGET(netStatus.eventMask, MEIEventTypeSYNQNET_RECOVERY) ? "TRUE" : "FALSE");

    if (netInfo.nodeCount) {
        /* Loop over nodes */
        for (index = netInfo.nodeOffset;
             index < (netInfo.nodeOffset + netInfo.nodeCount);
             index++) {

            sqNode =
                meiSqNodeCreate(control, index);
            msgCHECK(meiSqNodeValidate(sqNode));

            /* Display SynqNet Node Status */
            displaySynqNetNodeStatus(sqNode);

            returnValue =
                meiSqNodeDelete(sqNode);
            msgCHECK(returnValue);
        }
    }
    else {
        printf("No SynqNet Blocks found.\n");
    }
}

int main(int    argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEISynqNet          synqNet;
    long                synqNetNumber = 0;
    long                returnValue;

    /* Parse command line */
    returnValue =
        parseCommandLine(argc,
                         argv,
                         &synqNetNumber,
                         &controlType,
                         &controlAddress);
    msgCHECK(returnValue);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &synqNet,
                synqNetNumber);

    /* Display SynqNet Status */
    displaySynqNetStatus(control,
                         synqNet);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &synqNet);

    return ((int)returnValue);
}


SQStatus2.c -- Display/Save/Verify SynqNet Topology using SynqNet Info Structure

.

SQStatus2.c -- Display/Save/Verify SynqNet Topology using SynqNet Info Structure
/* SQStatus2.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[] =
    "RCSHeader";
#endif

/*

:Display/Save/Verify SynqNet Topology using SynqNet Info Structure

This program demonstrates how to verify a SynqNet network topology.  Your
 application code should always verify that the network topology is as expected.
 This step is required for safe machine operation.

This program only displays and verifies basic SynqNet node topology information.
 It does NOT check the drive/motor specific details.  Depending on your system
 installation and configuration, additional steps may be required to verify the
 individual network devices.  Please consult your drive/motor manufacturer
 documentation for details.

If the -save  option is selected, the topology info is saved to a text file.
 The saved text file can be used to verify the SynqNet topology at system startup
 using the -verify  option.  This option saves the current topology info to
 a temporary file, then compares the temporary file to the saved file. A failure or
 success is reported after the verify check.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define	main	SQStatus2Main

argMainRENAME(main, SQStatus2)
#endif

/* Command line arguments and defaults */
long	confirm = 0;
long	synqNetNumber = 0;
char	*saveFilename = NULL;
char	*verifyFilename = NULL;

Arg	argList[] = {
    {   "-confirm", ArgTypeNONE,    &confirm,         },
    {   "-synqNet", ArgTypeLONG,    &synqNetNumber,   },
    {   "-save",    ArgTypeTEXT,    &saveFilename,    },
    {   "-verify",  ArgTypeTEXT,    &verifyFilename,  },

    {   NULL,       ArgTypeINVALID, NULL,             }
};

long
    networkInfoOutput(MEISynqNet    synqNet,
                      char          *fileName);

long
    networkInfoVerify(MEISynqNet    synqNet,
                      char          *filename);

int
    main(int     argc,
         char    *argv[])
{
    MPIControl           control;
    MPIControlType       controlType;
    MPIControlAddress    controlAddress;

    MEISynqNet           synqNet;

    long        returnValue;
    long        argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
            (synqNetNumber < 0) ||
            (synqNetNumber >= MEIXmpMaxSynqNets) ||
            ((saveFilename != NULL) && (verifyFilename != NULL))) {
            meiPlatformConsole("usage: %s %s\n",
                               "\t\t[-confirm]\n"
                               "\t\t[-synqNet (0 .. %d)]\n"
                               "\t\t[-save filename | -verify filename]\n",
                                argv[0],
                                ArgUSAGE,
                                MEIXmpMaxSynqNets - 1);
            exit(MPIMessageARG_INVALID);
      }

      /* Create control object */
      control =
             mpiControlCreate(controlType,
                              &controlAddress);
      msgCHECK(mpiControlValidate(control));

      /* Initialize the controller */
      returnValue = mpiControlInit(control);

      /* check for configuration mismatch */
      if (returnValue == MEISynqNetMessageTOPOLOGY_MISMATCH) {
              meiPlatformConsole("\n\nWARNING: %s\n\n",
                                 mpiMessage(returnValue, NULL));
      }
      else {
              msgCHECK(returnValue);
      }

      /* Create SynqNet Object */
      synqNet =
              meiSynqNetCreate(control,
                               synqNetNumber);
      msgCHECK(meiSynqNetValidate(synqNet));

      /* Display current topology */
      networkInfoOutput(synqNet, NULL);

      if (confirm) {
          printf("\n\nSaving network topology to flash...");
          returnValue =
               meiSynqNetTopologySave(synqNet);
               msgCHECK(returnValue);
       }
       else {

          if (saveFilename != NULL) {
              char in;

              /* verify with user */
              printf("\n\nIs this network topology correct? (y/n)");
              in = getchar();

              /* save topology to file */
              if ((in == 'y') ||
                 (in == 'Y')) {

                  networkInfoOutput(synqNet, saveFilename);

                  printf("\nNetwork topology saved to file: %s\n\n", saveFilename);
               }
           }

           if (verifyFilename != NULL) {
               returnValue =
                   networkInfoVerify(synqNet, verifyFilename);

               if (returnValue == -1) {
                    printf("Verify failed\n\n");
               }
               else {
                    printf("Verify Successful!!\n\n");
               }
            }

       }

       /* Delete object handles */
       returnValue = meiSynqNetDelete(synqNet);
       msgCHECK(returnValue);

       returnValue = mpiControlDelete(control);
       msgCHECK(returnValue);

       return ((int)returnValue);
}

long
       networkInfoOutput(MEISynqNet    synqNet,
                         char          *fileName)
{
       MEISynqNetInfo    netInfo;

       MEISqNode         sqNode;
       MEISqNodeInfo     nodeInfo;

       long     bytes;
       long     index;
       long     returnValue;

       FILE *stream = stdout;

      /* open file for output */
      if (fileName != NULL) {
          stream = fopen( fileName, "w" );
      }

      /* Read SynqNet Info */
      returnValue =
          meiSynqNetInfo(synqNet, &netInfo);
      msgCHECK(returnValue);

      bytes = fprintf(stream, "SynqNet Information\n\n");

      if (netInfo.nodeCount) {
          /* Display SynqNet Info */
          for (index = netInfo.nodeOffset;
               index < netInfo.nodeOffset + netInfo.nodeCount;
               index++) {

               sqNode =
                     meiSqNodeCreate(meiSynqNetControl(synqNet), index);
               msgCHECK(meiSqNodeValidate(sqNode));

               returnValue =
                     meiSqNodeInfo(sqNode, &nodeInfo);
               msgCHECK(returnValue);

               bytes +=
                     fprintf(stream,
                           "  Node %ld Information\n"
                           "  Motor Count  : %d\n"
                           "  Motor Offset : 0x%x\n",
                           index,
                           nodeInfo.motorCount,
                           nodeInfo.motorOffset);

               bytes +=
                 fprintf(stream,
                           "    NodeType     : 0x%8.8x\n"
                           "    NodeOption   : 0x%8.8x\n"
                           "    Unique Id    : %d\n"
                           "    Serial Number: %s\n"
                           "    Model Number : %s\n"
                           "    Switch Id    : 0x%x\n"

                           "    FPGA Number  : 0x%x\n"
                           "    FPGA Version : 0x%x\n\n",
                       nodeInfo.id.nodeType,
                           nodeInfo.id.option,
                           nodeInfo.id.unique,
                           nodeInfo.id.serialNumber,
                           nodeInfo.id.modelNumber,
                           nodeInfo.id.switchId,

                           nodeInfo.fpga.vendorDevice,
                           nodeInfo.fpga.version);
               }
       }
       else {
             printf("No SynqNet Blocks found.\n");
       }

       /* close output file */
       if (fileName != NULL) {
           fclose( stream );
       }

       return (bytes);
}

long
       networkInfoVerify(MEISynqNet   synqNet,
                         char         *fileName)
{
       long returnValue = MPIMessageOK;
       long bytes, i;

       char chr1, chr2;

       FILE *stream1, *stream2;

       /* save current topology to temp file */
       bytes =
            networkInfoOutput(synqNet, "tmpfile.txt");

       /* open files */
       stream1 = fopen( "tmpfile.txt", "r" );
       stream2 = fopen( fileName, "r" );

       /* compare files */
       for(i=0;i<bytes;i++) {
           chr1=fgetc(stream1);
           chr2=fgetc(stream2);

           if (chr1 != chr2) {
               returnValue = -1;
               break;
           }
      }

      return (returnValue);
}


SQStatus3.c -- Display/Save/Verify SynqNet Topology and DMD/SigmaIII Specific Information

.

SQStatus3.c -- Display/Save/Verify SynqNet Topology and DMD/SigmaIII Specific Information
/* SQStatus3.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Display/Save/Verify SynqNet Topology and DMD/SigmaIII Specific Information

This sample application is the same as SQStatus2.c with the addition
drive specific configuration display and verification.

This program only displays and verifies 3rd party drives that support the
 meiSqNodeDriveInfo(...) routines.  Depending on your SynqNet installation
 and configuration, additional steps may be required to verify other
 individual drive specific values and structures.  Please consult your
 drive/motor manufacturer documentation for details.

If the -save  option is selected, the topology info is saved to a text file.
 The saved text file can be used to verify the SynqNet topology at system startup
 using the -verify  option.  This option saves the current topology info to
 a temporary file, then compares the temporary file to the saved file. A failure or
 success is reported after the verify check.

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

#include

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#include "..\sqNodeLib\include\sqNodeLib.h"

#if defined(ARG_MAIN_RENAME)
#define	main	SQStatus3Main

argMainRENAME(main, SQStatus3)
#endif

/* Command line arguments and defaults */
long    synqNetNumber = 0;
char    *saveFilename = NULL;
char    *verifyFilename = NULL;

Arg     argList[] = {
        {    "-synqNet",   ArgTypeLONG,     &synqNetNumber,   },
        {    "-save",      ArgTypeTEXT,     &saveFilename,    },
        {    "-verify",    ArgTypeTEXT,     &verifyFilename,  },

        {    NULL,         ArgTypeINVALID,  NULL,             }
};

long
        networkInfoOutput(MEISynqNet   synqNet,
                          char         *fileName);

long
        networkInfoVerify(MEISynqNet   synqNet,
                          char         *filename);

int
        main(int     argc,
             char    *argv[])

{
        MPIControl           control;
        MPIControlType       controlType;
        MPIControlAddress    controlAddress;

        MEISynqNet           synqNet;

        long    returnValue;
        long    argIndex;

        /* Parse command line for Control type and address */
        argIndex =
              argControl(argc,
                         argv,
                         &controlType,
                         &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) ||
            (synqNetNumber < 0) ||
            (synqNetNumber >= MEIXmpMaxSynqNets) ||
            ((saveFilename != NULL) && (verifyFilename != NULL))) {
            meiPlatformConsole("usage: %s %s\n",
                               "\t\t[-synqNet (0 .. %d)]\n"
                               "\t\t[-save filename | -verify filename]\n",
                               argv[0],
                               ArgUSAGE,
                               MEIXmpMaxSynqNets - 1);
            exit(MPIMessageARG_INVALID);
        }

        /* Create control object */
        control =
            mpiControlCreate(controlType,
                             &controlAddress);
        msgCHECK(mpiControlValidate(control));

        /* Initialize the controller */
        returnValue = mpiControlInit(control);
        msgCHECK(returnValue);

        /* Create SynqNet Object */
        synqNet =
            meiSynqNetCreate(control,
                             synqNetNumber);
        msgCHECK(meiSynqNetValidate(synqNet));

        /* Display current topology */
        networkInfoOutput(synqNet, NULL);

        if (saveFilename != NULL) {
                char in;

                /* verify with user */
                printf("\n\nIs this network topology correct? (y/n)");
                in = getchar();

                /* save topology to file */
                if ((in == 'y') ||
                    (in == 'Y')) {

                     networkInfoOutput(synqNet, saveFilename);

                     printf("\nNetwork topology saved to file: %s\n\n", saveFilename);
                }
        }

        if (verifyFilename != NULL) {
                returnValue =
                     networkInfoVerify(synqNet, verifyFilename);

                if (returnValue == -1) {
                    printf("Verify failed\n\n");
        }
        else {
                    printf("Verify Successful!!\n\n");
                }
        }

        /* Delete object handles */
        returnValue = meiSynqNetDelete(synqNet);
        msgCHECK(returnValue);

        returnValue = mpiControlDelete(control);
        msgCHECK(returnValue);

        return ((int)returnValue);
}

long
        networkInfoOutput(MEISynqNet     synqNet,
                          char           *fileName)
{
        MEISynqNetInfo   synqNetInfo;

        MEISqNode        sqNode;
        MEISqNodeInfo    nodeInfo;

        long    nodeFirst;
        long    nodeLast;

        long    bytes;
        long    index;
        long    returnValue;

        FILE *stream = stdout;

        /* open file for output */
        if (fileName != NULL) {
              stream = fopen( fileName, "w" );
        }

        /* Read SynqNet Info */
        returnValue =
              meiSynqNetInfo(synqNet, &synqNetInfo);
        msgCHECK(returnValue);

        if (synqNetInfo.nodeCount) {
              /* Display SynqNet Info */
              bytes =
                   fprintf(stream,
                           "SynqNet Information\n"
                               "  Node Count   : %ld\n\n",
                               synqNetInfo.nodeCount);

              nodeFirst = synqNetInfo.nodeOffset;
              nodeLast = synqNetInfo.nodeOffset + synqNetInfo.nodeCount;

              for (index = nodeFirst; index < nodeLast; index++) {

                   sqNode =
                        meiSqNodeCreate(meiSynqNetControl(synqNet),
                                        index);
                   msgCHECK(meiSqNodeValidate(sqNode));

                   returnValue =
                        meiSqNodeInfo(sqNode, &nodeInfo);
                   msgCHECK(returnValue);

                   bytes +=
                        fprintf(stream,
                            "\n  Node [%ld] Information\n"
                            "    Type         : %s\n"
                            "    Motor Count  : %d\n"
                            "    Motor Offset : 0x%x\n",
                            index,
                            nodeInfo.id.nodeName,
                            nodeInfo.motorCount,
                            nodeInfo.motorOffset);

                   bytes +=
                         fprintf(stream,
                             "    Serial Number: %s\n"
                             "    Model Number : %s\n"
                             "    VendorDevice : 0x%x\n"
                             "    Version      : 0x%x\n\n",
                             nodeInfo.id.serialNumber,
                             nodeInfo.id.modelNumber,
                             nodeInfo.fpga.vendorDevice,
                             nodeInfo.fpga.version);

                   switch(nodeInfo.id.nodeType) {
                        case (SQNodeLibNodeTypeYASKAWA_DMD) : {
                              DMDInfo	driveInfo;
                              long drive;

                              memset((void*)&driveInfo,0x0,sizeof(driveInfo));

                              for (drive=0; drive < nodeInfo.motorCount; drive++) {
                                   /* Read Drive specific Info */
                                   returnValue =
                                         meiSqNodeDriveInfo(sqNode,
                                                            index,
                                                            (void*)&driveInfo,
                                                             NULL);
                                         msgCHECK(returnValue);

                                         bytes +=
                                              fprintf(stream,
                                              "    Drive/Amp Information\n"
                                              "        FW Version    : %d\n"
                                              "        Encoder Type  : %s\n"
                                              "        Motor Type    : %s\n"
                                              "        Rated Current : %2.2f A\n"
                                              "        Rated Power   : %d Watts\n"
                                              "        Rated Speed   : %d rpm\n"
                                              "        Rated Torque  : %2.2f Nm\n\n",
                                              driveInfo.version,
                                              driveInfo.encoder.type,
                                              driveInfo.motor.type,
                                              driveInfo.motor.rating.current * 0.1,
                                              driveInfo.motor.rating.power,
                                              driveInfo.motor.rating.speed * 100,
                                              driveInfo.motor.rating.torque * 0.01);
                                 }
                                 break;
                          }

                          case (SQNodeLibNodeTypeYASKAWA_SIGMA3) : {
                                SIGMA3Info     driveInfo;

                                memset((void*)&driveInfo,0x0,sizeof(driveInfo));

                               /* Read Drive specific Info */
                               returnValue =
                                     meiSqNodeDriveInfo(sqNode,
                                                       index,
                                                       (void*)&driveInfo,
                                                       NULL);
                               msgCHECK(returnValue);

                               bytes +=
                                     fprintf(stream,
                                          "    Drive/Amp Information\n"
                                          "        FW Version     : %d\n"
                                          "        Motor Capacity : %d\n"
                                          "        Motor Torque   : %d\n"
                                          "        Motor TorqueMax: %d\n",
                                           driveInfo.FWVersion,
                                           driveInfo.MotorCapacity,
                                           driveInfo.MotorTorque,
                                           driveInfo.MotorTorqueMax);
                                break;
                           }
                           case (SQNodeLibNodeTypeGLENTEK_OMEGA) : {
                                 GLENTEKOmegaInfo       driveInfo;

                                 memset((void*)&driveInfo,0x0,sizeof(driveInfo));

                                 /* Read Drive specific Info */
                                 returnValue =
                                       meiSqNodeDriveInfo(sqNode,
                                                          index,
                                                          (void*)&driveInfo,
                                                          NULL);
                                 msgCHECK(returnValue);

                                 bytes +=
                                       fprintf(stream,
                                            "    Drive/Amp Information\n"
                                            "        Base Model               : %d\n"
                                            "        Powerboard Tab           : %d\n"
                                            "        PreAmp Tab               : %d\n"
                                            "        Continuous Current Rating: %6.3lf\n"
                                            "        Peak Current Rating      : %6.3lf\n"
                                            "        Bus Under-Voltage        : %6.3lf\n"
                                            "        Bus Over-Voltage         : %6.3lf\n"
                                            "        I/O Invert Mask          : 0x%8.8x\n"
                                            "        Cal. Offset Phase R      : %d\n"
                                            "        Cal. Offset Phase S      : %d\n"
                                            "        Cal. Offset Phase T      : %d\n"
                                            "        FW Command Set           : %d\n"
                                            "        FW Version               : %s\n",
                                             driveInfo.mode.baseModel,
                                             driveInfo.mode.powerBoardTab,
                                             driveInfo.mode.preAmpTab,
                                             driveInfo.mode.currentRatingCont,
                                             driveInfo.mode.currentRatingPeak,
                                             driveInfo.mode.busUnderVoltage,
                                             driveInfo.mode.busOverVoltage,
                                             driveInfo.mode.ioInvertMask,
                                             driveInfo.calibration.adcOffsetPhaseR,
                                             driveInfo.calibration.adcOffsetPhaseS,
                                             driveInfo.calibration.adcOffsetPhaseT,
                                             driveInfo.firmware.commandSet,
                                             driveInfo.firmware.version);

                                 break;
                             }
                             case (SQNodeLibNodeTypeKOLLMORGEN_CD) :
                             case (SQNodeLibNodeTypeKOLLMORGEN_DASA) : {
                                   DASADriveInfo   driveInfo;
                                   long	           drive;

                                   memset((void*)&driveInfo,0x0,sizeof(driveInfo));

                                   for (drive=0; drive < nodeInfo.motorCount; drive++) {
                                        /* Read Drive specific Info */
                                        returnValue =
                                            meiSqNodeDriveInfo(sqNode,
                                                               index,
                                                               (void*)&driveInfo,
                                                               NULL);
                                        msgCHECK(returnValue);

                                        bytes +=
                                            fprintf(stream,
                                               "    Drive/Amp Information\n"
                                               "      Continuous Current Rating: %d\n"
                                               "      Peak Current Rating      : %d\n"
                                               "      Max Current for drive    : %d\n"
                                               "      PWM Frequency            : %d\n"
                                               "      Drive FW Version         : 0x%8.8x\n",
                                                driveInfo.dicont,
                                                driveInfo.dipeak,
                                                driveInfo.imax,
                                                driveInfo.pwmfrq,
                                                driveInfo.ver);
                                    }

                                    break;
                                }
                                default: {
                                    break;
                                }
                        }
                }
        }
        else {
             printf("No SynqNet Blocks found.\n");
        }

        /* close output file */
        if (fileName != NULL) {
            fclose( stream );
        }

        return (bytes);
}

long
        networkInfoVerify(MEISynqNet    synqNet,
                          char          *fileName)
{
        long returnValue = MPIMessageOK;
        long bytes, i;

        char chr1, chr2;

        FILE *stream1, *stream2;

        /* save current topology to temp file */
        bytes =
              networkInfoOutput(synqNet, "tmpfile.txt");

        /* open files */
        stream1 = fopen( "tmpfile.txt", "r" );
        stream2 = fopen( fileName, "r" );

        /* compare files */
        for(i=0;i<bytes;i++ {
            chr1=fgetc(stream1);
            chr2=fgetc(stream2);

            if (chr1 != chr2) {
                returnValue = -1;
                break;
            }
        }

        return (returnValue);
}


sqTiming1.c -- Display SynqNet Timing values

.

sqTiming1.c -- Display SynqNet Timing values
/* sqTiming1.c */

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

/*

:Display SynqNet Timing values

This sample application retrieves the SynqNetwork timing values from the
MPI and displays them to the console.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    sqTiming1Main
argMainRENAME(main, sqTiming1)
#endif

/* 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,
                 MEISynqNet         *synqNet)
{
    long    returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

   /* Obtain a synqNet handle */
    *synqNet =
        meiSynqNetCreate(*control, 0);
    msgCHECK(meiSynqNetValidate(*synqNet));

}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl   *control,
                    MEISynqNet   *synqNet)
{
    long    returnValue;

    /* Delete synqNet handle */
    returnValue =
        meiSynqNetDelete(*synqNet);
    msgCHECK(returnValue);

        *synqNet = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

        *control = MPIHandleVOID;
}

/* Display SynqNet timing information */
void displaySynqNetTiming(MEISynqNet synqNet)
{
        MEISynqNetTiming     timingValues;
        long                 returnValue;

    /* Get SynqNet timing values */
    returnValue =
        meiSynqNetTiming(synqNet, &timingValues);
    msgCHECK(returnValue);

    /* Display SynqNet timing values */
    if (returnValue == MPIMessageOK) {
            printf("SynqNet Timing Values\n"
                   "=====================\n\n");

            printf("Controller Frequency  : %3.3lf kHz\n"
                   "Controller Period     : %3.3lf uS\n"
                   "TxTime                : %d percent\n"
                   "Calculation Limit     : %3.3lf uS\n"
                   "Drive Update Frequency: %3.3lf kHz\n"
                   "Drive Update Period   : %3.3lf uS\n\n"
                   "SynqNet Bandwidth Used: %d percent \n\n",
                   timingValues.controllerFreq,
                   timingValues.controllerPeriod,
                   timingValues.txTime,
                   timingValues.calculationLimit,
                   timingValues.driveUpdateFreq,
                   timingValues.driveUpdatePeriod,
                   timingValues.bandwidthUsage);

            if (timingValues.controlLatency.calculationTime != 0) {
                printf("Calculation Time : %3.3lf uS\n",
                       timingValues.controlLatency.calculationTime);
            }
            else {
                printf("Calculation Time : N/A\n");
            }

            printf("Calculation Slack: %3.3lf uS\n"
                   "Demand Latency   : %3.3lf uS\n"
                   "Feedback Latency : %3.3lf uS\n"
                   "================================\n"
                   "Total Latency    : %3.3lf uS\n"
                   "Latency Slack    : %3.3lf uS\n\n",
                   timingValues.controlLatency.calculationSlack,
                   timingValues.controlLatency.demandLatency,
                   timingValues.controlLatency.feedbackLatency,
                   timingValues.controlLatency.total,
                   timingValues.controlLatency.latencySlack);

            printf("Synq Packets    : %3.3lf uS\n"
                   "Demand Packets  : %3.3lf uS\n"
                   "Control Packets : %3.3lf uS\n"
                   "================================\n"
                   "Total Downstream: %3.3lf uS\n\n",
                   timingValues.downstream.synq,
                   timingValues.downstream.demand,
                   timingValues.downstream.control,
                   timingValues.downstream.total);

            printf("Feedback Packets : %3.3lf uS\n"
                   "Status Packets   : %3.3lf uS\n"
                   "================================\n"
                   "Total Upstream   : %3.3lf uS\n",
                   timingValues.upstream.feedback,
                   timingValues.upstream.status,
                   timingValues.upstream.total);
      }
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MEISynqNet          synqNet;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &synqNet);

    /* Display SynqNet timing information */
    displaySynqNetTiming(synqNet);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control, &synqNet);

    return MPIMessageOK;
}


ssiEncCfg.c -- Demonstrates SSI encoder configuration for an RMB-10v2

.

ssiEncCfg.c -- Demonstrates SSI encoder configuration for an RMB-10v2
/* ssiEncCfg.c */

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

/*

:Demonstrates SSI encoder configuration for an RMB-10v2.

This sample program configures the motor's primary encoder for an SSI encoder.
 The SSI encoder interface is a clock output with serial data feedback.  The
 configuration parameters for SSI encoders depend on the manufacturer and
 model.  Please consult the SSI encoder documentation for details.

This sample program requires an RMB-10v2, with an FPGA image that supports
 the SSI encoder interface.  The C0FE002C FPGA image supports both incremental
 quadrature encoder types and SSI encoder types.  Make sure you download the
 appropriate FPGA image to your RMB-10v2.

After the SSI encoder is initialized, the motor's feedback position will
 be updated automatically by the FPGA and controller's firmware.

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.

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

#include "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"
#include "..\sqNodeLib\include\mei_rmb.h"

#if defined(ARG_MAIN_RENAME)
#define main    ssiEncCfgMain
argMainRENAME(main, ssiEncCfg)
#endif

#define MOTOR_NUMBER    (0)
#define BAUD_100_KHZ    (100000)

/* 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           *motor,
                 long                motorNumber)
{
    long    returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);

    *motor =
        mpiMotorCreate(*control, motorNumber);
    msgCHECK(mpiMotorValidate(*motor));
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
                    MPIMotor   *motor)
{
    long    returnValue;

    /* Delete motor handle */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    *motor = MPIHandleVOID;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);

    *control = MPIHandleVOID;
}

void ssiEncoderInit(MPIControl  control,
                    MPIMotor    motor,
                    long        baudRate)
{
    MEIMotorConfig          motorConfig;
    MEIMotorInfo            motorInfo;
    RMBSsiEncoderConfig     ssiConfig;
    long                    returnValue;

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

    /* Configure the RMB's XCVR_B for the SSI Clock signal */
    motorConfig.Io[RMBMotorIoConfigXCVR_B].Type = RMBMotorIoTypeSSI_CLOCK;

    /* Configre the RMB's feedback type to SSI */
    motorConfig.Encoder[0].type = MEIMotorEncoderTypeSSI;

    returnValue =
            mpiMotorConfigSet(motor,
                              NULL,
                              &motorConfig);
    msgCHECK(returnValue);

    /* motorInfo will be used to determine the node number and drive offset */
    returnValue =
            meiMotorInfo(motor,
                         &motorInfo);
    msgCHECK(returnValue);

    returnValue =
            rmbSsiEncoderConfigGet(control,
                                   motorInfo.sqNode.nodeNumber,
                                   motorInfo.sqNode.driveIndex,
                                   &ssiConfig);
    msgCHECK(returnValue);

    /* Configure for the particular SSI Encoder manufacturer/model. */
    ssiConfig.baudRate          = baudRate;                 /* baud rate may vary depending on the
                                                               length of the serial cable */
    ssiConfig.bitCount          = 12;                       /* position resolution */
    ssiConfig.brokenWireEnable  = FALSE;                    /* disable broken wire detection */
    ssiConfig.errorBitEnable    = TRUE;                     /* enable error bit detection */
    ssiConfig.input             = RMBSsiEncoderInputXCVR_A; /* use XCVR_A for encoder serial input */
    ssiConfig.parity            = RMBSsiParityODD;

    returnValue =
            rmbSsiEncoderConfigSet(control,
                                   motorInfo.sqNode.nodeNumber,
                                   motorInfo.sqNode.driveIndex,
                                   &ssiConfig);
    msgCHECK(returnValue);

}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotor            motor;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress,
                &motor,
                MOTOR_NUMBER);

    /* Initialize the motor's feedback for an SSI encoder. */
    ssiEncoderInit(control,
                   motor,
                   BAUD_100_KHZ);

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control,
                   &motor);

    return MPIMessageOK;
}


stoprate.c -- Set deceleration rate for MPIActionSTOP and MPIActionE_STOP.

.

stoprate.c -- Set deceleration rate for MPIActionSTOP and MPIActionE_STOP.
/* stoprate.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:Set deceleration rate for MPIActionSTOP and MPIActionE_STOP.

This sample code demonstrates how to configure the MPIActionSTOP and
MPIActionE_STOP deceleration rates for a given Motion objectr.  Unless
specified at the command line, the DEFAULT deceleration rates will be used.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    stoprateMain

argMainRENAME(main, stoprate)
#endif

/* Define STOP and ESTOP rates in seconds */
#define STOP_RATE_DEFAULT   ((float)3.0)
#define ESTOP_RATE_DEFAULT  ((float)1.0)

/* Command line arguments and defaults */
long    motionNumber    = 0;
float   stopRate        = STOP_RATE_DEFAULT;
float   eStopRate       = ESTOP_RATE_DEFAULT;

Arg argList[] = {
    {   "-motion",  ArgTypeLONG,    &motionNumber,  },
    {   "-stop",    ArgTypeFLOAT,   &stopRate,      },
    {   "-estop",   ArgTypeFLOAT,   &eStopRate,     },

    {   NULL,       ArgTypeINVALID, NULL,   }
};

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

    MPIControl  control;        /* Motion controller handle */
    MPIMotion   motion;         /* Motion supervisor handle */

    MPIMotionConfig     motionConfig;   /* Motion supervisor configuration */

    long    returnValue;            /* Return value from library */

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-stop (%f)]\n"
                           "\t\t[-estop (%f)]\n",
                           argv[0],
                           ArgUSAGE,
                           MEIXmpMAX_MSs - 1,
                           STOP_RATE_DEFAULT,
                           ESTOP_RATE_DEFAULT);
        exit(MPIMessageARG_INVALID);
    }

    /* Create controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motion object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        MPIHandleVOID);
    msgCHECK(mpiMotionValidate(motion));

    /* Read current motion supervisor configuration */
    returnValue =
        mpiMotionConfigGet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    printf("OLD: motion %d: stopRate %f eStopRate %f\n",
            motionNumber,
            motionConfig.decelTime.stop,
            motionConfig.decelTime.eStop);

    /* Set new STOP and E_STOP deceleration rates */
    motionConfig.decelTime.stop  = stopRate;
    motionConfig.decelTime.eStop = eStopRate;

    returnValue =
        mpiMotionConfigSet(motion,
                           &motionConfig,
                           NULL);
    msgCHECK(returnValue);

    printf("NEW: motion %d: stopRate %f eStopRate %f\n",
            motionNumber,
            stopRate,
            eStopRate);

    /* Delete objects */

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}


template.c -- Template application (one line description for sample

.

template.c -- Template application (one line description for sample app)
/* template.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

#if defined(ARG_MAIN_RENAME)
#define main    templateMain
argMainRENAME(main, template)
#endif

/*

:Template application (one line description for sample app)

detailed description

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.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

/* 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)
{
    long    returnValue;

    /* Obtain a control handle */
    *control =
        mpiControlCreate(controlType, controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue =
        mpiControlInit(*control);
    msgCHECK(returnValue);
}

/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control)
{
    long    returnValue;

    /* Delete control handle */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/* Your first function */
void function1()
{
    printf(""); /* Dummy function call - Replace with useful code */
}

/* Your second function */
void function2()
{
    printf(""); /* Dummy function call - Replace with useful code */
}

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    /* Perform basic command line parsing. (-control -server -port -trace) */
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects */
    programInit(&control,
                controlType,
                &controlAddress);

    /* Place your code here! */
    function1();
    function2();

    /* Perform certain cleanup actions and delete MPI objects */
    programCleanup(&control);

    return MPIMessageOK;
}


usrlim1.c -- User Limit to watch an input bit and set an output bit.

.

usrlim1.c -- User Limit to watch an input bit and set an output bit.
/* UsrLim1.c */

/* Copyright(c) 1991-2003 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[] =
    "RCSHeader";
#endif

/*

:User Limit to watch an input bit and set an output bit.

This sample code shows how to configure the XMP controller's User Limits
 to compare an input bit to a specific pattern.  If the pattern matches,
 then the specified output bit is activated and a User Event is generated
 to the host.

The XMP-Series controller "User Limit" feature allows the user to program a
 the result of two logical condition to generate an event to the host.  Also,
 a "User Limit" can be configured to write an "output" to any XMP memory
 location, using an AND mask and OR mask.

Here is the "User Limit" block structure:

typedef struct {
    MEIXmpLimitType         Type;
    void                    *SourceAddress;
    long                    Mask;
    MEIXmpGenericValue      LimitValue;
} MEIXmpLimitCondition;

typedef struct {
    long                    AndMask;
    long                    OrMask;
    long                    *OutputPtr;
    long                    Enabled;
} MEIXmpLimitOutput;

typedef struct {
    MEIXmpLimitCondition    Condition[MEIXmpLimitConditions];
    MEIXmpStatus            Status;
    MEIXmpLogic             Logic;
    MEIXmpLimitOutput       Output;
    long                    Count;
    long                    State;
} MEIXmpLimitData;

MEIXmpLimitTypes are the operators that are used for the User Limit's
 Condition[0] and Condition[1].  They are found in xmp.h.

*SourceAddress is a pointer to an XMP memory location.

Mask is ANDed with the value located at the *SourceAddress.

LimitValue is compared with the masked value located at *SourceAddress,
 using the Type operator.

Status defines the status bit used to generate an event to the host.

MEIXmpLogic is the logic applied between the two condition block outputs,
 Condition[0] and Condition[1]:

 MEIXmpLogicNEVER
    Does NOT evaluate Condition[0], Condition[1].  No event is generated.

 MEIXmpLogicSINGLE
    Only evaluates Condition[0].  Event is generated if Condition[0] is TRUE.

 MEIXmpLogicOR
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    OR Condition[1]) = TRUE.

 MEIXmpLogicAND
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    AND Condition[1]) = TRUE.

The other MEIXmpLogic enums in xmp.h are for internal use only.

*OutputPtr is a pointer to an XMP memory location.

AndMask is ANDed, and OrMask is ORed with the value located at
 *OutputPtr when the resultant MEIXmpLogic applied Condition[0] and
 Condition[1] are TRUE.

Count and State are for internal use only.  Do not write these values.
  The MPI method, mpiMotorEventConfigSet(...) will not write these values.

The XMP supports up to 8 User Limits per motor.  The User Limit processing
 occurs in the firmware background task.  For maximum efficiency, the XMP only
 processes the User Limits (in order 0, 1, 2, etc.), up to the largest User
 Limit number that has (motorEventConfig.Logic ! = MEIXmpLogicNEVER).

For example:
 If UserLimit 0 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    only process the first UserLimit for each motor.
 If UserLimit 3 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    process UserLimits number 0, 1, 2, and 3 for each motor.

It's best to use the lower numbered UserLimits for maximum efficiency.  When
 finished using UserLimits, it's a good idea to set the Logic to
 MEIXmpLogicNEVER.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    UsrLim1Main

argMainRENAME(main, UsrLim1)
#endif

/* Motor I/O Configurations */
#define INPUT_BIT       (MEIMotorTransceiverIdC)    /* A, B, or C */
#define INPUT_MASK      (MEIMotorTransceiverMaskC)  /* mask for input bit */
#define ACTIVE_STATE    (FALSE)                     /* trigger on active or inactive */

#define OUTPUT_BIT      (MEIMotorTransceiverIdB)    /* A, B, or C */
#define OUTPUT_MASK     (MEIMotorTransceiverMaskB)  /* mask for output bit */
#define OUTPUT_INVERT   (TRUE)                      /* inverted or normal */

/* User Limit Event configuration */
#define EVENT_TYPE      (MEIEventTypeLIMIT_USER0)   /* 0, 1, 2...7 */

/* Notify Wait Timeout */
#define CYCLE_TIME          (100)                   /* msec */

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

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

/* Function Prototypes */
long XcvrUserLimitSet(MPIMotor motor,
                      long inputMask,
                      long inputActiveState,
                      long outputMask,
                      MEIEventType eventType);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis object */
    MPIMotion   motion;     /* motion object */
    MPIMotor    motor;      /* motor object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    MEIMotorConfig  motorConfigXmp;  /* XMP motor I/O configuration */

    long    motionNumber;   /* motion supervisor number */
    long    axisNumber;
    long    returnValue;    /* return value from library */

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motorNumber >= MEIXmpMAX_Motors)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1);
        exit(MPIMessageARG_INVALID);
    }

    /* Use a one to one relationship between motor, axis, and motion */
    motionNumber = motorNumber;
    axisNumber = motorNumber;

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create motor object for motorNumber */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    /* Configure the specified INPUT_BIT */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Transceiver[INPUT_BIT].Config = MEIMotorTransceiverConfigINPUT;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Configure the specified OUTPUT_BIT */
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    motorConfigXmp.Transceiver[OUTPUT_BIT].Config = MEIMotorTransceiverConfigOUTPUT;
    motorConfigXmp.Transceiver[OUTPUT_BIT].Invert = OUTPUT_INVERT;

    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Configure User Limit */
    returnValue =
        XcvrUserLimitSet(motor,
                         INPUT_MASK,
                         ACTIVE_STATE,
                         OUTPUT_MASK,
                         EVENT_TYPE);
    msgCHECK(returnValue);

    printf("Press any key to exit ...\n");

    /* Loop repeatedly */
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        /* Wait for events */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               (MPIWait)CYCLE_TIME);

        if (returnValue == MPIMessageTIMEOUT) {     /* ignore timeouts */
            returnValue = MPIMessageOK;
        }
        else {
            msgCHECK(returnValue);

            info = (MEIEventStatusInfo *)eventStatus.info;

            switch (eventStatus.type) {
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER0: {
                    printf("\nUser Limit #0, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER1: {
                    printf("\nUser Limit #1, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER2: {
                    printf("\nUser Limit #2, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER3: {
                    printf("\nUser Limit #3, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER4: {
                    printf("\nUser Limit #4, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER5: {
                    printf("\nUser Limit #5, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER6: {
                    printf("\nUser Limit #6, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }
                /* User Limit Event from motor source */
                case MEIEventTypeLIMIT_USER7: {
                    printf("\nUser Limit #7, type %d source 0x%x info 0x%x",
                            eventStatus.type,
                            eventStatus.source,
                            eventStatus.info[0]);
                    break;
                }

                default: {
                    printf("mpiNotifyEventWait() returns 0x%x\n"
                        "\teventStatus: type %d source 0x%x info 0x%x\n",
                        returnValue,
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                    break;
                }
            }
        }
    }

    printf("\n");

    /* Delete objects */
    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long XcvrUserLimitSet(MPIMotor motor,
                      long inputMask,
                      long inputActiveState,
                      long outputMask,
                      MEIEventType eventType)
{
    MPIControl          control;

    MEIXmpData          *firmware;

    MEIMotorEventConfig motorEventConfig;
    MEIXmpStatus        status;

    long                returnValue;
    long                motorIndex;
    MPIEventMask        resetMask;

    /* Determine motor number */
    returnValue =
        mpiMotorNumber(motor,
                       &motorIndex);

    /* Determine control handle */
    if(returnValue == MPIMessageOK) {
        control = mpiMotorControl(motor);
        returnValue = mpiControlValidate(control);
    }

    /* Get pointer to XMP firmware */
    if(returnValue == MPIMessageOK) {
        returnValue =
            mpiControlMemory(control,
                             (void **)&firmware,
                             NULL);
    }

    mpiEventMaskCLEAR(resetMask);

    if (returnValue == MPIMessageOK) {
        switch (eventType) {
            case MEIEventTypeLIMIT_USER0: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER0);
                break;
            }
            case MEIEventTypeLIMIT_USER1: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER1);
                break;
            }
            case MEIEventTypeLIMIT_USER2: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER2);
                break;
            }
            case MEIEventTypeLIMIT_USER3: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER3);
                break;
            }
            case MEIEventTypeLIMIT_USER4: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER4);
                break;
            }
            case MEIEventTypeLIMIT_USER5: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER5);
                break;
            }
            case MEIEventTypeLIMIT_USER6: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER6);
                break;
            }
            case MEIEventTypeLIMIT_USER7: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER7);
                break;
            }
            default:
                printf("\nError, invalid event type\n");
                break;
        }

        returnValue =
            mpiMotorEventConfigGet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    if (returnValue == MPIMessageOK) {
        /* Set up the Condition[0] block.  The operator between the value in
            the SourceAddress (masked by the Mask), and LimitValue.l, is
            MEIXmpLimitTypeBIT_CMP (equals).  Thus, when the value in
            SourceAddress equals the value in LimitValue.l, then the
            Condition[0] block is TRUE.
        */
        motorEventConfig.Condition[0].Type = MEIXmpLimitTypeBIT_CMP;
        motorEventConfig.Condition[0].SourceAddress =
            &firmware->Motor[motorIndex].IO.DedicatedIN.IO;     /* input address */
        motorEventConfig.Condition[0].Mask = inputMask;         /* AND mask */
        motorEventConfig.Condition[0].LimitValue.l =
            inputActiveState ? inputMask : 0x0;                 /* expected value */

        /* Set up the Condition[1] block.  The operator is MEIXmpLimitTypeFALSE.
            Therefore, the Condition[1] block is always FALSE.
        */
        motorEventConfig.Condition[1].Type = MEIXmpLimitTypeFALSE;
        motorEventConfig.Condition[1].SourceAddress = NULL;
        motorEventConfig.Condition[1].Mask = 0;
        motorEventConfig.Condition[1].LimitValue.l = 0;

        motorEventConfig.Status = status;
        /* Determine logic result from Condition[0] only */
        motorEventConfig.Logic  = MEIXmpLogicSINGLE;

        motorEventConfig.Output.OutputPtr =
            &firmware->Motor[motorIndex].IO.MotorOutput;    /* output address */
        motorEventConfig.Output.AndMask = 0xffffffff;
        motorEventConfig.Output.OrMask = outputMask;
        motorEventConfig.Output.Enabled = TRUE;

        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    /* Reset event in case conditions have already been satisfied */
    if (returnValue == MPIMessageOK) {
        returnValue =
                mpiMotorEventReset(motor,
                                   resetMask);
    }

    return returnValue;
}


usrlim2.c -- Position comparison using User Limits to generate events.

.

usrlim2.c -- Position comparison using User Limits to generate events.
/* UsrLim2.c */

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

/*

:Position comparison using User Limits to generate events.

This sample code shows how to configure the XMP controller's User Limits
 to compare an axis' actual position to a specific position value.  If the
 actual position is greater than or equal to the value specified, then
 the controller will generate a User Event to the Host.

The function CompareLimitSet(...) demonstrates how to configure a
 User Limit for position compare.

The XMP-Series controller "User Limit" feature allows the user to program a
 the result of two logical condition to generate an event to the host.  Also,
 a "User Limit" can be configured to write an "output" to any XMP memory
 location, using an AND mask and OR mask.

Here is the "User Limit" block structure:

typedef struct {
    MEIXmpLimitType         Type;
    void                    *SourceAddress;
    long                    Mask;
    MEIXmpGenericValue      LimitValue;
} MEIXmpLimitCondition;

typedef struct {
    long                    AndMask;
    long                    OrMask;
    long                    *OutputPtr;
    long                    Enabled;
} MEIXmpLimitOutput;

typedef struct {
    MEIXmpLimitCondition    Condition[MEIXmpLimitConditions];
    MEIXmpStatus            Status;
    MEIXmpLogic             Logic;
    MEIXmpLimitOutput       Output;
    long                    Count;
    long                    State;
} MEIXmpLimitData;

MEIXmpLimitTypes are the operators that are used for the User Limit's
 Condition[0] and Condition[1].  They are found in xmp.h.

*SourceAddress is a pointer to an XMP memory location.

Mask is ANDed with the value located at the *SourceAddress.

LimitValue is compared with the masked value located at *SourceAddress,
 using the Type operator.

Status defines the status bit used to generate an event to the host.

MEIXmpLogic is the logic applied between the two condition block outputs,
 Condition[0] and Condition[1]:

 MEIXmpLogicNEVER
    Does NOT evaluate Condition[0], Condition[1].  No event is generated.

 MEIXmpLogicSINGLE
    Only evaluates Condition[0].  Event is generated if Condition[0] is TRUE.

 MEIXmpLogicOR
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    OR Condition[1]) = TRUE.

 MEIXmpLogicAND
    Evaluates Condition[0], Condition[1].  Event is generated if (Condition[0]
    AND Condition[1]) = TRUE.

The other MEIXmpLogic enums in xmp.h are for internal use only.

*OutputPtr is a pointer to an XMP memory location.

AndMask is ANDed, and OrMask is ORed with the value located at
 *OutputPtr when the resultant MEIXmpLogic applied Condition[0] and
 Condition[1] are TRUE.

Count and State are for internal use only.  Do not write these values.
  The MPI method, mpiMotorEventConfigSet(...) will not write these values.

The XMP supports up to 8 User Limits per motor.  The User Limit processing
 occurs in the firmware background task.  For maximum efficiency, the XMP only
 processes the User Limits (in order 0, 1, 2, etc.), up to the largest User
 Limit number that has (motorEventConfig.Logic ! = MEIXmpLogicNEVER).

For example:
 If UserLimit 0 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    only process the first UserLimit for each motor.
 If UserLimit 3 (motor 0) is configured for MEIXmpLogicSINGLE, then the XMP will
    process UserLimits number 0, 1, 2, and 3 for each motor.

It's best to use the lower numbered UserLimits for maximum efficiency.  When
 finished using UserLimits, it's a good idea to set the Logic to
 MEIXmpLogicNEVER.

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 "stdmpi.h"
#include "stdmei.h"

#include "apputil.h"

#if defined(ARG_MAIN_RENAME)
#define main    UsrLim2Main

argMainRENAME(main, UsrLim2)
#endif

#define MOTION_COUNT        (2)

/* User Limit configurations */
#define EVENT_TYPE          (MEIEventTypeLIMIT_USER0)   /* 0, 1, 2...7 */
#define COMPARE_POSITION    (10000)                     /* Actual Position */

/* Command line arguments and defaults */
long            axisNumber      = 0;
long            motionNumber    = 0;
long            motorNumber     = 0;
MPIMotionType   motionType      = MPIMotionTypeS_CURVE;

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

    {   NULL,       ArgTypeINVALID, NULL,   }
};

double position[MOTION_COUNT] = {
    20000.0,
    0.0,
};

MPITrajectory trajectory[MOTION_COUNT] = {
    /* velocity     accel       decel       jerkPercent */
    { 10000.0,      1000000.0,  1000000.0,  0.0,    },
    { 10000.0,      100000.0,   100000.0,   0.0,    },
};

/* Motion Parameters */
MPIMotionSCurve sCurve[MOTION_COUNT] = {
    {   &trajectory[0], &position[0],   },
    {   &trajectory[1], &position[1],   },
};

MPIMotionTrapezoidal    trapezoidal[MOTION_COUNT] = {
    {   &trajectory[0], &position[0],   },
    {   &trajectory[1], &position[1],   },
};

MPIMotionVelocity   velocity[MOTION_COUNT] = {
    {   &trajectory[0], },
    {   &trajectory[1], },
};

/* Function Prototypes */
long CompareLimitSet(MPIAxis axis,
                     MPIMotor motor,
                     long position,
                     MEIEventType eventType);

int
    main(int    argc,
         char   *argv[])
{
    MPIControl  control;    /* motion controller handle */
    MPIAxis     axis;       /* axis object */
    MPIMotion   motion;     /* motion object */
    MPIMotor    motor;      /* motor object */
    MPINotify   notify;     /* event notification object */
    MPIEventMgr eventMgr;   /* event manager handle */

    MPIEventMask    eventMask;

    long    returnValue;    /* return value from library */

    long    index;
    long    motionDone;     /* flag when Done occurs */

    Service service;

    MPIControlType      controlType;
    MPIControlAddress   controlAddress;

    long    argIndex;

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   &controlType,
                   &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) ||
        (motionNumber >= MEIXmpMAX_MSs) ||
        (motorNumber >= MEIXmpMAX_Motors) ||
        (motionType < MPIMotionTypeFIRST) ||
        (motionType >= MEIMotionTypeLAST)) {
        meiPlatformConsole("usage: %s %s\n"
                           "\t\t[-axis # (0 .. %d)]\n"
                           "\t\t[-motion # (0 .. %d)]\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                           "\t\t[-type # (0 .. %d)]\n",
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Axes - 1,
                            MEIXmpMAX_MSs - 1,
                            MEIXmpMAX_Motors - 1,
                            MEIMotionTypeLAST - 1);
        exit(MPIMessageARG_INVALID);
    }

    switch (motionType) {
        case MPIMotionTypeS_CURVE:
        case MPIMotionTypeTRAPEZOIDAL:
        case MPIMotionTypeVELOCITY: {
            break;
        }
        default: {
            meiPlatformConsole("%s: %d: motion type not available\n",
                                argv[0],
                                motionType);
            exit(MPIMessageUNSUPPORTED);
            break;
        }
    }

    /* Create motion controller object */
    control =
        mpiControlCreate(controlType,
                         &controlAddress);
    msgCHECK(mpiControlValidate(control));

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

    /* Create axis object for axisNumber */
    axis =
        mpiAxisCreate(control,
                      axisNumber);
    msgCHECK(mpiAxisValidate(axis));

    /* Create motor object for motorNumber */
    motor =
        mpiMotorCreate(control,
                       motorNumber);
    msgCHECK(mpiMotorValidate(motor));

    /* Create motion object, appending the axis object */
    motion =
        mpiMotionCreate(control,
                        motionNumber,
                        axis);
    msgCHECK(mpiMotionValidate(motion));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    returnValue =
        mpiMotionEventNotifySet(motion,
                                eventMask,
                                NULL);
    msgCHECK(returnValue);

    /* Create event notification object for motion */
    notify =
        mpiNotifyCreate(eventMask,
                        motion);
    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 */
    meiASSERT(service != NULL);

    /* Configure the Position Compare, using a User Limit */
    returnValue =
        CompareLimitSet(axis,
                        motor,
                        COMPARE_POSITION,
                        EVENT_TYPE);
    msgCHECK(returnValue);

    printf("Press any key to exit ...\n");

    /* Loop repeatedly */
    index       = 0;
    motionDone  = TRUE;
    while (meiPlatformKey(MPIWaitPOLL) <= 0) {
        MPIEventStatus      eventStatus;
        MEIEventStatusInfo  *info;

        if (motionDone) {
            MPIMotionParams     motionParams;       /* motion parameters */

            /* fill in the MPIMotionParams structure */
            switch (motionType) {
                case MPIMotionTypeS_CURVE: {
                    motionParams.sCurve = sCurve[index];
                    break;
                }
                case MPIMotionTypeTRAPEZOIDAL: {
                    motionParams.trapezoidal = trapezoidal[index];
                    break;
                }
                case MPIMotionTypeVELOCITY: {
                    motionParams.velocity = velocity[index];
                    break;
                }
                default: {
                    meiASSERT(FALSE);
                    break;
                }
            }

            printf("\n\nMotion Start...");

            /* Start Motion */
            returnValue =
                mpiMotionStart(motion,
                               motionType,
                               &motionParams);
            msgCHECK(returnValue);

            motionDone = FALSE;
        }

        /* Wait for events */
        returnValue =
            mpiNotifyEventWait(notify,
                               &eventStatus,
                               MPIWaitFOREVER);
        msgCHECK(returnValue);

        info = (MEIEventStatusInfo *)eventStatus.info;

        switch (eventStatus.type) {
            /* In Coarse Event from axis source */
            case MEIEventTypeIN_POSITION_COARSE: {
                printf("\nInCoarse (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeIN_POSITION_FINE: {
                printf("\nInFine (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* In Fine Event from axis source */
            case MEIEventTypeAT_TARGET: {
                printf("\nAtTarget (%ld)",
                       info->data.axis.sampleCounter);
                break;
            }
            /* Motion Done Event from motion source */
            case MPIEventTypeMOTION_DONE: {
                printf("\nDone (%ld)",
                       info->data.motion.sampleCounter);

                motionDone = TRUE;

                if (++index >= MOTION_COUNT) {
                    index = 0;
                }
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER0: {
                printf("\nUser Limit #0, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER1: {
                printf("\nUser Limit #1, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER2: {
                printf("\nUser Limit #2, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER3: {
                printf("\nUser Limit #3, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER4: {
                printf("\nUser Limit #4, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER5: {
                printf("\nUser Limit #5, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER6: {
                printf("\nUser Limit #6, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }
            /* User Limit Event from motor source */
            case MEIEventTypeLIMIT_USER7: {
                printf("\nUser Limit #7, type %d source 0x%x info 0x%x",
                        eventStatus.type,
                        eventStatus.source,
                        eventStatus.info[0]);
                break;
            }

            default: {
                printf("mpiNotifyEventWait() returns 0x%x\n"
                    "\teventStatus: type %d source 0x%x info 0x%x\n",
                    returnValue,
                    eventStatus.type,
                    eventStatus.source,
                    eventStatus.info[0]);
                break;
            }
        }
    }

    printf("\n");

    /* Delete objects */
    returnValue = mpiMotorDelete(motor);
    msgCHECK(returnValue);

    returnValue = mpiMotionDelete(motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(axis);
    msgCHECK(returnValue);

    returnValue = serviceDelete(service);
    msgCHECK(returnValue);

    returnValue = mpiEventMgrDelete(eventMgr);
    msgCHECK(returnValue);

    returnValue = mpiNotifyDelete(notify);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(control);
    msgCHECK(returnValue);

    return ((int)returnValue);
}

long CompareLimitSet(MPIAxis axis,
                     MPIMotor motor,
                     long position,
                     MEIEventType eventType)
{
    MEIXmpAxis          *xmpAxis;

    MEIMotorEventConfig motorEventConfig;
    MEIXmpStatus        status;

    long                returnValue;
    MPIEventMask        resetMask;

    returnValue  =
        mpiAxisMemory(axis,
                      (void **)&xmpAxis);

    if (returnValue == MPIMessageOK) {
        returnValue  =
            mpiAxisMemory(axis,
                          (void **)&xmpAxis);
    }

    mpiEventMaskCLEAR(resetMask);

    if (returnValue == MPIMessageOK) {
        switch (eventType) {
            case MEIEventTypeLIMIT_USER0: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER0);
                break;
            }
            case MEIEventTypeLIMIT_USER1: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER1);
                break;
            }
            case MEIEventTypeLIMIT_USER2: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER2);
                break;
            }
            case MEIEventTypeLIMIT_USER3: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER3);
                break;
            }
            case MEIEventTypeLIMIT_USER4: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER4);
                break;
            }
            case MEIEventTypeLIMIT_USER5: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER5);
                break;
            }
            case MEIEventTypeLIMIT_USER6: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER6);
                break;
            }
            case MEIEventTypeLIMIT_USER7: {
                status = MEIXmpStatusLIMIT;
                mpiEventMaskSET(resetMask, MEIEventTypeLIMIT_USER7);
                break;
            }
            default:
                printf("\nError, invalid event type\n");
                break;
        }

        returnValue =
            mpiMotorEventConfigGet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    if (returnValue == MPIMessageOK) {
        /* Set up the Condition[0] block.  The operator between the value in the
            SourceAddress (masked by the Mask), and LimitValue.l, is
            MEIXmpLimitTypeGT (greater than).  Thus, when the value in
            SourceAddress is "GT" (greater than) the value in LimitValue.l,
            then the Condition[0] block is TRUE.
        */
        motorEventConfig.Condition[0].Type = MEIXmpLimitTypeGT;
        motorEventConfig.Condition[0].SourceAddress = &(xmpAxis->ActualPosition);
        motorEventConfig.Condition[0].Mask = 0xffffffff;
        motorEventConfig.Condition[0].LimitValue.l = position;

        /* Set up the Condition[1] block.  The operator is MEIXmpLimitTypeFALSE.
            Therefore, the Condition[1] block is always FALSE.
        */
        motorEventConfig.Condition[1].Type = MEIXmpLimitTypeFALSE;
        motorEventConfig.Condition[1].SourceAddress = NULL;
        motorEventConfig.Condition[1].Mask = 0;
        motorEventConfig.Condition[1].LimitValue.l = 0;

        motorEventConfig.Status = status;
        /* Determine logic result from Condition[0] only */
        motorEventConfig.Logic  = MEIXmpLogicSINGLE;

        /* Disable the output feature */
        motorEventConfig.Output.OutputPtr = NULL;
        motorEventConfig.Output.AndMask = 0x0;
        motorEventConfig.Output.OrMask = 0x0;
        motorEventConfig.Output.Enabled = 0;

        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)eventType,
                                   NULL,
                                   &motorEventConfig);
    }

    /* Reset event in case conditions have already been satisfied */
    if (returnValue == MPIMessageOK) {
        returnValue =
                mpiMotorEventReset(motor,
                                   resetMask);
    }

    return returnValue;
}


MPI Software Concepts Home

.

MPI Library Basics
Introduction
MPI Objects Overview
Motion Concepts
General Definitions
Naming Conventions
Object Descriptions

Software Topics
 Encoder Fault for Secondary Encoders New!
SynqNet Network Topology Verification New!
Saving Current SynqNet Topology to Flash New!
Upgrading Software to SynqNet Phase II New!
Motor Brake (brake enable/disable delay) New!
Object Relationships
Host and Controller Based Motion
Multitasking
Configuration Diagram
Servo Algorithms: PID / PIV
Project / Makefile Settings
About Homing
Using the Origin Variable
How Stop Events Work
Compiling Program Sequencer Commands
Running Multiple Applications with the XMP
Perform a Point-to-Point Coordinated Move
About PID PIDOutputOffset Parameter
How Motion Completion Events are Generated
S-Curve Jerk Algorithm and Attributes
S-Curve Motion Profiles:
Command Acceleration vs. Peak Acceleration
Default XMP-Series Controller Configuration
Axis Tolerances and Related Events
Compares and Encoder Rollovers

FAQs
 - What is the MPI?
- What is the difference between 'mpi' and 'mei' data types and methods?
- What is the difference between the MPI and the MPX?

- more >>

Methods
 Object Methods
Configuration Methods
Memory Methods
Status Methods
Event Notification Methods
List Methods
Identity Methods


General Definitions

MPI | Platform | MPI Installation Directory | Object | Handle | Method | Module

MPI

The Motion Programming Interface (MPI) defines a set of object-oriented, C-language functions and data types that you can use to develop motion control applications. The MPI is designed to be independent of the motion controller hardware used, as well as the platform (operating system & compiler) on which the motion control application is built. To support the MPI, a platform must be 32-bit (e.g. Windows NT). Most 32-bit platforms are capable of multi-threading and multi-tasking, and the MPI has built-in features that simplify the design and development of these types of applications.

For XMP only Instructions for the implementation of MPI in Motion Engineering’s XMP motion controller are flagged with the notice “For XMP only."

To add custom features, applications often make use of extensions to the MPI, which limits portability.

Platform

A platform is the combination of the host computer, operating system, and C compiler. A platform must be 32-bit, i.e., the operating system must be able to execute 32-bit programs.
For XMP only The MPI/XMP has been ported to the WindowsNT/Microsoft Visual C++ platform. This platform is referred to as XMP-WinNT. If you are interested in using the MPI/XMP with other operating systems and C compilers, please contact MEI.

MPI Installation Directory

The MPI installation directory is the location into which the MPI software has been installed. The installation procedure suggests a default location (C:\MEI), but you can choose to install it wherever you desire. It is highly recommended that you use the default location. The installation directory contains an MPI directory:

MPI Subdirectories
Directory \ MPI | Contains
\doc | Documentation – User and Reference Guides
\include | MPI header files

For XMP-WinNT only The default installation directory is C:\MEI, and it contains a release note named YYYYMMDD.pdf, where YYYY represents the year, MM the month, and DD the day of the release. The installation directory also contains an XMP directory, which has various subdirectories.

XMP Subdirectories
Directory: C:\MEI\XMP Contains

\app

 Sample applications

\bin

 XMP firmware

\bin\WinNT

 Windows NT utilities (from util)

\doc

 Documentation - XMP Harware and Software Reference

\include

 XMP header files

\lib

 XMP libraries

\util

 XMP utility source

Object

An object is an instance of a data structure. The data structure is typically not directly accessible by an application.
When an application calls a function (also called a method) to create an object, the function returns a handle to the object. The object handle is then passed as the first argument to all other functions (methods) that are associated with that object. These functions provide indirect access to the object’s data structure. When it is finished using an object, an application simply calls another function to delete it.
Example The MPI defines an Axis object. An Axis object is created by the mpiAxisCreate(...) function, which returns a handle of type MPIAxis. The mpiAxisStatus(...) function takes an Axis handle as its first argument and returns the status of the hardware axis with which the Axis object is associated. An Axis object is deleted by calling the mpiAxisDelete(...) function.

Handle

A handle is returned by the function that creates an object, and the handle uniquely identifies that object. A handle is simply a pointer to a pointer to an object. The MPI defines the type MPIHandle to be a generic handle. The symbol MPIHandleVOID is used to represent an invalid handle. The MPI functions that create and delete objects typically allocate and free memory from a heap; in this case a handle is generally a pointer to the allocated object data structure. However, an MPI implementation could define a handle to be a pointer into a static array of data structures, or an index into such an array. Regardless, an application MUST NOT do anything with a handle other than to pass it as an argument to other functions. In cases where a handle is a pointer, the pointer cannot be dereferenced, because the object data structure to which the handle points is not directly available to the application.

Example The MPI defines an Axis handle to be of type MPIAxis. An axis handle named axisHandle can be declared as follows: MPIAxis axisHandle;

Method

A function associated with an object is called a method. The first argument of a method is always the handle of the object with which it is associated. A function that is not associated with an object is called a function. Throughout the MPI documentation, the term function refers to methods and functions, whereas the term method only refers to methods.

Example The following functions are all considered to be methods: mpiAxisCreate(...), mpiAxisStatus(...), mpiAxisDelete(...). Except for mpiAxisCreate(...), these functions all take an MPIAxis handle as their first argument.
                      MPIAxis axis;
                      axis = mpiAxisCreate(…);
                      mpiAxisStatus(axis, …);
                      mpiAxisDelete(axis);

Module

A module is a source file (module.c) whose interface is declared in a header file (module.h). A module contains code symbols (methods, functions, macros) and data symbols (data, data types and constants) that together implement an object. However, a module may also contain functions that have a logical connection without being associated with an object.

MPI Module | Header
Adc | adc.h
Axis | axis.h
Capture | capture.h
Command | command.h
Control | control.h
Event | event.h
EventMgr | eventmgr.h
Filter | filter.h
Idn | idn.h
IdnList | idnlist.h
Message | message.h
Motion | motion.h
Motor | motor.h
MpiDef | mpidef.h
Node | node.h
Notify | notify.h
Object | object.h
Recorder | recorder.h
Sequence | sequence.h
Sercos | sercos.h
StdMpi | stdmpi.h

XMP Module | Header
Client | client.h
Element | element.h
Firmware | firmware.h
Flash | flash.h
List | list.h
Map | map.h
MeiDef | meidef.h
Packet | packet.h
Platform | platform.h
Remove | remove.h
RipTide | riptide.h
Server | server.h
Trace | trace.h
XMP | xmp.h

Utility Module | Header
msgCHECK | msg.h
Service | service.h
Log | log.h
LogFunc | logFunc.h

Example The axis module consists of a source file called axis.c and a header file called axis.h. The axis.c source file contains the definitions of all Axis code and data symbols, in particular the Axis object data structure. The axis.h header file contains the declarations for the code and data symbols in axis.c.
Introduction | Motion Concepts | General Definitions | Naming Conventions | Object Descriptions


Introduction to the MPI Library

The MPI is a C language object-oriented interface that makes it easy for you to develop motion control applications that run on many different types of platforms. Programs written using the MPI range from simple single-task, single-controller applications to complex multi-tasking applications using multiple motion controllers. The MPI hides platform-specific and firmware implementation details while providing a rich set of functions to control motion at any desired level. As a system designer, you have complete flexibility to choose the level of control best suited for your application. The MPI library executes on the host computer, while the firmware executes on the XMP controller.

The XMP’s firmware components are managed by host software using the MPI (Motion Programming Interface). The MPI provides direct memory access to all XMP firmware components, delivering much more performance than competing systems that use command-based controllers or ASCII interfaces. Designed for multitasking environments, the MPI can access one or more motion controllers at maximum bus bandwidth, while efficiently handling controller interrupts.

Debugging under the MPI environment is simple if you use the configurable trace and debug features. The trace feature enables you to follow the progress of an executing program by observing the stream of messages produced whenever a library function is entered (displaying calling parameters) and whenever a library function is exited (displaying the return value).

You also have the ability to validate all library function parameters, and to stop execution whenever an error occurs, displaying the source file name and line number where the error occurred. You can configure the MPI for optimal trace and debug support during the design and test phase, and then reconfigure the MPI for optimal performance (without the debugging support).


Motion Concepts

Introduction | Maps & Links | Motor Links | Filter Links
Axis Links | see Object Relationships

Introduction

The XMP software architecture is composed of separate modular objects that can be associated in a variety of ways to create custom systems. For example, a gantry or robot using more than one motor for a physical axis may be configured to allow the application to treat the axis as a single entity, simplifying the geometry. This flexibility does not come without a price, however, since configuration of complex systems involves a fairly large number of parameters. To overcome the need to configure simple "standard" systems, the XMP is pre-configured with a factory default configuration which can be used for most simple systems.

To understand how to create a custom XMP configuration, you must understand the component objects involved. Custom configurations are created using four types of objects: Motors, Filters, Axes, and Motion Supervisors (called Motion objects). To simplify implementation of the XMP architecture, we assumed that the association of Motors, Filters, and Axis would be more or less static (created during initialization), while association of Axes with Motion Supervisors would be more dynamic (created or modified during runtime).

Maps & Links

The relationships between the controller objects are determined by Maps and Links associated with the objects. The Maps are used by the MPI to define the object relationships and usually have the form of bitmaps. The following MPI functions are used to read and write these Maps.

mpiMotorAxisMapGet(...) | .
mpiMotorFilterMapGet(...) | mpiMotorFilterMapSet(...)
mpiFilterAxisMapGet(...) | mpiFilterAxisMapSet(...)
mpiFilterMotorMapGet(...) | mpiFilterMotorMapSet(...)
mpiAxisMotorMapGet(...) | .
mpiAxisFilterMapGet(...) | mpiAxisFilterMapSet(...)

Note that there are no functions to write any Motor-Axis or Axis-Motor maps. This is because these relationships are defined by the maps of the associated filters.

The links are used by the controller's objects to determine the sources for data generated by other objects. These links generally have the form of pointers that reference the source of the data or indexes that identify the sourcing object.

Motor Links

There can be up to 2 filter outputs used in calculating the output level of the Motor command. The following expression is evaluated each sample to determine this output:

Filter Links

The Filter object uses the difference between command and actual positions to calculate a control output (control algorithm). Both the command and actual positions used in these calculations can be defined as a linear combination of positions from 2 different sources.

MEIFilterConfig{}.Axis[] determine the sources and weight factors for these position inputs. On each sample, the following equations are used to determine the position error and command position used by the Filter:

The command velocity and acceleration used in feedforward calculations is also determined from MEIFilterConfig{}.AxisInput[], using the following equations:

Axis Links

The actual position of an axis can be calculated as a linear combination of position values from two separate sources. On each sample, the following equation is used to compute the Axis' actual position:

Introduction | Motion Concepts | General Definitions | Naming Conventions | Object Descriptions


Naming Conventions

Uniqueness | Symbol Declaration & Definition | Symbol Naming | Data Symbols | Code Symbols

Uniqueness

We have tried to make the names of all MPI code and data symbols unique, so that the names don’t conflict with symbols already defined in the supported operating systems, and in C language and third-party libraries. The MPI naming convention enables you to look at a symbol and know whether the symbol refers to code or data. The MPI uses “MPI” as the initial token of data symbols, while code symbols use an initial token of “mpi”.
Example The axis handle data type is called MPIAxis. The method that creates an axis object is called mpiAxisCreate(...).

MPI/XMP: MEI-specific additions and extensions to the MPI are named similarly with an initial token of “MEI” indicating a data symbol and “mei” indicating a code symbol.

Example The MEIAxisConfig{} data structure contains XMP-specific axis configuration parameters that extend the MPI-defined axis configuration parameters. The meiFilterCreate(...) function creates a Filter object, returning a handle of type MEIFilter. The Filter object is an addition to the MPI.

Symbol Declaration & Definition

MPI symbols are declared in header files and defined in source files. To determine the file in which an MPI symbol is declared and defined, look at the second token of the symbol name: the second token indicates the module where the symbol is declared and defined. Also, to maximize the portability of the code, the MPI uses a DOS-like 8.3 file naming convention. Therefore, the second token of any symbol name will not exceed 8 characters, nor will the names of modules and objects.

For example, consider a symbol named MPIObjectXyz. The symbol is a data symbol (MPI) declared in object.h and defined in object.c. Similarly, a symbol named mpiObjectAbc is a code symbol (mpi) declared in object.h and defined in object.c.
Example The MPIAxis data type and the mpiAxisCreate(...) method are declared in the header file axis.h. The MEIServer data type and meiServerDelete(...) method are declared in header file server.h. The code and data symbols for the Axis object are defined in axis.c; for the Server object, they are defined in server.c.

Symbol Naming

The previous sections use the concept of a token when discussing symbol names, where a token is a word or abbreviation contained in a symbol name. The name of an MPI symbol consists of a left-to-right sequence of tokens (with no spaces in between). An uppercase letter indicates the beginning of a token, except the first token of a symbol, which may be either upper (MPI) or lower case (mpi). The MPI uses underscores in symbol names only when it is necessary to separate tokens that are all uppercase letters.

The first token of a symbol (MPI or mpi) guarantees uniqueness and indicates whether the symbol is a data symbol (MPI) or a code symbol (mpi) . The second token indicates the module that declares and defines the symbol. The remaining tokens of the symbol name vary, depending on whether the symbol is code or data.

Data Symbols

Tokens in data symbols are arranged from left-to-right in a hierarchical fashion, with the leftmost token being general and the rightmost token being specific. If the data symbol names are listed alphabetically, this scheme results in an listing that groups related data symbols together.

If the rightmost token of a data symbol is all uppercase, then that data symbol is a constant. If the rightmost token of a data symbol is not all uppercase, then that data symbol is either data or a data type. Because the MPI contains virtually no global data, there is little need to distinguish between data and data type.

Consider the MPIMotorHomeIndex enumeration:

typedef enum {
    MPIMotorHomeIndexINVALID = -1,

    MPIMotorHomeIndexHOME_HI_INDEX,
    MPIMotorHomeIndexINDEX_ONLY,
    MPIMotorHomeIndexHOME_LO_INDEX,
    MPIMotorHomeIndexHOME_ONLY,

    MPIMotorHomeIndexLAST,
    MPIMotorHomeIndexFIRST = MPIMotorHomeIndexINVALID + 1
} MPIMotorHomeIndex;
The third and fourth tokens (Home, Index) are the same for all symbols. The enum name (MPIMotorHomeIndex) is incorporated in the name of all of the enum members, whose last token is all uppercase (FIRST, HOME_HI_INDEX, etc.) to indicate that they are constants (instead of a data type). It is standard coding practice to use enums rather than #defines to declare constants, which allows for greater control of the name space and better type-checking. The use of FIRST and LAST members in an enum is also standard coding practice, so that functions can bounds-check enum values.

Code Symbols

Tokens in code symbols indicate the data type and order of the arguments to the function. The last token in a code symbol is often the action that the function performs, or the data type that the function returns. If the code symbol names are listed alphabetically, this scheme results in a listing that groups related code symbols together.

If the rightmost token of a code symbol is all uppercase, then that code symbol is a macro.

If the rightmost token of a code symbol is not all uppercase, then that code symbol is either a function or a method.

Consider mpiAxisConfigGet(...) and mpiAxisConfigSet(...), which are 2 methods used to configure an Axis. Because these functions are methods, the first argument to them is an Axis handle. The second argument is a pointer to a structure of type MPIAxisConfig{}. The last token of the method name indicates the action to take; Get fills the supplied structure with Axis configuration and Set configures the Axis from the supplied structure.

The mpiAxisControl(...) method returns the MPIControl handle with which the Axis was created, while meiElementNEXT(...) is a macro that returns the MEIElement following the specified Element.

Introduction | Motion Concepts | General Definitions | Naming Conventions | Object Descriptions


Object Descriptions

Control Objects | Axis Objects | Motion Objects | Motor Objects | Filter Objects
Event Objects | Notify Objects | EventMgr Objects | Recorder Objects
Sequence Objects | Command Objects | Adc Objects | Coordinate Systems

Control Objects

Think of a Control object as a “Controller” object, which is typically a single circuit board residing in a PC or an embedded system. A Control object manages that motion controller board.

Every application creates a single Control object per board (XMP controller).

A Control object can read and write device memory using I/O port, memory-mapped or device driver methods. All communication with motion controller firmware is handled by a Control object.

For the case where the application and the motion controller device exist on two physically separate platforms connected by a LAN or serial line, the application creates a client Control object which communicates via remote procedure calls with a server.

Objects that are created with a single Control

Object | Relationship to a Controller
Adc | many-to-one, must reside on that controller
Axis | many-to-one
Filter | one-to-one or many-to-one
Motion | many-to-one or many-to-many
Motor | many-to-one
Recorder | one-to-one
Sequence | many-to-one

Axis Objects

An Axis object is associated with a single physical axis on a motion controller, and corresponds to a geometric axis used for calculation of a path of motion. An Axis may be controlled by one or more Motion objects.

The concept of an Axis is a “geometric” idea, but the main purpose of an Axis object is to generate the desired path (trajectory calculations, i.e., to generate command positions) on every sample, using the path-planning data provided by a Motion Supervisor. An Axis object is mostly a computational block.

The Filter and Motor objects ensure that the command path (calculated by Axis) is followed, and that the signals get to the right motors.
Axis Objects Are Mapped to Filters and Motors

Motion Objects

Think of a Motion object as really a “Motion Supervisor” object.

The Motion (Supervisor) object corresponds to a coordinate system or collection of axes. The primary function of the Motion Supervisor is to provide data in a synchronized manner to the Axis objects for use in path creation.

A second important function of the Motion Supervisor is to monitor the status of all of the Axes under its control (and all of the Motors, and Filters associated with these Axes), so that motion can be stopped or resumed in a controlled manner, especially in the event of errors. The Motion Supervisor is the primary interface for a your MPI application with respect to motion. A Motion object maintains an ordered list of Axis objects, which specify the coordinate system for all motions to be performed with that Motion object. When a motion is started, the type of motion is specified (trapezoidal, S-curve, parabolic, etc.) along with type-specific motion parameters. A Motion can be started directly (by calling a Motion method), or started when the Motion is associated with a Command that is called by a Sequence (that is executing). An Axis object may be controlled by more than one Motion object, but only one of those Motion objects may be active at a time.

Motor Objects

The Motor object corresponds to a physical motor used to create motion. The primary function of the Motor object is simply to provide an interface to the physical hardware associated with the physical motor. The Motor object could practically be called the “I/O” object (only the User I/O is handled outside of the Motor object). Essentially, the Motor object is the controller’s interface to the outside world.

The data of the Motor object contains the state of encoders, limit switches, home sensors, amplifier control and status signals (amplifier enable, fault, step and direction), and general purpose digital and analog I/O. Secondary functions of the motor object include commutation control, limit checking, and position capture and compare control.

To perform sinusoidal commutation, the Motor takes the outputs from the Filter object. The Motor object also implements scale interpolation.

Filter Objects

The Filter object is concerned with the controller’s control loop, i.e., what should the controlled output be (usually an input to a Dac) based on the position error? The Filter is primarily a computational block, taking command positions and actual positions and computing errors.

The Filter object calculates the output (usually the D/A output level) that controlls a physical motor or motors, using data (command positions) calculated by the Axis object. PID, PIV and Biquad filter calculations are all parts of the Filter object.

Event Objects

An Event object contains information about an asynchronous event that has occurred. You typically obtain an Event object from the EventMgr object.

Notify Objects

A Notify object is used by a thread to wait for event notification.You can configure a Notify object to wait and look for specific events and for specific event sources.

Event Manager (EventMgr) Objects

An EventMgr:

  • obtains asynchronous events from the Control object(s) that the EventMgr is associated with
  • generates Event objects for enabled event sources
  • awakens any threads that are waiting for events

Recorder Objects

You typically use the Recorder object to periodically record motion data. Note that you can only have one Recorder object per Control object (controller).

Sequence Objects

A motion application can issue individual motion commands, or can create a series of motion commands (that are executed in sequence by the controller). Essentially, you can use the Sequence object to download commands that are executed by the XMP controller, and not executed by the host.

Using the MPI, you can create a sequence of commands (a Sequence object), using high-level motion (e.g., trapezoidal motion profile on axes 2 & 4), using low level work (e.g., write 0x00043433 into memory address 0x2000).

A typical Sequence might be:
    1. Start a motion
    2. Wait 60 msec
    3. Turn on a specific I/O bit
    4. Wait for motion to finish
    5. Wait for another I/O bit
    6. Start a new motion
A Sequence object is always executed starting with the first command. After completing the first command, subsequent commands can initiate a new motion, set values in firmware memory, execute a delay for a specified period, branch to a different command in the sequence, wait for a condition to be met, and so on.

Command Objects

A Command object specifies a single action that is executed by a Sequence, such as motion, conditional branch, computation, time delay, wait for condition, etc. Any Command object that specifies motion must have a Motion object associated with it.

Adc Objects

Adc objects manage the A/D converters on a controller (Control). Typically the A/Ds can be programmed to perform conversions on different channels. On every timer interrupt, the A/D performs a single conversion, which takes 12 microseconds to complete.

A 16-Axis XMP controller has 8 A/D channels available for your application’s use. Each Adc can be correlated to a Motor object.
Note: For the XMP, no more than 2 Adc objects can be associated with a single Motor.

Coordinate Systems

To create a coordinate system for a motion application, you simply associate a list of Axis objects with a Motion object. The list of Axis objects and the order of those Axis objects on the list essentially define the coordinate system.
Introduction | Motion Concepts | General Definitions | Naming Conventions | Object Descriptions

Return to MPI Software Concepts


Configuration Methods

Introduction | mpiObjectConfig{}
                      Structure | mpiObjectConfigGet(...)
                      / mpiObjectConfigSet(...) mpiObjectFlashConfigGet(...)
                      / mpiObjectFlashConfigSet(...)

Introduction

An object’s configuration is static information that may be read and written, and an object retains its configuration until an application changes it. To configure an MPI object, you use a Config structure that is specific to each object.

To configure an MPI object, get the current Config from the motion controller by calling the ConfigGet method. Modify the Config structure as desired, and then send it back to the motion controller by calling the ConfigSet method.

If a motion controller has flash memory, you can configure that flash memory using the same Config structure. The MPI implementation handles all of the details for flash memory support; all your application needs is a handle to a flash memory object. If a motion controller does not have flash memory, the flash configuration methods will return MPIMessageUNSUPPORTED.

MPIObjectConfig{} Structure

An object’s configuration structure contains all of the configurable items for that object. To configure an object, your application must declare a variable of type MPIObjectConfig{}. Note that some Config structures are very large, so if you declare a Config structure on a small stack, your application might encounter problems. A pointer to a Config structure is passed to the Config methods.

The MPI Config structures should be able to support generic object configurations for a variety of motion controllers. However, the MPI also provides you with a way to perform configuration unique to a particular motion controller. In addition to the MPIObjectConfig{} structure, MPI Config methods can also use an external configuration structure that is defined by the implementation.
For XMP only The external configuration structures are of type MEIObjectConfig{}.
Example The MEIAxisConfig{} structure contains XMP-specific configuration parameters that extend the configuration available in MPIAxisConfig{}.

Configuration Methods
Root | Method | .
ConfigGet | mpiObjectConfigGet(...) | Fill configuration structures with current motion controller configuration
ConfigSet | mpiObjectConfigSet(...) | Change current motion controller configuration
FlashConfigGet FlashConfigSet | mpiObjectFlashConfigGet(...) mpiObjectFlashConfigSet(...) | Fill configuration structures with current motion controller Flash configuration Change current motion controller Flash configuration

mpiObjectConfigGet(...) / mpiObjectConfigSet(...)

The mpiObjectConfig( ) structure is meant to illustrate how objects are configured. Please swap the object you are interested in for the the object to configure. For example, mpiObjectConfigSet( ) shows the naming convention that mpiAxisConfigGet( ) follows.Both ConfigGet and ConfigSet take three arguments:
    • the first argument is the object handle (MPIObject)
    • the second argument is a pointer to an MPIObjectConfig{} structure (MPIObjectConfig *)
    • the third argument is a pointer to an external implementation-defined configuration structure (void *).The third argument may also be NULL
For XMP only The external argument is a pointer to an XMP-specific configuration structure of type MEIObjectConfig{}.

Use the Get method to fill the configuration structures with the current motion controller configuration for the object.
Use the Set method to change the current motion controller configuration for the object. (The Set method uses the configuration structures to do that.)

mpiObjectFlashConfigGet(...) / mpiObjectFlashConfigSet(...)

The FlashConfigGet and FlashConfigSet methods take four arguments:

    • The first argument is the object handle (MPIObject)
    • The second argument is an implementation-specific handle to Flash memory (void *).
    • The second argument can also be NULL.
    • The third argument is a pointer to an MPIObjectConfig{} structure (MPIObjectConfig *)
    • The fourth argument is a pointer to an external implementation-defined configuration structure (void *). The fourth argument can also be NULL.
For XMP only The flash handle is of type MEIFlash (second argument); the external argument (fourth argument) is a pointer to a configuration structure of type MEIObjectConfig{}.

Use the Get method to fill the configuration structures with the current motion controller Flash configuration for the object.
Use the Set method to change the current motion controller Flash configuration for the object. (The Set method uses the configuration structures to do that.)

The flash configuration is in effect after system start-up and also after resetting the motion controller (by calling the mpiControlReset(...) method).
Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Event Notification Methods

Introduction | mpiObjectEventNotifyGet(...)
                      | mpiObjectEventNotifySet(...)
mpiObjectEventNotifyReset(...) | Notification
                      Process

Introduction

The MPI EventMgr is responsible for the collection and distribution of host notifications of firmware events. An application often needs to be notified of events that take place on the motion controller. Events include normal motion completion, motion limits being reached, hardware failure, etc. The EventNotify methods enable your application to request host notification of certain types of events, while ignoring other types of events. Some events are latched, in which case your application must reset the event before the event can be triggered again.

Method | Description
mpiObjectEventNotifyGet(...) | Get event mask used for host notification
mpiObjectEventNotifySet(...) | Set event mask to request host notification of events
mpiObjectEventNotifyReset(...) | Reset event notification

mpiObjectEventNotifyGet(...)

Use EventNotifyGet to return an MPIEventMask, which has a bit set for each type of event that host notification has been requested for, by the object.

mpiObjectEventNotifySet(...)

Use EventNotifySet to request host notification for each type of event specified in the MPIEventMask argument.

mpiObjectEventNotifyReset(...)

Use EventNotifyReset to reset each type of event specified in the MPIEventMask argument.

Notification Process

Events [that are requested by mpiObjectEventNotifySet(...)] move up through the firmware to the EventMgr.
To collect events, the EventMgr either polls the firmware (using mpiEventMgrService(...)) or is interrupted by the firmware. The EventMgr passes each event to its list of Notify objects, who further qualify events based on the event type and the source of the event, and generate signals and otherwise notify the host application of event occurrences.
Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Identity Methods

Identity methods are used to identify an object, by providing the value of each of the arguments passed to the Create method to create that object. An identity method exists for each Create method argument, and typically is named by that argument.

Identity methods generally have a second output argument that is a pointer to the Create method argument to be returned; the return value of the method will indicate success or failure (as usual). However, identity methods that return an object handle do so directly rather than using an output argument.

Example

The mpiAxisCreate(...) method takes 2 arguments; an MPIControl handle and an axis number. Therefore, the Axis module declares 2 identity methods: mpiAxisControl(...) and mpiAxisNumber(...).

The mpiAxisControl(...) method returns the MPIControl handle with which the axis object was created. The mpiAxisNumber(...) method returns a value that indicates success or failure; if the value indicates success, the second argument points to a location that will be set to the axis number.

Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |

Return to MPI Software Concepts


List Methods

Introduction | List | Element | Array Methods
List Expansion Methods | List Contraction Methods | List Traversal Methods

Introduction

Several MPI objects maintain a list whose elements are other MPI objects.

Example A Motion object maintains a list of Axis objects.
An EventMgr object maintains 2 lists: a list of Control objects and a list of Notify objects.

The MPI declares standard list manipulation methods for all such objects. The MPI does not specify how lists are to be implemented.

List

A list is an ordered sequence of elements. Generally, the elements of a list are objects of the same type, but this is not required. A list that contains no elements is empty. A list may be traversed either forwards or backwards from any element that is a member of the list. List manipulation methods are declared for the object that maintains the list.

Element

An element is a member of a list. An element is generally an object. An element is added to or removed from a list using list manipulation methods (declared by the object that maintains the list).
Grouping | List Action | Method | .
Array Methods | ListGet ListSet | . | .
List Expansion | Append Insert | . | .
List Contraction | Remove | . | .
List Traversal | Count First Index Last Next Previous | mpiListElement(...) mpiListElementCount(...) mpiListElementFirst(...) mpiListElementIndex(...) mpiListElementLast(...) mpiListElementNext(...) mpiListElementPrevious(...) | Return handle of indexth element Return number of elements in list Return handle to first element in list Return index number of element in list Return handle to last element in list Return handle to next element in list Return handle to previous element in list

Array Methods

You use Array methods to manipulate lists. Array methods use an element count and an application-resident array of elements. These methods provide a convenient way of dealing with a list as a whole. Note that if you do use array methods for list manipulation, you can also use other list manipulation methods as well.

mpiListElementListGet(MPIList list, long *count, MPIElement *Element)
The ListGet method returns the list (maintained by List) as an array of object handles of type MPIElement. Upon successful return of the ListGet method, the contents of the location pointed to by count will be set to the number of elements in the list, or set to zero (if the list is empty). Your application must also define the object handle array pointed to by Element, and the array must be large enough to hold the current number of list elements.

mpiListElementListSet(MPIList list, long count, MPIElement *Element)
The ListSet method sets the list (maintained by List) from an array of object handles of type MPIElement. Upon successful return of the ListSet method, the list will contain count elements. Your application must also define the object handle array pointed to by Element, and the array must contain at least count list elements. After using the ListSet method, any existing list will be completely replaced by the new list. To make an existing list empty, call the ListSet method with a count of 0 and Element set to NULL.

List Expansion Methods

A list can be expanded by inserting an element at any point, either as the first element of the list, after a specific list element, or as the last element of the list. Lists generally check and verify that an element to be inserted is not already a list element. Other list-specific checks may be made before insertion as well.

mpiListElementAppend(MPIList list, MEIElement Element)
The Append method appends an object (whose handle is Element) to the list maintained by List, making it the last element of the list.

mpiListElementInsert(MPIList list, MEIElement before, MEIElement insert)
The Insert method inserts an object (whose handle is insert) into the list maintained by List, placing it after the list element whose handle is before. If before is MPIHandleVOID, insert becomes the first element of the list.

List Contraction Methods

A list can be contracted (shortened) by removing a list element. Lists check and verify that the element to be removed is actually a list element.

mpiListElementRemove(MPIList list, MEIElement Element)
The Remove method removes an object (whose handle is Element) from the list maintained by List.

List Traversal Methods

To traverse a list means to be able to move through all of the elements on a list. It can also involve determining the number of list elements, searching for a particular list element, finding the index of a list element, and more.
MPIElement mpiListElement(MPIList list, long index)

Return Values

 .
handle of the indexth list element of the list maintained by List
MPIHandleVOID if index is less than zero
if index is greater-than-or-equal-to the number of list elements

mpiListElementCount(MPIList list)

Return Values

 .
number of list elements on the list maintained by List
-1
 if list is invalid

MPIElement mpiListElementFirst(MPIList list)

Return Values

 .
handle to the first list element of the list maintained by List
MPIHandleVOID
 if list is empty or is not valid
if list is not valid

mpiListElementIndex(MPIList list, MPIElement Element)

Return Values

 .
index of Element in the list maintained by List
-1
 if list is empty or not valid
if Element is not a list element of the list maintained by List

MPIElement mpiListElementLast(MPIList list)

Return Values

 .
handle to the last list element of the list maintained by List
MPIHandleVOID
 if list is empty
if list is not valid

MPIElement mpiListElementNext(MPIList list, MPIElement Element)

Return Values

 .
handle to the list element immediately after Element in the list maintained by List
MPIHandleVOID
 if list is not valid
if Element is not a list element
if Element is the last list element of the list maintained by List

MPIElement mpiListElementPrevious(MPIList list, MPIElement Element)

Return Values

 .
handle to the list element immediately before Element in the list maintained by list
MPIHandleVOID
 if list is not valid
if Element is not a list element
if Element is the first list element of the list maintained by List
Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Memory Methods

Introduction | Accessing Memory Methods | Control Object Memory Methods
mpiObjectMemory(...) | mpiObjectMemoryGet(...) / Set(...)

Introduction

You use Memory methods to access a motion controller’s RAM. The MPI imposes no structure on motion controller RAM, so the use of memory methods requires implementation-specific knowledge of the motion controller’s memory map.

The controller's memory map is version specific. If you use a hard-coded address with a memory method, it may not be compatible with other controller firmware versions. The xmp.h header file defines the controller's memory map and the interface to the MPI. It is intended for internal purposes only. The defines, structures, and ordering will change with each revision. If you use the xmp.h structures directly, be aware that your application code may require changes to be compatible with other xmp.h versions.

For MEI/XMP only The memory map is defined in the xmp.h header file. All accessible memory is defined in the MEIXmpData{} and MEIXmpBufferData{} structures.
Each object has its own memory methods; only the memory directly associated with the specific object can be accessed using that object’s Memory methods.
Example An Axis object created with axis number 0 may only access memory associated with Axis 0.

Accessing Memory Methods

Memory access via these methods is thread-safe; only one thread at a time can read or write the portion of memory associated with the object. The Get/Set methods will bounds-check the memory address to be accessed, and return an error if the address is not associated with the object.

Control Object Memory Methods

The Control object memory methods are an exception. Using the ControlMemory methods, an application may access all memory on the motion controller at any time, without constraint. The ControlMemory methods are not thread-safe. Memory methods for the other objects are generally implemented by locking the section of memory associated with the object, and then calling a ControlMemory method.

It is possible to write a motion application using only a Control object. After creating and initializing the Control object, the address of motion controller memory can be obtained, and you can use the ControlMemoryGet/Set methods to access that memory.

Depending on the type of Control object created, an application can directly access the motion controller memory without using the ControlMemoryGet/Set methods. Such an application would bypass the rest of the MPI library and must implement its own thread safety, as well as deal with how the motion controller firmware operates.
Method .
mpiObjectMemory(...)
mpiObjectMemoryGet(...)
mpiObjectMemorySet(...) 		Return host address of object in memory Read motion controller memory
Write motion controller memory

mpiObjectMemory(...)

The mpiObjectMemory(...) method returns a host address that maps to the section of motion controller memory associated with the object. mpiObjectMemory(...) uses 2 arguments: the object handle, and an output argument of type void **. If a call to mpiObjectMemory(...) succeeds, the location pointed to by the output argument is set to the host address.

mpiObjectMemoryGet(...) / mpiObjectMemorySet(...)

These methods read (get) and write (set) motion controller memory. They take 4 arguments:
    • the object handle
    • a destination address of type void *
    • a source address of type void *
    • and a length in bytes
The Get method’s destination address points to host memory, while the source address points to motion controller memory (based on the address returned by the Memory method for the object). The Set method is the opposite. The Set method’s destination address points to motion controller memory and the source address points to host memory.
Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Object Methods

Introduction | Common Methods for MPI Objects
mpiObjectCreate(...) | mpiObjectDelete(...) | mpiObjectValidate(...)

Introduction

Object-oriented languages such as C++ and Java provide capabilities such as inheritance and polymorphism. The MPI is written in the C language, and so these more exotic object-oriented features are not available. However, the basic concepts of object-oriented design are in the MPI: modularity, data hiding and no global or static data.

It’s similar to C++
If you are already familiar with C++, you will quickly realize that the MPI methods that create and delete objects are patterned after C++ constructors and destructors. An MPI method takes an object as its first argument, much as a C++ method has a “this” pointer. Object data is private and available only by calling object methods. MPI source code is organized into modules, with one object per module. Library state is distributed across application-created objects; there is virtually no state information maintained by the library.

All object methods and all functions return a value indicating whether the call to them succeeded or not. In general, the return value is of type long, with a value of 0 indicating success. The return value can be treated as an MPIMessage, so that you can call the mpiMessage(...) function to obtain a text string that describes the return value. The text string that indicates a successful return value of MPIMessageOK (0) is empty (“”).

All MPI objects must implement certain required methods. Note that most MPI objects implement standard configuration and memory methods; many MPI objects implement standard status and list manipulation methods and a few objects implement standard event notification methods. For multi-threaded environments, all objects must implement standard resource allocation timeout methods.

In general, there are few methods that are unique to an object, and those unique methods tend to be those that perform object-specific actions. The following sections describe the standard methods that are implemented by many objects. For specific details about objects and their methods/functions, refer to the breakdown of Objects.

Where used in the rest of this section, the word Object may be replaced with the name of an MPI object in order to obtain the name of the methods for that object.
Example

For the term mpiObjectCreate(...), replace Object with Axis to obtain the name of the method that you would use to create Axis objects, mpiAxisCreate(...).

For the term MPIObject, replace Object with Axis to obtain the data type of the Axis handle (MPIAxis) returned by the Axis method mpiAxisCreate(...), and also used by other Axis methods, such as mpiAxisValidate(...).

Common Methods for MPI Objects

All MPI objects have four types of common methods:

    • methods which create an object
    • methods which delete an object
    • methods which validate an object
    • methods which identify an object

mpiObjectCreate(...)

Use the Create method to create an object and return a handle that uniquely identifies that object. The MPI does not support declaring an object directly, so you must always use the Create method. The Create method is the only method that does not take an object handle as its first argument. The Create method arguments depend on the type of object being created.

If an object cannot be created, the value of the handle returned is MPIHandleVOID, which typically indicates only that no memory is available to hold the object. If memory is available to create the object, but the Create method encounters an error, then the Create method returns a handle, but the object referenced by the handle is not valid. A call to the mpiObjectValidate(...) method returns a value that indicates whether an object is valid, and if it is not valid, why. In general, if you call a method using an object handle that is invalid, the method will fail and return a value indicating the cause of failure.

The MPI supports multiple motion controllers. Typically, an MPI application first creates a Control object that corresponds to the desired motion controller. If the application will use more than one motion controller, it must create a Control object for each motion controller. The arguments to mpiControlCreate(...) associate a Control object with a specific motion controller.

A motion controller provides various types of resources, such as axis, digital-to-analog converter, data recorder, etc. Many of a motion controller’s resource types have multiple instances. For example, motion controllers provide multiple axes and DACs.

Most MPI objects are associated with a specific instance of a resource on a specific motion controller. An Axis object, for example, is associated with a single axis on a motion controller. When creating an MPI object that corresponds to a specific motion controller resource, the Create method takes an MPIControl handle as its first argument and a number as the second argument. The number argument identifies the specific motion controller resource to be used.

Example

The number argument of mpiAxisCreate(...) identifies an axis on the motion controller specified by the MPIControl handle argument.

For XMP only Number arguments, for those MPI objects that take them, start with 0 (not 1). For example, on an 8-axis XMP motion controller, valid axis numbers are 0 - 7.
Some MPI objects maintain a list whose elements are other MPI objects. The Create method for a list object generally takes a third argument that is a handle to an element object. The element object then becomes the first element of the list maintained by the list object. Specifying an element object is optional; if the handle (third argument) has value MPIHandleVOID, the list object will be created with an empty list.
Example The Motion object maintains an ordered list of Axis objects. This ordered list of Axis objects defines a motion coordinate system. The third argument to mpiMotionCreate(...) is an Axis handle (MPIAxis). If the Axis handle is valid, then the Axis object (that the handle points to) will be made the first axis in the motion coordinate system.
All MPI objects provide a method to return the value of each of its Create method arguments. These methods serve to identify the object. For more detail, see Identity Methods on page 1-47.

mpiObjectDelete(...)

Use the Delete method to delete an object created by the Create method. After an object has been deleted, the handle to that object can no longer be used.

If a method attempts to use a handle to a deleted object, it returns MPIMessageObject_FREED, but not always. If the memory originally allocated for the deleted object is subsequently allocated for a different purpose, then the method will not return MPIMessageObject_FREED.

Your application must ensure that handles to deleted objects are no longer used. After an object is deleted, your application should ensure that the handle to that object is set to MPIHandleVOID. After that, any calls to methods using this handle will return MPIMessageHANDLE_INVALID.

When your application exits, it should call Delete methods for all objects that have been created by your application. We recommend that your application delete objects in the reverse order in which they were created. Regardless, the Control object should be the last object deleted. The MPI does not provide the ability to automatically delete all of the objects that have been created.

Alternatively, to delete objects, your application may use the C library function atexit(...), which guarantees that the objects will be deleted even if the application terminates abnormally.

mpiObjectValidate(...)

Use the Validate method to “validate” an object created by the Create method. Your application should always call the Validate method immediately after calling the Create method. Afterwards, the Validate method can additionally be called at any time in an application.

If the object is valid, the Validate method will return MPIMessageOK. If the handle passed to the Validate method has value MPIHandleVOID, the Validate method returns MPIMessageHANDLE_INVALID. If a method attempts to use a handle to a deleted object, the method returns MPIMessageObject_FREED. (Also see the previous discussion in mpiObjectDelete(...)).

Other possible return values are declared in the message header file(MPI\include\message.h) and in the object’s header file (MPI\include\object.h).
Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Status Methods

Introduction | MPIStatus{...} Structure | MPIObjectStatus{...} Structure

Introduction

Status is read-only information that changes dynamically. Many objects define a Status structure and a method that uses that structure to return status to the application.

MPIStatus{...} Structure

The MPIStatus{...} structure contains information about the state of an axis or an entire motion. The Axis object and the Motion object return status using the MPIStatus{...} structure. Because the MPIStatus{...} structure is shared among objects, it is defined in the mpidef.h header file instead of being defined in an object header file.

For objects that involve more than 1 axis, the status returned by the motion object indicates the “sum” of the status conditions of the axes in its coordinate system. In general, the status structure gives an indication of whether an axis is moving or idle. The axis structure also indicates whether the axis is idle because of an error.

For MEI/XMP only The filter object (whose handle is of type MEIFilter) also returns status in MPIStatus{...}.

MPIObjectStatus{...} Structure

Objects that are not Axis and Motion objects return status using an object-specific Status structure defined in the object’s header file.

mpiObjectStatus(...)
For Axis and Motion objects, mpiObjectStatus(...) returns the object’s status using the object’s handle and a pointer to an MPIStatus{...} structure. For objects that are not Axis or Motion objects, mpiObjectStatus(...) returns the object’s status using the object’s handle and a pointer to an MPIObjectStatus{...} structure.

Object Methods | Configuration Methods | Memory Methods | Status Methods
| Event Notification Methods | List Methods | Identity Methods |


Upgrading Software to SynqNet Phase II

.

The introduction of SynqNet Phase II has necessitated changes to motor I/O and capture interfaces in the MPI library. Since the number of available motor I/O pinouts vary from node to node, different structures must be used to enumerate I/O signal access through the MPI. Some of the changes necessary to switch from old versions of the MPI (Analog and SynqNet Phase I) to SynqNet Phase II MPI are listed below.
Additional Include File and Directory
Motor I/O Enumeration Changes
Changes to the MEIMotorConfig Structure
MEIMotorConfig Parameter Changes
New Capture Engine Features
Capture Enumeration Changes
Changes to the MPICaptureConfig structure
MPICaptureConfig Parameter Changes
Creating MPICapture Objects
Capture Engine Diagrams


Additional Include File and Directory

.

Additional Include File and Directory

To access the node-specific enumerations, the file "sqNodeLib.h" must be #included in application code. This requires the addition of the directory, "\xmp\sqNodeLib\include" to the list of additional include directories in the Project->Settings C/C++ tab.

If only general MPI enumerations are used, then there is no need to #include "sqNodeLib.h" in an application.


Motor I/O Enumeration Changes

.

Motor I/O Enumeration Changes

With old versions of the MPI, all digital inputs were included into one enumeration, MEIMotorInput, while all digital outputs were included in another, MEIMotorOutput.

With SynqNet Phase II, digital I/O has been split up into 3 categories:

  • Dedicated Inputs - represented by MEIMotorDedicatedIn, refers to common inputs such as the home line.

  • Dedicated Outputs - represented by MEIMotorDedicatedOut, refers to common outputs such as the brake enable line.

  • Configurable and/or Node - Specific I/O, represented by MEIMotorIoMask. Presently, these only support digital inputs or outputs. In the future, support for stepper motor output and compares will be supported by these I/O.
When upgrading application code to SynqNet Phase II, check the drive manufacturer's configuration type and documentation for details about which configurable I/O are supported. If the enumerations are replaced without verifying a drive's capabilities, an application will compile, but it may not work.

The tables below shows how to upgrade motor I/O enumerations to SynqNet Phase II.

Analog & SynqNet Phase I MPI | SynqNet Phase II MPI
MEIMotorInputAMP_FAULT | MEIMotorDedicatedInAMP_FAULT
MEIMotorInputHOME | MEIMotorDedicatedInHOME
MEIMotorInputOVERTRAVEL_POS | MEIMotorDedicatedInLIMIT_HW_POS
MEIMotorInputOVERTRAVEL_NEG | MEIMotorDedicatedInLIMIT_HW_NEG
MEIMotorInputINDEX | MEIMotorDedicatedInINDEX
MEIMotorInputBROKEN_WIRE | MEIMotorDedicatedInFEEDBACK_FAULT
MEIMotorInputILLEGAL_STATE
(No equivalent enumeration) | MEIMotorDedicatedInBRAKE_APPLIED
(No equivalent enumeration) | MEIMotorDedicatedInDRIVE_STATUS_0
(No equivalent enumeration) | MEIMotorDedicatedInDRIVE_STATUS_1
(No equivalent enumeration) | MEIMotorDedicatedInDRIVE_STATUS_2
MEIMotorInputSIM4_INDEX | (No equivalent enumeration) Sinusoidal Interpolation Not Supported
MEIMotorInputSIM4_ENCA
MEIMotorInputSIM4_ENCB
(No equivalent enumeration) | MEIMotorDedicatedOutAMP_ENABLE
MEIMotorOutputBRAKE_ENABLE | MEIMotorDedicatedOutBRAKE_RELEASE

Analog & SynqNet Phase I MPI | RMB Specific Values † | Equivalent General MPI Values
MEIMotorTransceiverConfigINPUT | (none - use generic MPI value –> ) | MEIMotorIoTypeINPUT
MEIMotorTransceiverConfigOUTPUT | (none - use generic MPI value –> ) | MEIMotorIoTypeOUTPUT
MEIMotorTransceiverConfigSTEP | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigDIR | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigCW | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigCCW | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigQUAD_A | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigQUAD_B | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverConfigCOMPARE | (No equivalent enum -- Step Engine Not Yet Implemented)
MEIMotorTransceiverIdA | RMBMotorIoConfigXCVR_A | MEIMotorIoConfigIndex0
MEIMotorTransceiverIdB | RMBMotorIoConfigXCVR_B | MEIMotorIoConfigIndex1
MEIMotorTransceiverIdC | RMBMotorIoConfigXCVR_C | MEIMotorIoConfigIndex2
MEIMotorTransceiverExtendedIdD | RMBMotorIoConfigXCVR_D | MEIMotorIoConfigIndex3
MEIMotorTransceiverExtendedIdE | RMBMotorIoConfigXCVR_E | MEIMotorIoConfigIndex4
MEIMotorTransceiverExtendedIdF | RMBMotorIoConfigXCVR_F | MEIMotorIoConfigIndex5
(No equivalent enumeration) | RMBMotorIoConfigUSER_0_IN | MEIMotorIoConfigIndex6
(No equivalent enumeration) | RMBMotorIoConfigUSER_0_OUT | MEIMotorIoConfigIndex7
MEIMotorInputXCVR_A | RMBMotorXcvrA | MEIMotorIoMask0
MEIMotorInputXCVR_B | RMBMotorXcvrB | MEIMotorIoMask1
MEIMotorInputXCVR_C | RMBMotorXcvrC | MEIMotorIoMask2
MEIMotorInputUSER | RMBMotorOptoUSER0_IN | MEIMotorIoMask6
MEIMotorInputUSER_0 | RMBMotorOptoUSER0_OUT | MEIMotorIoMask6
MEIMotorInputUSER_1 | (Not Supported by RMB) | (Vendor Specific)
MEIMotorOutputXCVR_A | RMBMotorXcvrA | MEIMotorIoMask0
MEIMotorOutputXCVR_B | RMBMotorXcvrB | MEIMotorIoMask1
MEIMotorOutputXCVR_C | RMBMotorXcvrC | MEIMotorIoMask2
MEIXmpMotorIOMaskXCVR_D | RMBMotorXcvrD | MEIMotorIoMask3
MEIXmpMotorIOMaskXCVR_E | RMBMotorXcvrE | MEIMotorIoMask4
MEIXmpMotorIOMaskXCVR_F | RMBMotorXcvrF | MEIMotorIoMask5
MEIMotorOutputUSER | RMBMotorOptoUSER0_OUT | MEIMotorIoMask7
MEIMotorOutputUSER_0 | RMBMotorOptoUSER0_OUT | MEIMotorIoMask7
MEIMotorOutputUSER_1 | (Not Supported by RMB) | (Vendor Specific)
† - RMB Specific Values are for only MEI RMB-10V Nodes


Changes to the MEIMotorConfig Structure

.

Changes to the MEIMotorConfig structure

Analog (20020117.1.6)

typedef struct MEIMotorConfig {
  ...
    MEIMotorTransceiver   Transceiver[MEIXmpMotorTransceivers];
    MEIMotorTransceiver   TransceiverExtended[MEIXmpMotorTransceiversExtended];
    long                  UserOutInvert;   /* Output Polarity */
  ...
} MEIMotorConfig;

typedef struct MEIMotorTransceiver {
    long                       Invert;  /* TRUE = invert (not valid for INPUT) */
    MEIMotorTransceiverConfig  Config;
} MEIMotorTransceiver;

SynqNet Phase I (20011220.1.16)

typedef struct MEIMotorConfig {
  ...
    MEIMotorTransceiver Transceiver[MEIXmpMotorTransceivers];
    MEIMotorTransceiver TransceiverExtended[MEIXmpMotorTransceiversExtended];
    long                UserOutInvert[MEIXmpMotorUserOptos]; /* Output Polarity */
  ...
} MEIMotorConfig;

typedef struct MEIMotorTransceiver {
    long                        Invert;  /* TRUE = invert (not valid for INPUT) */
    MEIMotorTransceiverConfig   Config;
} MEIMotorTransceiver;

SynqNet Phase II (20021014)

typedef struct MEIMotorConfig {
  ...
    MEIMotorIoConfig    Io[MEIMotorIoConfigIndexLAST];
  ...
} MEIMotorConfig;

typedef struct MEIMotorIoConfig {
    MEIMotorIoType    Type;
    long              Invert;  /* TRUE = invert (not valid for INPUT) */
    long              AbortValue;
} MEIMotorIoConfig;


MEIMotorConfig Parameter Changes

.

MEIMotorConfig Parameter Changes

The table below shows how to upgrade motor I/O configuration code to SynqNet Phase II.

Analog & SynqNet Phase I MPI |  | SynqNet Phase II MPI
Type | Parameter | Type | Parameter
 | (unpowered default values) | long | MEIMotorConfig.Io[].AbortValue
long | MEIMotorConfig.Transceiver[].Invert | long | MEIMotorConfig.Io[].Invert
MEIMotorTransceiverConfig | MEIMotorConfig.Transceiver[].Config | MEIMotorIoType | MEIMotorConfig.Io[].Type
long | MEIMotorConfig.TransceiverExtended[].Invert | long | MEIMotorConfig.Io[].Invert
MEIMotorTransceiverConfig | MEIMotorConfig.TransceiverExtended[].Config | MEIMotorIoType | MEIMotorConfig.Io[].Type
long | MEIMotorConfig.UserOutInvert (analog) | long | MEIMotorConfig.Io[RMBMotorIoConfigUSER_0_OUT].Invert
long | MEIMotorConfig.UserOutInvert[0] (phase I) | long | MEIMotorConfig.Io[RMBMotorIoConfigUSER_0_OUT].Invert
(all parameters) | MEIMotorConfig.Stepper.Xxx | (No equivalent enum -- Step Engine Not Yet Implemented)
long | MEIMotorConfig.pulseEnable | (No equivalent enum -- Compare Engine Not Yet Implemented)
long | MEIMotorConfig.pulseWidth | (No equivalent enum - Step & Compare Engines Not Yet Implemented)


New Capture Engine Features

.

New Capture Engine Features

The next few sections on captures explain how to update code for the old capture engine to code for the new capture engine.

The new capture engine includes additional support for "global" capturing (capturing the positions of multiple encoders from a single trigger). Global capturing is only global to a single SynqNet node. The reason for this is because position capturing is supposed to be a high-speed process, on the order of tens of nanoseconds. Communicating information across the SynqNet network would seriously degrade the timing of the capture engine.

The way the global capturing works is that an internal "global" bit is kept inside a node's FPGA. This bit is considered as one of the inputs into a capture's engine. Each capture also has the ability to link this bit to its trigger state. (Please see the Capture Engine Diagrams.) At any given time, only one capture may link to the global bit. One should not configure a capture to use the global bit as an input and then link to the global bit with the same capture.

In SynqNet Phase II MPI, instead of a trigger mask for capture, there is now an array of trigger sources, each with an enable and invert option. The following few sections will explain how this array functions.

The new capture engine supported by SynqNet Phase II MPI, also supports capturing on different edges of the trigger state. (Please see the Capture Engine Diagrams.) Capturing can now happen on the rising edge, the falling edge, or any transition of the trigger state. This is specified by the edge member of the MPICaptureConfig structure:

MPICaptureEdgeRISING | Capture on the rising edge of the trigger state
MPICaptureEdgeFALLING | Capture on the falling edge of the trigger state
MPICaptureEdgeEITHER | Capture on an transition of the trigger state
MPICaptureEdgeNONE | Never Capture


Capture Enumeration Changes

.

Capture Enumeration Changes

The table below shows how to upgrade capture enumerations to SynqNet Phase II.

Analog & SynqNet Phase I MPI | SynqNet Phase II MPI
MPIIoType | (Enumeration no longer necessary)
MEIMotorInputHOME | MPICaptureSourceHOME
MEIMotorInputOVERTRAVEL_POS | MPICaptureSourceOVERTRAVEL_POS
MEIMotorInputOVERTRAVEL_NEG | MPICaptureSourceOVERTRAVEL_NEG
MEIMotorInputINDEX | MPICaptureSourceINDEX
MEIMotorInputXCVR_A | MPICaptureSourceMOTOR_IO_0 (MEI RMB Only)
MEIMotorInputXCVR_B | MPICaptureSourceMOTOR_IO_1 (MEI RMB Only)
MEIMotorInputXCVR_C | MPICaptureSourceMOTOR_IO_2 (MEI RMB Only)
(No equivalent enumeration) | MPICaptureSourceGLOBAL
(No equivalent enumeration) Configured through MPIMotorConfig.captureOnChange | MPICaptureEdge See MPICaptureConfig Parameter Changes section.


Changes to the MEICaptureConfig structure

.

Changes to the MEICaptureConfig structure

Analog / SynqNet Phase I (20020117.1.6 / 20011220.1.16)

typedef struct MPICaptureConfig {
    MPIIoTrigger    trigger;
    long            latchCount;
  ...
} MPICaptureConfig;

/* MPIIoTrigger */
typedef struct MPIIoTrigger {
  ...
    unsigned long     mask;
    unsigned long     pattern;
} MPIIoTrigger;

SynqNet Phase II (20021014)

typedef struct MPICaptureConfig {
    MPICaptureTrigger          source[MPICaptureSourceCOUNT];
    MPICaptureEdge             edge;
    MPICaptureTriggerGlobal    global;
} MPICaptureConfig;

typedef struct MPICaptureTrigger {
    long enabled;   /* TRUE/FALSE */
    long invert;    /* TRUE = invert, FALSE = normal */
} MPICaptureTrigger;

typedef struct MPICaptureTriggerGlobal {
    long enabled;   /* TRUE/FALSE */
} MPICaptureTriggerGlobal;


MPICaptureConfig Parameter Changes

.

MPICaptureConfig Parameter Changes

The table below shows how to upgrade capture configuration code to SynqNet Phase II.

Trigger when input is: | Analog / SynqNet Phase I |  | SynqNet Phase II
 | trigger.mask | trigger.pattern | source[sourceBit].enabled | source[sourceBit].invert
High | Include† MPIMotorInput bit | Include† MPIMotorInput bit | TRUE | FALSE
Low | Include† MPIMotorInput bit | Exclude†† MPIMotorInput bit | TRUE | TRUE
Don't use as a trigger | Exclude MPIMotorInput bit | Exclude MPIMotorInput bit | FALSE | (n/a)
Use Global Trigger Flag for Capture | (n/a) |  | source[MPICaptureSourceGLOBAL].enabled = TRUE
 |  |  | source[MPICaptureSourceGLOBAL].invert = FALSE
Set Global Trigger FlagOn Capture | (n/a) |  | MPICaptureConfig.global = TRUE
 | † - The bit associated with this motor input should be on †† - The bit associated with this motor input should be off


Creating MPICapture Objects

.

Creating MPICapture Objects

The way MPICapture Objects are created has also changed. MPICapture objects are now associated with encoders. Before SynqNet, each capture could easily be enumerated across the entire controller, and thus MPICapture objects were created using an MPIControl handle. But with SynqNet, different drives can support different numbers of encoders, so this enumeration is now impossible. In SynqNet Phase II, MPICapture objects are now created using an MPIMotor handle. SynqNet Phase I had two different ways to access capture objects, one of which was identical to the analog MPI and the second was specific to SynqNet Phase I. The table below lists some of the differences between the ways capture objects are created or accessed.

MPI Version | Method for Creating/Accessing Capture Objects | Handle Type Used to Create Capture Objects | Capture Objects Need Deletion?
Analog | mpiCaptureCreate | MPIControl | Yes
SynqNet Phase I | mpiCaptureCreate | MPIControl | Yes
SynqNet Phase I | meiMotorCapture | MPIMotor | No†
SynqNet Phase II | mpiCaptureCreate | MPIMotor | Yes
† - These capture objects were created and deleted by the motor object.

The function prototypes for creating or accessing capture objects is listed below:

Analog / SynqNet Phase I
const MPICapture mpiCaptureCreate(MPIControl  control,
                                  long        number);

const MPICapture meiMotorCapture(MPIMotor  motor,
                                 long      index);
SynqNet Phase II
const MPICapture mpiCaptureCreate(MPIMotor         motor,
                                  MPIMotorEncoder  encoder,
                                  long             number);

The encoder argument identifies which encoder to create a capture for.

The number argument tells which capture to use on a particular encoder. Number represents the index of a zero-indexed array of captures, similar to the number argument for other mpiCreate… methods.

The function prototype for the for the mpiCaptureDelete() method has not changed.


Capture Engine Diagrams

.

Capture Engine Diagrams

Analog / SynqNet Phase I
Capture Engine

SynqNet Phase II
Capture Engine

 Back to Table of Contents


Axis Tolerances and How Motion Related Events are Generated

.

Axis Tolerances and How Motion Related Events are Generated

There are five types of generated events related to motion: MOTION_DONE, MOTION_AT_VELOCITY, and IN_COARSE_POSITION, AT_TARGET, and SETTLED. Motion completion for a position move is indicated by a MOTION_DONE event, while motion completion for a velocity move is indicated by an MOTION_AT_VELOCITY event.

For both position moves and velocity moves, the MPI uses a settling time window to determine when to generate a motion completed event (to indicate that motion has finished on an axis).

For position moves, the MPI uses the settling time window to determine when an axis has reached the final target location and is stable.

For velocity moves, the MPI uses the settling time window to determine when an axis has reached the final velocity. This works because during ringing, the velocity is highest when the position error is lowest. (Velocity and position error are inversely-related.)

Position and Velocity criteria for generating motion completion events
For a | A "motion completed" event is generated when | Criteria
Position move | ABS(position error) < MPIAxisConfig.inPosition.tolerance.positionFine | position
Position move | ABS(velocity error) < MPIAxisConfig.inPosition.tolerance.velocity | velocity
Velocity move | ABS(velocity error) < MPIAxisConfig.inPosition.tolerance.velocity | velocity

where: |
 | position error = (command position – actual position)
 | velocity error = (command velocity – actual velocity)

For Position Moves
A MOTION_DONE event is generated after a position move only after both the position and velocity criteria have been met for the period specified by the settling time. To determine if motion has completed, position moves use both position and velocity criteria.

The default (factory) value for inPosition.tolerance.velocity is 20,000,000 counts/sec. We included the ability to additionally use the velocity criteria for position moves because some users prefer to decide that an axis is “settled” only after the position error and actual velocity are both low enough.

For Velocity Moves
An MOTION_AT_VELOCITY event is generated for a velocity move only after the velocity criteria has been met for the period specified by the settling time. To determine if motion has completed, velocity moves use only the velocity criteria (they don’t use the position criteria).

Note that the motion completed event generated this time is an MOTION_AT_VELOCITY event rather than a MOTION_DONE event. For velocity moves, MOTION_DONE events will only occur after mpiMotionAction(..., MPIActionSTOP) calls.

You can also use the velocity criteria to determine when ringing has stopped after an open loop commutation move. To do this, the position criteria is effectively disabled by setting the position tolerance to a very large value (e.g., 1.0E10). After that, the MOTION_DONE event following a move is determined entirely by the velocity tolerance and settling time, and, therefore, the event will be generated only after the ringing has stopped.

Be aware that setting MPIAxisConfig.inPosition.tolerance.velocity to 0 does not disable the velocity criteria. For interpolated scales, setting MPIAxisConfig.inPosition.tolerance.velocity to 0 makes it very difficult to meet the criteria of 0 counts of motion for settlingTime seconds.

Settling Time Parameters

Four Settling Time Parameters

For position moves, the generation of DONE events depends on three parameters:

MPIAxisConfig.inPosition.settlingTime
MPIAxisConfig.inPosition.positionFine
MPIAxisConfig.inPosition.velocity

DONE events are only generated when command = target or after STOP, ESTOP or ABORT events.

For velocity moves, the generation of AT_VELOCITY events depends on two parameters:

MPIAxisConfig.inPosition.settlingTime
MPIAxisConfig.inPosition.velocity

The settlingTime value specifies the amount of time (seconds) that a motion must be within the positionFine band, in order for the motion to be considered complete (finished).

The positionFine parameter is a tolerance (encoder counts), where we know a motion is complete if the motion settles within this tolerance.

The velocity parameter specifies a band around the target velocity for velocity moves.

A fourth parameter (MPIAxisConfig.inPosition.positionCoarse) specifies a band around the final position.

MEIXmpStatusIN_FINE_POSITION | MEIXmpStatusIN_COARSE_POSITION
 MEIXmpStatusAT_TARGET | MEIXmpStatusAT_VELOCITY
MEIXmpStatusDONE

MEIXmpStatusIN_FINE_POSITION

During Normal Conditions (no Stop, E-stop, or Abort)
Between mpiMotionStart(...) and AT_TARGET, SETTLED is FALSE.

After AT_TARGET, the evaluation of the settling criteria begins. When the settling criteria has been satisfied, IN_FINE_POSITION is TRUE.

The settling criteria are:

    1. The absolute value of the position error is less than or equal to the fine position tolerance.
    2. The absolute value of the velocity is less than or equal to the velocity tolerance.
    3. Both of the above criteria has been satisfied for the settling time. Whenever either criteria 1 or 2 is not satisfied, SETTLED is cleared and the settling timer is reset.

During STOP
If settleOnStop is FALSE, SETTLED is FALSE.

If settleOnStop is TRUE and Feedrate != 0, SETTLED is FALSE.

If settleOnStop is TRUE and Feedrate = = 0, evaluation of the settling criteria begins.

After the settling criteria has been satisfied, SETTLED is TRUE.

During E-STOP
If settleOnEstop is FALSE, SETTLED is FALSE.

If settleOnEstop is TRUE and Feedrate != 0, SETTLED is FALSE.

If settleOnEstop is TRUE and Feedrate = = 0, evaluation of the settling criteria begins.

After the settling criteria has been satisfied, SETTLED is TRUE.

If both E-STOP and STOPoccur simultaneously
If both settleOnStop and settleOnEstop are FALSE, SETTLED is FALSE.

If either settleOnStop or settleOnEstop are TRUE and Feedrate != 0, SETTLED is FALSE.

If either settleOnStop or settleOnEstop are TRUE and Feedrate = = 0, evaluation of the settling criteria begins.

After the settling criteria has been satisfied SETTLED is TRUE.

Note

If STOP and E-STOP occur simultaneously, the XMP applies priority to the E-STOP. Both status bits will be true, but the motion will decelerate at the E-STOP rate.

During ABORT
IN_FINE_POSITION is FALSE.

If both E-STOP and ABORT occur simultaneously
During an E-Stop_Abort condition, SETTLED is FALSE (even if settleOnEstop is TRUE).

After mpiMotionAction(..., MPIActionRESET)
If SETTLED status is TRUE before RESET, the status will be unaffected (no event generated).

If SETTLED status is FALSE, the effect of RESET depends on the cause: If SETTLED is FALSE because:

  • the position error exceeds the tolerance, SETTLED will remain FALSE (no event generated).
  • the position error is within the tolerance but STOP is TRUE and settleOnStop is FALSE, SETTLED will become TRUE at settlingTime after the RESET call (event will be generated).
  • the position error is within the tolerance but E_STOP is TRUE and settleOnEstop is FALSE, SETTLED will become TRUE at settlingTime after the RESET (event will be generated).
  • the position error has been within the tolerance for settlingTime but ABORT is TRUE, SETTLED will become TRUE immediately after the RESET (event will be generated).

MEIXmpStatusIN_COARSE_POSITION

During Normal Conditions (no Stop, E-stop, or Abort)
The SETTLED status bit can be set only during motion (defined from the return of mpiMotionStart(...) until MEIXmpStatusDONE is set for the following motion types:

  • S-Curve (final velocity = 0)
  • Trap
  • PT (after final point has been specified)
  • PVT (after final point has been specified)

For these motion types SETTLED is TRUE whenever the absolute distance to the target (measured from the actual position to the final position) is less than or equal to the coarse position tolerance. If the target position is changed by mpiMotionModify(...) calls, SETTLED may be set and cleared more than once (causing multiple events) during a single move.

SETTLED is always FALSE for velocity moves (or moves using the FINAL_VEL attribute where the final velocity is non-zero).

During STOP, E-STOP, or ABORT
SETTLED is FALSE.

After mpiMotionAction(..., MPIActionRESET)
SETTLED is FALSE.

MEIXmpStatusAT_TARGET

There can be up to 2 filter outputs used in calculating the output level of the Motor command. The following expression is evaluated each sample to determine this output:

During Normal Conditions (no Stop, E-stop, or Abort)
The AT_TARGET status bit can be set only during motion (defined from the return of mpiMotionStart(...) until MEIXmpStatusDONE is set for the following motion types:

  • S-Curve (final velocity = 0)
  • Trap
  • PT (after final point has been specified)
  • PVT (after final point has been specified)

For these motion types AT_TARGET is TRUE whenever the command position is equal to to the target (final) position. If the target position is changed by mpiMotionModify(...) calls, AT_TARGET may be set and cleared more than once (causing multiple events) during a single move.

AT_TARGET is always FALSE for velocity moves (or moves using the FINAL_VEL attribute where the final velocity is non-zero).

During STOP, E-STOP, or ABORT
AT_TARGET is always FALSE.

After mpiMotionAction(..., MPIActionRESET)
AT_TARGET is always FALSE.

MEIXmpStatusAT_VELOCITY

During Normal Conditions (no Stop, E-stop, or Abort)
The MOTION_AT_VELOCITY status bit can only be set during the constant velocity portions for the following move types:

  • Velocity
  • S-Curve (final velocity = 0)

The velocity settling criteria are continuously evaluated during the constant velocity portion of the motion. Once the criteria has been satisfied, the MOTION_AT_VELOCITY bit is set to TRUE. MOTION_AT_VELOCITY is FALSE during any non-constant velocity portions of the motion.

The velocity settling criteria are:

    1. The absolute value of the velocity error is less than or equal to the velocity tolerance.
    2. Criteria 1 has been satisfied for the settling time. Whenever Criteria 1 is not satisfied, MOTION_AT_VELOCITY is set to FALSE and the settling timer is reset.

After Reset, Stop, E-stop, or Abort
After a Reset, Stop, E-Stop, or Abort, MOTION_AT_VELOCITY is always FALSE.

MEIXmpStatusDONE

This status bit is set to TRUE whenever SETTLED is TRUE. It can be cleared only by mpiMotionStart(...).

After mpiMotionAction(..., MPIActionRESET)
DONE is always TRUE.
Return to MPI Software Concepts


Compares and Encoder Rollover

.

Compares and Encoder Rollover

The XMP's compare engine is capable of handling encoder rollover. The compare engine is designed to produce correct comparisons when the encoder is within 230 counts (1073741824 counts). The way the compare engine works is by dividing the range of signed 32-bit integers into four "quadrants" as shown below.

The compare engine looks to see if the encoder position is in an adjacent quadrant to the compare position.

If so, then the engine responds appropriately thus avoiding encoder rollover problems. If the encoder position is in the opposite quadrant, the compare engine assumes a false comparison and no comparison is made. If the encoder position is in the same quadrant, a comparison is necessary and the compare engine will perform a comparison.

TRUE = Comarison
FALSE = No Comparison

For motion that is in the negative direction, you will typically use a Less Than or Equal to Comparison (blue).

For motion that is in the positive direction, you will typically use a Greater Than Comparison (green).

A scenario that may be confusing and prone to an encoder rollover problem occurs between ±231 and -230. However, the following diagram will show how this comparison is not plagued by any rollover problem. For example,

If,
y = 2,000,000,000
x = -1,600,000,000
z = -1,000,000,000

Despite the actual values of the points, the compare engine sees the following relationships:

y < x
z > x

Here is an example demonstrating how the compare engine might work in a real-life scenario. The example below is using the Greater Than Comparison. Let's say that the XMP is controlling the camera so that it takes a snapshot once an object passes the compare position. The camera is set up to take a photo upon the transition of a digital I/O line that the XMP controls. Once the object has passed the compare position, the I/O state will change and a snapshot will be taken of the object. The host computer may then receive the data and based upon the results, tell the XMP to make the necessary adjustments.

The following table of diagrams can be used as a guide to explain every possible compare engine result.

For motion that is in the positive direction, you will typically use a Greater Than Comparison (yellow).
For motion that is in the negative direction, you will typically use a Less Than or Equal Comparison (blue).


Compiling Program Sequencer Commands

An MPICommand will “compile” into one or more MEIXmpCommand{}s, each of which takes up a slot in the MEIXmpCommandBuffer{}. In general, an MPICommand will compile into a single MEIXmpCommand{}, but an MPICommand of type MPICommandTypeMOTION [with a motionCommand of MPICommandMotionSTART (i.e. mpiMotionStart(...))] will require several MEIXmpCommand{}s.

How many sequencer commands an MPI sequence command compiles to depends on the number of axes and number of positions in the move. The next table shows how many xmp sequencer commands it takes to do the equivalent of an mpiMotionStart(...).
Number of Sequencer Commands to be equivalent to mpiMotionStart(...)
Number of sequencer commands required | To do this:
axisCount + | One MEIXmpCommand{} per axis to write the axis number to MEIXmpLinkBuffer{}.MSLink[].Axis[].AxisNumber
1+ | 1 + One MEIXmpCommand{} to write axisCount to MEIXmpLinkBuffer{}.MSLink[].Axes
1+ | One MEIXmpCommand{} to write the MEIXmpMotionType{} to MS[].Mode.
(((axisCount*pointCount) + 3) / 4) + | One MEIXmpCommand{} for every four MEIXmpPoint{}s written to PointBuffer.Point[]
axisCount + | One MEIXmpCommand{} per axis to load the MEIXmpPoint(s)
1 | One MEIXmpCommand{} to start the motion


XMP Configuration

For a print-friendly version of the diagram below, click here.


XMP Configuration (page layout view)

.

XMP Configuration

Legal Notice
Copyright © 2003 Motion Engineering


Default XMP-Series Controller Configuration

Overview | Introduction | Software Components | Version Control
Automated Software Configuration | FAQs

Overview

The XMP-Series controller’s Flash memory is now pre-loaded at the factory with base firmware. This firmware contains a minimal amount of code to boot the DSP and allows the MPI to identify the XMP-Series controller. To operate the controller you will need to download the binary code included in this MPI software distribution. Please see the sections below for a complete description about software binary management and instructions to download firmware to your controller.

Introduction

System designers need to give careful consideration to the software configuration management procedures for their machines. To ensure machine consistency and quality, a process for software installation, configuration, version control, and verification must be implemented. Addressing this issue early in the development cycle will significantly reduce confusion and mistakes. Failure to implement some basic procedures can cause unknown machine configurations, costly field repairs/upgrades, mysterious intermittent problems, broken equipment, and possible injury.

The MPI and XMP-Series controllers contain several features to make configuration management easy. Please take the time to understand and implement these features before you begin development.

Software Components

The MEI software distribution contains several software components, which need to be loaded onto your machine and controller. The MPI DLL, header files, import libraries, device driver, utility programs, controller binaries, sample code, etc. These are all loaded onto your hard drive by the InstallShield distribution. Additionally, the controller contains on-board flash memory to store DSP code, FPGA code, and configuration information. You will also need to load the appropriate DSP (.bin) and FPGA (.fpg) code into your controller’s flash memory. The code is loaded into the DSP and FPGA(s) during power-on or when the controller is reset.

Version Control

Each software component has its own version number. These components have been tested together at the factory for interoperability.

The software version numbers have the following format:

Motion Console | NN.NN.nn | Major, Medium, minor
Motion Scope | NN.NN.nn | Major, Medium, minor
MPI DLL | YYYYMMDD.b...r | Year, Month, Day, branch,...rev
XMP Firmware | NNNnn | Major, minor
FPGA Code | RRR | Revision

The software has automated compatibility checking. If there is a compatibility problem between software components, an error code will be returned.

If an application (Motion Console and Motion Scope are applications too) and MPI DLL are NOT compatible, the error message "Control: application not compatible with MPI DLL" will be returned. To correct this problem, you can recompile your application with the appropriate MPI import library OR install the proper MPI DLL.

If the MPI DLL and firmware versions are NOT compatible, the error message, Control: firmware version mismatch will be returned. The user or application must download the appropriate firmware to correct the problem. The DLL and firmware versions can be determined with the version.exe utility, Motion Console, or application code.

If the controller flash memory has NOT been configured, the error message Control: no firmware found (factory default) will be returned. To correct this problem, the user or application must download the appropriate XMP firmware and FPGA images. Firmware and FPGA images can be downloaded from Motion Console, flash.exe, or application code.

For example, if Motion Console detects that the controller is in the factory default configuration (no firmware) or if the MPI DLL is not compatible with the firmware, it will prompt the user to download firmware:

Click Yes. Motion Console will then prompt you for the firmware file:

Click Browse and select the appropriate firmware file (.bin). The firmware is stored in the mei\xmp\bin directory (by default):

Select the proper file and click Open.

Automated Software Configuration

During the development stage of your machine, several different versions of MPI DLLs and/or XMP firmware might be used. You may want to upgrade to new releases in order to take advantage of new features. MEI may provide custom features or bug patches for previous releases.

During the production stage of your machine, you will want to guarantee software configuration consistency. MEI recommends using the InstallShield release package, a third party installer program, or batch scripts to install your application code and MEI’s software onto your machine.

You will also want to guarantee that the controller’s flash memory configuration is consistent. To load the flash, you could automatically download firmware (.bin) and FPGA (.fpg) code during software installation OR during your application initialization. For example, the flash.exe program could be executed from an installer or batch script during software installation. Included in the XMP\Apps directory, is a sample program called initFlsh.c that demonstrates how to read the controller’s firmware/FPGA versions, check if they match the desired configuration, and download the correct versions (if needed).

Also, you can create your own custom firmware file by saving configurations to flash, and uploading the firmware file to your hard drive. The firmware contains a userVersion field, so you can keep track of your custom configured files. Using this technique, the firmware can be configured with Motion Console, uploaded to a file (myfirm.bin) and downloaded to future machines using Motion Console, flash.exe or your application.

FAQs

Why do I need to download firmware to my controller?
Only the machine developer knows which firmware version and configuration works with their application. By downloading firmware directly, you have complete control over your development and release versions.

Why can’t MEI download firmware to my controller at the factory?
MEI can download your firmware, but it is expensive and causes several problems:

1. You would need a custom part number for each controller with a different firmware image. Even if you use the same controller hardware in several machines, each version would need to be ordered, purchased, tracked, and stocked separately.

2. Changing a firmware image (version or configuration) would require a new part number. This causes transition problems between “old” and “new” parts.

3. Repairs and replacements are much more complicated.

4. Field upgrades are not possible. Controllers must be returned to the factory to receive new firmware and a new part number.

What if I need to upgrade software in the field?
If you configure the flash memory as part of your application or installation, then it is very easy to upgrade software and/or firmware in the field. If you do not, then you’ll need to manually update the flash memory.

Can I modify the FPGA (.fpg) files?
No. These files are binary and do not contain any configuration data.


Encoder Fault for Secondary Encoders

.

Encoder Fault for Secondary Encoders

In version 20021212, the MPI and Firmware were extended to support encoder faults (broken wire and ille-gal state) for secondary encoders. Each motor object has two encoder inputs (primary and secondary). Depending on the SynqNet node type, the hardware may or may not support secondary encoders. By default, during network initialization, the MPI maps each secondary encoder to each motor sequentially.

For example, a node with 4 primary encoders and 1 secondary encoder will have the secondary encoder mapped to motor 0. The encoder fault inputs for the primary encoder and the secondary encoder are mapped to the same motor object.

To configure the encoder fault conditions and action, use mpiMotorEventConfigSet.
To clear encoder faults, use meiMotorEncoderReset.
To determine encoder fault status, use meiMotorStatus.


About Homing

Capturing position is central to the concept of homing (even for Sercos XMPs). The HOME event is triggered by the Capture Status instead of the Home Input (Motor[].IO.DedicatedIN.IO). Also note that each motor has its own default Capture Register (see the separate tip about capture numbering).

Currently the only configurable capture parameter (mpiCaptureConfigSet(...)) is captureConfig.trigger. CaptureConfig.trigger indicates which inputs are used for capturing (trigger.mask) and what polarity these inputs must be (trigger.pattern) to trigger a capture (HOME) event.

For non-Sercos XMPs, you can use 7 inputs to capture position: Home, Index, Positive and Negative Overtravel, and the three Transceiver inputs. These 7 inputs can be combined in a wide variety of ways, but the most useful are the Home and Index combination. Some designers also like to use Overtravel and Index combinations, and there is no problem doing this for non-Sercos drives.

For Sercos drives the selection is more limited. Only Index truly captures position, but all combinations of Home and Index can be used to cause a HOME event.

After a Capture object has been configured, capturing is controlled by mpiCaptureArm(...). To put the capture latch in the armed state, call mpiCaptureArm(...) with a TRUE arm parameter.

Actual position capturing will then occur if the capture criteria (defined by trigger.mask and trigger.pattern) is true (for at least 100 nsec) following a period where the criteria is false (for at least 100 nsec). To disable capturing, call mpiCaptureArm(...) with a FALSE arm parameter.

Note that capture will not occur (for non-Sercos motors) if the capture criteria is already TRUE when mpiCaptureArm(...) is called. Capture will only occur if the criteria goes FALSE, and then returns to TRUE.


.

Host-Based and Controller-Based Motion

Host-Based Motion | Controller-Based Motion | Sequence

Host-Based Motion

Basic Motion

NOTE: The terms “Control object” and “Controller” designate the same thing: a Control object.

To perform a simple motion using the XMP controller requires as few as eight basic steps:

    1. Create a Control object
    2. Initialize the Control object
    3. Create an Axis Object
    4. Create a Motion Object
    5. Append an Axis to a Motion object’s list (of axes)
    6. Start the Motion Check the Status of the Motion
    7. Delete the Objects

In more detail,

    1. Create a Control Object: Use mpiControlCreate(...) to create a Control object. You should only create one and only one Control object per board per process. The Control object controls all of the operating system resources for the actual board. You must create a Control object before creating any other objects.
    2. Initialize the Control Object: Use mpiControlInit(...) to initialize a Control object. mpiControlInit(...) establishes contact with the device driver, and maps the XMP’s memory space to the application’s memory space. An application can call mpiControlInit(...) more than once, but it isn’t necessary.
    3. Create an Axis Object: Use mpiAxisCreate(...) to create an Axis object, by passing a Control object handle and Axis number to it.
    4. Create a Motion Object: Use mpiMotionCreate(...) to create a Motion object, by passing a Control object handle and a Motion Supervisor (number) to it. Each motion object maintains a list of axes, which defines a coordinate system (specified by the number and order of the axes).
    5. Add an Axis to a Motion object’s list (of axes): Use mpiMotionAxisAppend(...) to associate an Axis with a Motion. The association is done by appending the Axis to a Motion object’s list of axes. Note that the Axis must be located on the same controller (board) as the Motion object.
    6. Start the Motion: Use mpiMotionStart(...) to start a Motion.
    7. Check the Status of the Motion: Use mpiMotionStatus(...) to determine if the current motion has completed yet.
    8. Delete the Objects: Use mpiObjectDelete(...) methods to delete the objects. We recommend deleting objects in the reverse order of creation. For this example, you would perform the object deletions in the order: Motion first, then Axis, then Control. Note that for any application, the Control object must be deleted last.

Controller-Based Motion

Motion Command
The XMP controller’s firmware uses a state machine for controller-based motion. The motion state machine has three states (Moving, Idle, Error). Transitions between states occur after a command (Start, Resume, Modify, Stop, E-Stop, Abort, Reset) or after an event (Done, Amp_Fault, Limits).
MPIEvents are generated by the XMP controller. MPIEvents (axis events) cause MPIActions to be generated. The MPIActions in the table are the default values and can be changed. Valid MPIActions for events are None, Stop, EStop, Abort.
MPIEventType | MPIAction (Default) | Event Trigger
AMP_FAULT | ABORT | Polarity (I/O bit Hi/Lo)
HOME | STOP | Polarity (I/O bit Hi/Lo)
LIMIT_HW_POS | ESTOP | Polarity (I/O bit Hi/Lo)
LIMIT_HW_NEG | ESTOP | Polarity (I/O bit Hi/Lo)
LIMIT_SW_POS | ESTOP | Position
LIMIT_SW_NEG | ESTOP | Position
LIMIT_ERROR | ABORT | Error [= absolute value (command position - actual position)]

MPIActions can come from the host or the firmware. For safety, there are 4 guaranteed restrictions on who can generate certain MPIActions:

    • The firmware can never issue Start. (Never 1 in table)
    • The firmware can never issue Resume. (Never 1 in table)
    • The firmware can never issue Reset. (Never 1 in table)
    • The host can never issue Done. (Never 2 in table)

    1 = Start/Resume/Reset can never be issued from the firmware; Start/Resume/Reset can only be issued from the host.
    2 = Done can never be issued from the host; Done can only be issued from the firmware.
MPIAction | Originating from Host | Originating from XMP Firmware
Start
Resume
Reset
Stop 		mpiMotionStart(...) mpiMotionResume(...) mpiMotionReset(...)
mpiMotionStop(...) 		Never 1
Never 1
Never 1
Event
E_Stop
Abort 		mpiMotionEStop(...) mpiMotionAbort(...) Event
Event
Done | Never 2 | If Settled and In_Position

1 = Start/Resume/Reset can never be issued from the firmware; Start/Resume/Reset can only be issued from the host.
2 = Done can never be issued from the host; Done can only be issued from the firmware.

Sequence

A Sequence consists of a linked list of Commands. Execution of a Sequence can be started, stopped, or its status queried. Execution of a Sequence begins with the first Command in the sequence and proceeds sequentially, unless otherwise commanded (e.g., a branch command). Execution of a Sequence ends when the last Command in the sequence is executed, or when the execution is stopped by the host.

An XMP can be controlled directly by the host or controlled by commands that the host downloads (for independent execution by the XMP firmware). Downloaded commands are managed by a firmware object known as a Program Sequencer (PS).
For the XMP, there are currently 16 Program Sequencers and a single command buffer that holds 256 commands. Each Sequence is created with a maximum command count, but the total command count for all Program Sequencers cannot exceed 256 commands.
The XMP commands can be thought of as a machine language for a virtual RISC processor (Reduced Instruction Set Computer) implemented by the XMP firmware. Similarly, a Program Sequencer can be thought of as an operating system thread, with the PS command buffer considered as a page of virtual memory for the thread. Each PS maintains the location within its command buffer of the next command to be executed, i.e., a program counter. The XMP firmware time-slices the PS “threads” by executing a command in every active PS, on every firmware cycle. When the next command to be executed is not located in the PS command buffer, a host interrupt is generated (i.e., a page fault occurs). The host is then expected to fill the PS command buffer with the next batch of commands. This method allows command sequences to be of any length.

The Motion Programming Interface (MPI) provides a layer of abstraction on top of the XMP Program Sequencer. The MPI Sequence object maintains a list of MPI Command objects. Commands exist to perform motion, compute/load/store data, branch-on/wait-for conditions (arithmetic, logical, I/O bits, events), delay, generate user-defined events, etc. There are a variety of command types, each with type-specific command parameters. The high-level language defined by these commands makes use of MPI objects, and allows for simple expressions with operands (that can be specified by value or by reference). A command can have a text label so that the command itself can be the target of a branch command.

When you create a Sequence, you specify the desired XMP PS command buffer size. Specifying a PS command buffer size of -1 will cause all remaining command buffer space to be allocated. After creating a Sequence, you typically create and append Command objects to the Sequence, and a Sequence can have any number of Command objects appended to it. When the Sequence is started, the Commands are “compiled” into XMP commands and loaded into the PS command buffer for execution.

When the XMP firmware does not find the next command to be executed in the command buffer, the firmware generates a host interrupt. This interrupt is handled by the MPI EventMgr, which then calls the Sequence to load the next batch of commands down to the Program Sequencer; your application does not have to do anything.


MPI Objects Overview

.

MPI Objects Overview

Motor
Drive Communication
I/O (Home, Motor, Limit switches)
Encoder

Capture

  • high speed position capture (triggered by digital input)
  • useful for homing

Compare

  • high speed position compare (triggers a digital output)
  • useful for triggering some other instrument

Filter
Control Algorithm (PID, PIV, custom)
Ouput filtering (postfilters)

  • biquad (6 filters)
  • IIR (32 coefficients)

Axis
Represents a physical axis
Trajectory calculations
Position information

Motion (Supervisor)
Coordinates motion between axes
Responsible for clearing errors

Recorder
Record any 32 locations of controller memory at 10kHz continuously in real time
Large buffer on controller
Useful for

  • Tuning (Motion Scope)
  • Data correlation (ex: ADC inputs vs. axis position)
  • System well being (Is a part about to fail?)

EventMgr (Event Manager)
Responsible for distributing gathering and distributing events
NOTE: mpiEventMrgFlush() flushes events from associated notify objects, not from the event pool

Notify
Report events

Platform
Useful for translating memory addresses between the host PC and the XMP

Motion Types
Trapezoidal
S-Curve

  • Uses parameter "jerk percent"

S-Curve Jerk

  • Specify acceleration and deceleration jerks

Velocity
Velocity Jerk
PT

  • Linear interpolation (segments have constant velocity)
  • Useful for streaming points

PVT

  • Useful for specifying custom paths

Spline
Bessel
Path

Motion Attributes
Delay

  • Wait for a period of time before starting a move

Hold

  • Wait for a status or I/O change before starting a move

SynqStart

  • Synchronize the start of motion for all axes

SynqEnd

  • Synchronize the end of motion for all axes

Special Case: Neither SynqStart or SynqEnd are used

  • Only one trajectory is used
  • Useful for ensuring maximum accelerations and velocities are not exceeded on x-y systems

Server
A computer without XMP (client) can communicate efficiently with a computer with an XMP (server) over an Ethernet connection. The client can then run any application writtten with the MPI over the Ethernet connection. This is useful for using Windows based Tools if the server is running at RTOS.

  • Motion Console
  • Motion Scope
  • System Analysis Tools

Useful for changing configurations if the server is in a clean room.

Trajectory

Beyond the MPI

Firmware
The contoller firmware is written in C.

  • Easy to change/customize
  • Can be compiled and downloaded quickly (under 5 minutes)


How Motion Completion Events are Generated

.

How Motion Completion Events are Generated

There are three types of generated events related to motion completion: DONE, AT_VELOCITY, and IN_POSITION_COARSE. Motion completion for a position move is indicated by a DONE event, while motion completion for a velocity move is indicated by an AT_VELOCITY event.

AT_VELOCITY is not generated for position moves. For both position moves and velocity moves, the MPI uses a settling time window to determine when to generate a motion completed event (to indicate that motion has finished on an axis).

For position moves, the MPI uses the settling time window to determine when an axis has reached the final target location and is stable.

For velocity moves, the MPI uses the settling time window to determine when an axis has reached the final velocity. This works because during ringing, the velocity is highest when the position error is lowest. (Velocity and position error are inversely-related.)

Position and Velocity criteria for generating motion completion events
For a | A "motion completed" event is generated when | Criteria
Position move | ABS(position error) < inPosition.tolerance.positionFine | position
Position move | ABS(velocity error) < inPosition.tolerance.velocity | velocity
Velocity move | ABS(velocity error) < inPosition.tolerance.velocity | velocity

where: |
 | position error = (command position – actual position)
 | velocity error = (command velocity – actual velocity)

For Position Moves
A DONE event is generated after a position move only after both the position and velocity criteria have been met for the period specified by the settling time. To determine if motion has completed, position moves use both position and velocity criteria.

The default (factory) value for inPosition.tolerance.velocity is 20,000,000 counts/sec. We included the ability to additionally use the velocity criteria for position moves because some users prefer to decide that an axis is “settled” only after the position error and actual velocity are both low enough.

For Velocity Moves
An AT_VELOCITY event is generated for a velocity move only after the velocity criteria has been met for the period specified by the settling time. To determine if motion has completed, velocity moves use only the velocity criteria (they don’t use the position criteria).

Note that the motion completed event generated this time is an AT_VELOCITY event rather than a DONE event. For velocity moves, DONE events will only occur after mpiMotionAction(..., MPIActionSTOP) calls.

You can also use the velocity criteria to determine when ringing has stopped after an open loop commutation move. To do this, the position criteria is effectively disabled by setting the position tolerance to a very large value (e.g., 1.0E10). After that, the DONE event following a move is determined entirely by the velocity tolerance and settling time, and, therefore, the event will be generated only after the ringing has stopped.

Be aware that setting inPosition.tolerance.velocity to 0 does not disable the velocity criteria. For interpolated scales, setting inPosition.tolerance.velocity to 0 makes it very difficult to meet the criteria of 0 counts of motion for settlingTime seconds.

Settling Time Parameters

Four Settling Time Parameters

For position moves, the generation of DONE events depends on three parameters:

MPIAxisConfig.inPosition.settlingTime
MPIAxisConfig.inPosition.positionFine
MPIAxisConfig.inPosition.velocity

DONE events are only generated when command = target or after STOP, ESTOP or ABORT events.

For velocity moves, the generation of AT_VELOCITY events depends on two parameters:

MPIAxisConfig.inPosition.settlingTime
MPIAxisConfig.inPosition.velocity

The settlingTime value specifies the amount of time (seconds) that a motion must be within the positionFine band, in order for the motion to be considered complete (finished).

The positionFine parameter is a tolerance (encoder counts), where we know a motion is complete if the motion settles within this tolerance.

The velocity parameter specifies a band around the target velocity for velocity moves.

A fourth parameter (MPIAxisConfig.inPosition.positionCoarse) specifies a band around the final position. Optionally, an interrupt can be triggered when the motion is in the positionFine band, but not necessarily complete (finished). In this case, the interrupt becomes an early warning of motion that is about to finish (i.e., mostly finished).


Motor Brake (brake enable/disable delay)

.

Motor Brake (brake enable/disable delay)

The Brake feature sets the User Output (one per motor) to an active state when the Amp Enable output is disabled and sets the User Output to an inactive state when the Amp Enable is enabled. The Brake feature also supports specifiable delay times between the Amp Enable/Disable and User Output logic.

The following data structure has been added to the motor.h header file to support the Brake feature.

Data Structure

typedef enum{
     MPIMotorBrakeModeINVALID = -1,
     MPIMotorBrakeModeNONE,
     MPIMotorBrakeModeDELAY,
     MPIMotorBrakeModeLAST,
     MPIMotorBrakeModeFIRST = MPIMotorBrakeModeINVALID + 1
} MPIMotorBrakeMode;

typedef struct MPIMotorBrake {
     MPIMotorBrakeMode   mode;
     float               applyDelay;
     float               releaseDelay;
} MPIMotorBrake;

Description of Members

mode - set to MPIMotorBrakeModeNONE for no brake, set to MPIMotorBrakeModeDELAY for use brake feature specified delays.

applyDelay - specifies the delay (seconds) between when the brake is active and the amp enable is disabled.

releaseDelay - specifies the delay (seconds) between when the amp enable is enabled and the brake is inactive.

The following diagrams further explain how the Brake Enable/Disable Delay feature works:


XMP Multitasking

.

XMP Multitasking

Introduction

The MPI provides multitasking capabilities in the host, while the XMP can execute commands and receive data without host intervention.


SynqNet Network Topology Verification

.

SynqNet Network Topology Verification

By default, the controller's SynqNet topology information is un-initialized and cannot be verified at a power-on or reset. The default configuration for all MPI objects (i.e. motion, motor, axis, filter) is considered safe for all SynqNet drive blocks (or nodes). Changing an object's default configuration is said to give the object a "custom" configuration. While a particular custom configuration might be safe for one SynqNet drive block, it may not be safe for other drive blocks. All object configurations saved in flash will be sent/written from the logical MPI objects to the underlying physical network hardware during controller initialization or a controller/network reset. Without topology verification, if custom object configurations are saved to flash and the underlying physical network changes, a custom configuration could be sent to a drive block, for which it was not intended. As a safety measure, when attempting to save a custom configuration to flash using any mpi*Object*FlashConfigSet(...) method, a return value of MEIFlashMessageNETWORK_TOPOLOGY_WARNING will be returned whenever the controller's SynqNet topology information is un-initialized. The corresponding text message for this return value is:

Flash: saving values to an unconfirmed network -please run meiControlTopologyToFlash

If this code is returned, the method has successfully executed. However, it is also indicating that the user should confirm the network by saving the current SynqNet topology to flash.


Object Relationships

.

Objects Relationships

Introduction | Object List | Bitmap | Array of Object Numbers
Using Lists, Bitmaps, & Arrays | Application-MPI-Controller Interface

Introduction

To create a motion application, you create objects, link them in relationships (associate them), and provide the desired parameters for motion.

There are three ways that you can associate one object with another object:

    • Using an object List
    • Using bitmap
    • Using an array of object numbers

Objects using bitmaps or an array of numbers must all be present physically on the same controller, while objects on an object list can come from different controllers (such as objects on the EventMgr control list).
Three Ways to Associate Objects with Objects
Object | . | When to Use
List | an ordered list | Use a List when the order of the objects to be associated is important, OR when some of the objects reside on different controllers.
Bitmap | an un-ordered list | Use a bitmap when the order of the objects is not important, AND the objects must all reside on the same controller (same Control object).
Array of object numbers | an ordered list | Use an array of object numbers when the order of the objects is important, AND the objects must all reside on the same controller (same Control object).

Object List

Use an object list to associate objects when ordering is required, such as the Axis list maintained by a Motion object. For example, when using a Motion object, a list of Axes 0, 1, 2 is not the same as a list of Axes 0, 2, 1. Such a distinction is not available when using an object map. Refer to the List methods for Motion, Notify, Sequence and EventMgr objects.

This object: | Can have object lists of:
Motion | Axes
Notify | Events
EventMgr | Controls Notify objects
Sequence | Commands

Bitmap

An object map is a bitmap, where each numbered bit represents the presence or absence of the correspondingly numbered object. You can order the objects in the bitmap from numeric low-to-high or high-to-low, but there is no other meaningful capability for ordering objects with an object map.

Another consideration with object maps is that all objects specified in the map and the object (that those objects are being associated with) must be resident on the same controller (Control object).

Note: Although the MPI allows an Axis to be associated with a Motion without regard to the controller (Control), the XMP implementation of the MPI does not allow this.

Object maps tend to be used to associate low-level objects that:

    • must all reside on the same controller (Control)
    • and the order in which the objects are ordered does not matter

Note that the objects specified in the bitmap may be associated with another object, without those objects having to be created and deleted. A goal of the MPI has been to minimize the need to create and delete objects, especially objects that are just used for configuration. For example, an MPI application that uses the default configuration doesn’t have to create Filter or Motor objects, yet the application can still configure an Axis, by calling mpiAxisFilterMapSet(...), where the Filters are specified by the bitmap.

Object Maps for Objects
This object: | Has associated object maps of:
Filter | Axes Motors
Axis | Filters Motors
Motor | Filters Axes Adcs

Array of Object Numbers

The MPI provides a third means of associating objects, by using object numbers. Object numbers should be used when ordering is required, and all the resources arelocated on the same controller.

Using List, Bitmaps, & Arrays

Application-MPI-Controller Interface

Legal Notice
Copyright © 2003 Motion Engineering


Using the Origin Variable

In servo control applications, the Command and Actual Positions for an Axis are generally used for position error calculations. On each sample, the XMP controller reads the new Actual Positions from the feedback devices and calculates the new Command Positions.

To determine the relationship between Command and Actual Positions for an Axis and physical positions on the machine, you can use the Origin variable (which can be set by the host).

If it is important to set the Command or Actual Position to an exact value, you should use the mpiAxisOriginSet(...) function. Calling mpiAxisOriginSet(...) will modify both Command and Actual Positions by the same amount.

The Origin variable can be set in two different ways depending on the desired result. For example, assume the Command and Actual Positions are 10,000 and 10,024 counts respectively and that the axis is not moving.

Setting the Origin variable to 10,000 will result in Command Position = 0 and Actual Position = 24. Setting the Origin variable to 10,024 will result in Command Position = -24 and Actual Position = 0.

This second method is the most frequently used method for setting the new Origin after homing. Refer to the next table.
Position and Velocity criteria for generating motion completion events
If Command Position = | If Actual Position | And you set Origin Variable | Then Command Position = | And Actual Position =
10,000 | 10,024 | 10,000 | 0 | 24
10,000 | 10,024 | 10,024 | -24 | 0

Cautions about motion in general:

  1. During motion, you should never call the mpiAxisOriginSet(...) and mpiAxis[Actual|Command|Position]Set(...) functions. If you do call one of these functions, the XMP controller will immediately act on the new positions, causing the move to complete at a different point than the point specified in mpiMotionStart(...).
  2. Setting a new Command Position using mpiAxisCommandPositionSet(...) should be done with caution, because the XMP controller will immediately try to servo to the new position. If the new and old command positions differ by a large amount the axis may fault (limit error) or jump to the new position at very high speed.
  3. The effect of mpiAxisOriginSet(...) and mpiAxis[Actual|Command]PositionSet(...) calls will not be seen by the host until the next controller sample following the call.

    For example, if you call mpiAxisCommandPositionGet(...) immediately after calling mpiAxisOriginSet(...) or mpiAxisCommandPositionSet(...), mpiAxisCommandPositionGet(...) will probably return the old position values.


About the PID PIDOutputOffset Parameter

The PIDoutput Offset parameter is a constant value added to the PID calculation before sending the DAC value to the DAC.
Reason
More
1
 To compensate for the input offset errors in a “conventional” amplifier

For situations when the amplifier performs the commutation.

Individual DAC offsets can also be used to zero out-of-spec amplifier offsets.
2
 If a static DC torque (force) on the system is needed Typically used with a gravity-loaded (vertical) axis that has a simple current amplifier controlling the motor
3
 For testing the DAC

If the axis is aborted or all PID gains are zeroed, you can use the PIDOutputOffset parameter to set the DAC voltage directly. (3277 = 1Volt, 6553 = 2Volts, etc.)

You can only use the PIDOutputOffset parameter if the controller is not configured for motor commutation. If the controller is configured for commutation, use the Commutation DAC Offset to test the DAC.
4
 For using the DAC as a general purpose analog output

In some cases, the easiest way for the host to generate an analog signal is to set all PID gains to zero and use the PIDOutputOffset parameter to set the desired voltage level.

Alternatively, you can use the Commutation DAC Offset for the same purpose, which has the advantage that the voltage levels can be individually set for the two DACs.


Perform a Point-to-Point Coordinated Move

To generate a point-to-point coordinated move, you can use mpiMotionStart(...) with either a “trapezoidal” or “S-Curve” type motion. By scaling the Velocities, Accels, and Decels by the ratio of the distances, you can get a point-to-point coordinated move. The coordinated moves will all start and end at the same time.

It doesn't matter what the Jerk Percent parameter value is, because the calculated move time is the same for both trapezoidal and S-Curve moves. For example, specifying a vector Vel, Accel, Decel, and a distance X, Y, Z:


Symbol Definitions

.

Project / Makefile Settings: Symbol Definitions

MPI_DECL1/MPI_DECL2 | MEI_ASSERT | MEI_PLATFORM

Introduction |
 | This section describes compile-time symbol definitions used by the MPI library.
MPI_DECL1/MPI_DECL2

These symbols are used in library header files to handle compiler-specific language extensions when declaring external functions and data; in particular, those extensions used when making Win32 dynamic link libraries (DLLs). MPI_DECL1 precedes the return type of a function declaration; MPI_DECL2 follows the return type and precedes the function name:

    MPI_DECL1 long MPI_DECL2 mpiModuleFunction();
When building an application or the MPI library for Win32 platforms (Windows 95/NT), the following symbol definitions should be used:
MPI_DECL1=__declspec(dllexport)
    MPI_DECL2=__stdcall

MEI_ASSERT

When defined, MEI_ASSERT will cause calls to the macro meiASSERT(expression) to be compiled into the library. Otherwise, these calls will be discarded by the preprocessor.

The meiASSERT(...) macro is used by the library and is available to applications. It is a valuable debugging tool that can be used to catch programming errors at their source and prevent them from spreading. If the argument to the macro is TRUE (i.e. non-zero), execution proceeds normally. Otherwise, an error message is displayed; the message contains the name of the file and the line number of the meiASSERT(...) call. The application exits after displaying the message.

The MEI_ASSERT define is also required for the msgCHECK(…) macro to work. msgCHECK(…) is use throughout the sample applications and utilities.

MEI_PLATFORM

The MEI_PLATFORM symbols are used to indicate the platform for which the library and applications are built. Each platform has its own unique symbol.

Currently supported platforms:

MEI_PLATFORM_WIN95 | Microsoft Windows 95
MEI_PLATFORM_WINNT | Microsoft Windows NT
MEI_PLATFORM_WINRTSS | VenturComm WinNT RealTime SubSystem
Currently supported platforms; however, platform- and version-specific (contact MEI for details):
MEI_PLATFORM_LYNXOS | Real-Time Systems LynxOS
MEI_PLATFORM_QNX | Quantum Software Systems
QNX MEI_PLATFORM_VXWORKS | WindRiver Systems VxWorks
Potentially supported platforms:
MEI_PLATFORM_DOS | Microsoft DOS
MEI_PLATFORM_IRMX | Intel iRMX
MEI_PLATFORM_OS9 | Microware OS-9
MEI_PLATFORM_PSOS | Integrated Systems pSOS
MEI_PLATFORM_VRTX | Microtec Research
VRTX MEI_PLATFORM_WIN31 | Microsoft Windows 3.1
Note: Existence of an MEI_PLATFORM symbol for a potentially supported platform does not imply intent to support that platform.


Running Multiple Applications with the XMP

There are two situations that often cause problems when you are executing multiple applications at the same time:
  1. If one application resets the XMP controller while other applications are busy using the XMP, this is analogous to pulling the rug out beneath the feet of the other applications. The other applications are not aware that all states have been lost (controller reset), and thus these other applications get lost themselves.

    If you run two XMP applications at the same time (Motion Console and VM3, or Motion Console and your application), and if one application resets the board while the second application is busy accessing memory (like VM3), then the interface between the host and DSP can break down. To resolve this type of problem, you should close both applications, restart one application, and then reset the XMP.
  2. If you modify the default configuration of objects on the XMP, and then run another application which wants a different configuration of the same objects (program sequencers, motion supervisors, axes, etc), and you don't manage this, you can get into trouble.You have to coordinate how simultaneously exectuing applications manage the XMP resources.
  3. Simultaneously, using DLLs, applications, and Motion Console from different MEI releases can and will cause problems.


Saving Current SynqNet Topology to Flash

.

Saving Current SynqNet Topology to Flash

Executing the following method will save the current SynqNet topology to the controller's flash memory.

MPI_DECL1 long MPI_DECL2 meiControlTopologyToFlash(MPIControl control)

After a power-on or network reset, the firmware/mpi will compare the discovered network topology with the topology saved in flash memory. If all topology information matches, the controller will automatically transition the network to Synq (cyclic) mode. If the topology doesn't match, then the mpiControlInit() method returns a value of MEISynqNetMessageTOPOLOGY_MISMATCH, which has the corresponding text message:

SynqNet: network topology mismatch - network in asynq mode

Correcting a mismatch

If you receive the mismatch error message above, the motion application can alert the system operator that the physical SynqNet topology does not match the expected topology and suggest corrective action. This is a safety feature added to SynqNet that removes the possibility of automatically sending a block-specific configuration to the wrong block.

At this point, the network will be functional and in ASYNQ mode. ASYNQ mode allows network communication to each remote block, however no operational (control) data will be sent to any block. A motion application can query the actual network information, modify motion, motor, axis, and filter objects configurations in Motion Console, etc.

If the error code was returned due to a physical network problem, correcting the problem and resetting the network will bring the controller into SYNQ (Cyclic) mode. If the error code was returned due to an intentional topology change, the system-operator/developer needs to save the new topology to flash and reset the network. There are two way to do this:

  • The safest procedure is to reload the default firmware file (to restore default object configurations) and then save the new SynqNet topology to flash using meiControlTopologyToFlash(...).
  • If the system operator/developer is certain that the controller objects' (i.e. motion, motor, axis, filter, etc) configurations are safe for the new physical topology, he/she may opt to execute meiControlTopologyToFlash(...) method again, without reloading default firmware and reset the network.

NOTE: The second procedure can be a potentially hazardous. The configuration for the previously saved topology will be restored to the current topology at next reset or power-on. Restoring incorrect configuration settings can cause unexpected behavior in the physical motion system.


S-Curve Jerk Algorithm and Attributes

Algorithm | Attributes

Algorithm

A new move type, MPIMotionTypeS_CURVE_JERK, has been added to support a jerk-specified profile. This replaces the old jerkPercent algorithm. Two added features that the new S-Curve Jerk algorithm provide are the ability to call a motion modify at any time during a path move and the freedom to change jerk, acceleration, and maximum velocity independently. None of these values will be exceeded in the resulting motion. The new S-Curve Jerk algorithm will be ideal for making final adjustments to a move as it draws closer to its final target and for making smoother transitions from one motion to the next.

Old firmware: Notice that the acceleration is assumed
to be zero and that there is a sudden change in the velocity as a result.

New firmware: Notice that the acceleration changes less
abruptly and that the velocity profile is much smoother.

Safe parameters for jerk values should range from a minimum of amax* amax / vmax (amax is just reached when accelerating from 0 to vmax) and a maximum of amax / sample period (amax is reached in one sample period). In the new firmware, changes to the jerk will also change the time needed to complete a motion. For example, a large value of jerk will have a shorter time, but increase the “jerkiness” of the motion (see fig 1). Conversely, a small value of jerk will have a longer time, but a much smoother motion (see fig 2).

Two new parameters, accelerationJerk and decelerationJerk have been added to the MPITrajectory{…} structure. When they are non-zero, the acceleration profile uses the specified jerk and acceleration to ramp an axis(es) to constant velocity and then decelerate to a stop. If accelerationJerk or decelerationJerk is zero, an illegal parameter error is returned.

For the move type, MPIMotionTypeS_CURVE, the MPI calculates an appropriate jerk value based on the specified velocity, acceleration, and jerkPercent. The jerk value is computed according to the following formula:

If jerkPercent is zero, the jerk value is computed so that the maximum acceleration is reached in one sample period. With the previous S-Curve algorithm, the time for a move would not change as jerkPercent value was varied. This is also true for this S-Curve algorithm, as long as the move reaches maximum velocity. In short moves, where maximum velocity is not reached, setting jerkPercent to be small will result in a quicker move than if you were to set jerkPercent to be large.

WARNING! The same jerkPercent values may cause different profiles than the previous S-Curve algorithm.

Attributes

The new S_Curve algorithm behaves similarly to the previous algorithm, except for its attributes.

MPIMotionAttrMaskDELAY can now be used with any start motion, but never with motion modify.

MPIMotionAttrMaskAPPEND can be used with any motion, as long as it is not preceded by a motion that had a final velocity.

MEIMotionAttrMaskNO_REVERSAL returns a MPIMotionMessagePROFILE_ERROR if the given specifications would result in a move with a reversal init, thereby preventing the move from being executed.

MPIMotionTypeTRAPEZOIDAL, MPIMotionTypeS_CURVE, and MPIMotionTypeS_CURVE_JERK

MPIMotionAttrMaskRELATIVE, when used with MPIMotionTypeTRAPEZOIDAL, MPIMotionTypeS_CURVE and MPIMotionTypeS_CURVE_JERK means that the final position is relative to the beginning position of the motion.

MEIMotionAttrMaskFINAL_VEL can be used with MPIMotionTypeTRAPEZOIDAL, MPIMotionTypeS_CURVE and MPIMotionTypeS_CURVE_JERK, but should be used with caution as it may not be possible for the controller to compute a trajectory to meet these criteria, which would cause a MPIMotionMessagePROFILE_ERROR to be returned, and the move to be ignored.

Multi-Axis Motion

Neither MPIMotionAttrMaskSYNC_START nor MPIMotionAttrMaskSYNC_END
If neither MPIMotionAttrMaskSYNC_START nor MPIMotionAttrMaskSYNC_END are specified, a single MPITrajectory{...} may be specified for the resultant motion of multiple axes on one motion supervisor. The motion of each axis will be synchronized with the others on the motion supervisor. The maximum velocity, acceleration, deceleration, and jerk values of the first MPITrajectory structure will be used for the global vector parameters. It will ignore any other values supplied. This cannot be used with MEIMotionAttrMaskFINAL_VEL.

MPIMotionAttrMaskSYNC_START or MPIMotionAttrMaskSYNC_END but not both
If MPIMotionAttrMaskSYNC_START or MPIMotionAttrMaskSYNC_END (but not both) is specified, each axis will move as fast as possible and either start together, or stop together. If motion is point-to-point and more than one axis on the motion supervisor has a final velocity, MPIMotionAttrMaskSYNC_START or MPIMotionAttrMaskSYNC_END must be used. MPIMotionAttrMaskSYNC_END cannot be used with motion modify.

Both MPIMotionAttrMaskSYNC_START and MPIMotionAttrMaskSYNC_END
With MPIMotionAttrMaskSYNC_START and MPIMotionAttrMaskSYNC_END, the motion for each axis will be scaled so that the motion of all axes will end at approximately the same time. The time for this motion is based on the time for the longest motion, so that the limits are not exceeded. The axes will be scaled to start and stop together, but the scaling may not be exact. Both MPIMotionAttrMaskSYNC_START and MPIMotionAttrMaskSYNC_END cannot be used together with MEIMotionAttrMaskFINAL_VEL.

MPIMotionTypeVELOCITY

MPIMotionTypeVELOCITY moves allow a final velocity to be specified without a final point.

MPIMotionAttrMaskSYNC_START and/or MPIMotionAttrMaskSYNC_END
Neither is supported for this motion type. MPIMotionAttrMaskSYNC_END cannot be used with motion modify.

MEIMotionAttrMaskFINAL_VEL
MEIMotionAttrMaskFINAL_VEL is not supported for this motion type.

MPIMotionAttrMaskRELATIVE
MPIMotionAttrMaskRELATIVE, when used with MPIMotionTypeVELOCITY or MPIMotionTypeVELOCITY_JERK, means that the final velocity is relative to the velocity at the start of the motion.


S-Curve Motion Profiles: Command Acceleration vs. Peak Acceleration

The XMP’s DSP uses a formula to convert the “commanded acceleration” for an S-Curve move to a “peak acceleration.” The DSP calculates the trapezoidal profile first, then adjusts the accel/decel portions of the move based on the “Jerk Percent” parameter, while keeping the move time at a constant value. For example, a 0% jerk would look like a trapezoidal velocity profile (no jerk portion), and a 100% jerk would have no constant accel/decel (all jerks). See the table below.

Changes in Jerk Percent parameter change the
acceleration-deceleration curve characteristics

The conversion formula is:

where,

max_accel is the maximum acceleration (or decel) for a point to point profile accel is the specified acceleration (or decel) from the application code jerk_percent is the specified jerk percentage (0 to 100.0) from the application code.


XMP Servo Algorithms

PID-Based | PIV-Based

PID-Based

PIV-Based

PIV: Block Diagram

For a print-friendly version of the above diagram, click here.

PIV: Position Compensation

For a print-friendly version of the above diagram, click here.

PIV: Velocity Compensation

For a print-friendly version of the above diagram, click here.


How STOP Events work

Resuming Motion after STOP Events

When a motion supervisor sees a STOP event (generated by anything in the domains of motion supervisor’s axes), the Feedrate is changed from NormalFeedrate to PauseFeedrate (MS[n].PauseFeedrate in the firmware). To set the PauseFeedrate , use the method mpiControlMemorySet(...).

How quickly the NormalFeedrate changes to PauseFeedrate is determined by the value of StartStopRate (which is set by motionConfig.decelTime.stop). Normally, PauseFeedrate is 0.0, which causes the motion to stop.

When the motion is re-started (using mpiMotionAction(...,MPIActionRESUME) for STOP events), the Feedrate is changed back to the NormalFeedrate at the StartStopRate rate.
How Motion is Restarted after STOP Events
If Motion was stopped by | Then Motion resumes after
STOP Event | mpiMotionAction(...MPIActionRESUME) is called
PAUSE Event | mpiMotionAction(...MPIActionRESUME) is called
 | the limit (bit) is cleared

Note that STOP events are latched by the firmware, while PAUSE events aren’t. This means that if you configure a user limit to trigger a STOP event when an input (like Xcvr) is set (= 1), the Motion will go from NormalFeedrate to PauseFeedrate when that bit is set, and the Motion will stay at the PauseFeedrate until mpiMotionAction(...,MPIActionRESUME) is called.

If a limit is configured for a PAUSE event, the Motion will resume automatically after the bit is cleared (mpiMotionAction(...,MPIActionRESUME) is not needed).


PIV: Block Diagram

.

PIV: Block Diagram


PIV: Position Compensation

.

PIV: Position Compensation


PIV: Velocity Compensation

.

PIV: Velocity Compensation


MPI Software Documentation Object Home

.

Search by Object
Axis | EventMgr | Path
CAN | Filter | Platform
Capture | Flash | Recorder
Command | Global* | Sequence
Compare | Message* | Service
Control | Motion | SqNode
DriveMap | Motor | SynqNet
Event | Notify | Trace*
EventMask | Object* |
 |  | * - modules
Search by Data Type
Search by Method
Error Messages
For the Analog-XMP documentation (20020117.1.8).
Upgrading Software to SynqNet Phase II


Error Messages / Return Values

.

Error Messages / Return Values

A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z

General Return Values

MPIMessageOK
The operation was successful. This message code is returned by a method when the operation completed successfully. If a message code other than MPIMessageOK is returned by a method, then an error occurred or operation status information is being reported. Check return values from ALL method calls. The only exceptions are methods that return object handles. For example, the mpiObjectCreate(…) methods return a handle to an object.

MPIMessageARG_INVALID
An argument is not valid. This message code is returned by a method when one or more arguments fail an integrity check. The following integrity checks are made, depending on the argument types:
- Pointers and addresses are not NULL.
- Memory addresses are within a valid range.
- Object maps have a valid number of members.

MPIMessagePARAM_INVALID
A parameter is not valid. This message code is returned by a method when one or more parameters fail an integrity check. The following integrity checks are made, depending on the parameter types:
- Pointers and addresses in structures are not NULL.
- Memory addresses in structures are within a valid range.
- Object numbers are within a valid range.
- Values in structures are within a valid range.

MPIMessageHANDLE_INVALID
An object handle is not valid. This message code is returned by a method when the object handle argument is NULL. To correct this problem, create an object using an object create method. For example, to create an axis object use mpiAxisCreate(…).

MPIMessageNO_MEMORY
Memory is not available. This message code is returned by a method when an object, thread or buffer is not created due to a memory allocation failure. All host memory allocation occurs through meiPlatformAlloc(…). To correct this problem, check your host computer resources and remove unused components or add more memory. Note: Some methods may make several memory allocations or may call other methods that allocate memory. If a memory allocation fails, the previous allocations will not be freed.

MPIMessageOBJECT_FREED
The object has been freed. This message code is set within the object when the object is deleted. This message code is used internally. This message code is returned by an object delete method if the object has already been deleted. To prevent this problem, make sure to delete objects only one time.

MPIMessageOBJECT_NOT_ENABLED
The object is not active in the controller. This message code is returned by a method if real-time data or a handshake is required between the MPI and the controller, and the specified object is not enabled in the controller. To correct this problem, use mpiControlConfigSet(…) to enable the object, by setting the object count to greater than the specified object number. For example, to enable motor objects 0 to 3, set motorCount to 4.

MPIMessageOBJECT_NOT_FOUND
The object is not found on an object list. This message code is returned by a method when an object does not exist on the specified list or the object list does not exist. This message code can be returned from methods that insert or remove objects from a list. To correct this problem, specify an object that exists on the list or specify a different object list containing the object. To prevent object creation/deletion problems, delete objects in the reverse order they were created.

MPIMessageOBJECT_ON_LIST
The object is a member of a list. This message code is returned when a method tries to add an object to a list and the object already exists on the list. It is also returned when a method tries to delete an object when the object exists on a list. For example, if an axis object is a member of a list of axis objects or an axis object is associated with a motion object, calling mpiAxisDelete(…) will return the object on list message code. To correct this problem when adding an object to a list, check to make sure the object is not already a member. To correct this problem when deleting an object, remove the object from the list and delete the parent object. To prevent object creation/deletion problems, delete objects in the reverse order they were created.

MPIMessageTIMEOUT
The wait time has expired. This message code is returned by a method waiting for a response from the controller, a hardware resource, or a semaphore lock and the maximum wait time value expired. The library uses timeout values to prevent lock-up conditions when unexpected behavior occurs. To correct this problem, check the hardware health, power, and network connections.

MPIMessageUNSUPPORTED
The software or controller does not support a feature. This message code is returned by a method if the MPI library, controller, or network device does not support a feature.

MPIMessageFATAL_ERROR
The software or hardware failed. This message code is returned by a method when an inexplicable data value is read from the controller or host memory. This message code indicates a serious problem with the host computer, memory, or controller. Contact an MEI applications engineer if you receive this message code.

MPIMessageFILE_CLOSE_ERROR
An error occurred when closing a file. This message code is returned by a method that fails to close a file. Internally, files are closed using meiPlatformClose(…) which makes a platform specific call. File closing errors indicate a missing file, bad file, or other file system problems.

MPIMessageFILE_OPEN_ERROR
An error occurred when opening a file. This message code is returned by a method that fails to open a file. Internally, files are opened using meiPlatformOpen(…) which makes a platform specific call. File opening errors indicate a missing file, bad file, or other file system problems.

MPIMessageFILE_READ_ERROR
An error occurred when reading from a file. This message code is returned by a method that fails to read from a file. Internally, files are read using meiPlatformFileRead(…) which makes a platform specific call. File reading errors indicate a bad file or other file system problems.

MPIMessageFILE_WRITE_ERROR
An error occurred when writing to a file. This message code is returned by a method that fails to write to a file. Internally, files are written using meiPlatformFileWrite(…) which makes a platform specific call. File writing errors indicate a bad file or other file system problems.

Adc

MPIAdcMessageFIRST
First message in list of messages, placeholder only.

MPIAdcMessageADC_INVALID
The ADC number is out of range. This message code is returned by mpiAdcCreate(…) if the ADC number is less than zero or greater than or equal to MEIXmpMAX_ADCs.

Axis

MPIAxisMessageFIRST
First message in list of messages, placeholder only

MPIAxisMessageAXIS_INVALID
The axis number is out of range. This message code is returned by mpiAxisCreate(…) if the axis number is less than zero or greater than or equal to MEIXmpMAX_Axes.

MPIAxisMessageCOMMAND_NOT_SET
The axis command position did not get set. This message code is returned by mpiAxisCommandPositionSet(…) if the controller's command position does not match the specified value. Internally, the mpiAxisCommandPositionSet(…) method requests the controller to change the command position, waits for the controller to process the request, and reads back the controller's command position. There are several cases where the controller will calculate a new command position to replace the requested command position. For example, if motion is in progress, stopped, or if the amp enable is disabled (when the motor's disableAction is configured for command equals actual), the controller will calculate a new command position every sample. To prevent this problem, set the command position when the motion is in an IDLE state and the motor's disableAction is configured for no action.

MPIAxisMessageNOT_MAPPED_TO_MS
An axis is not mapped to the motion supervisor. This message code is returned by mpiMotionDelete(…), mpiMotionAxisList(…), or mpiMotionAxisRemove(…) when an axis is associated with a motion object, but not mapped to a motion supervisor. To correct this problem, map the axes to the motion supervisor in the controller by calling: mpiMotionAction(…) with MEIActionMAP or MPIActionRESET, mpiMotionStart(…), mpiMotionModify(…), or mpiMotionEventNotifySet(…).

CAN

MPICanMessageFIRMWARE_INVALID
The CAN firmware is not valid. This message code is returned by meiCanCreate(…) if the CAN hardware bootloader detects no firmware has been loaded or the firmware signature is not recognized. To correct this problem, download valid firmware with meiCanFirmwareDownload(…).

MPICanMessageFIRMWARE_VERSION
The CAN firmware version does not match the software version. This message code is returned by meiCanCreate(…), meiCanFirmwareDownload(…), or meiCanFirmwareUpload(…) if the CAN firmware version is not compatible with the MPI library. To correct this problem, download the proper firmware version with meiCanFirmwareDownload(…).

MPICanMessageNOT_INITIALISED
The CAN firmware did not initialize. This message code is returned by meiCanCreate(…) if the controller did not copy the configuration structure from flash to memory after power-on or controller reset. To correct this problem, verify the controller firmware is correct and the controller hardware is operating properly.

MPICanMessageIO_NOT_SUPPORTED
The CAN node does not support the specified I/O. This message code is returned by CAN methods that read/write to a digital or analog input/output that is out of range. To prevent this problem, specify a supported I/O bit.

MPICanMessageFILE_FORMAT_ERROR
The CAN firmware file format has an error. This message code is returned by meiCanFirmwareDownload(…) if the specified file has an error in its internal headers. This indicates a corrupted file. To correct this problem, use the original CAN firmware file or reinstall the software distribution.

MPICanMessageUSER_ABORT
The CAN firmware loading was aborted. This message code is returned by meiCanFirmwareDownload(…) or meiCanFirmwareUpload(…) when the firmware loading is aborted by the user via the callback function. This message code is returned for application notification. It is not an error.

MPICanMessageCOMMAND_PROTOCOL
The CAN command failed due to a protocol error. This message code is returned by CAN methods that do not get a valid response from a CAN node. To correct this problem, check your CAN nodes for proper operation.

MPICanMessageINTERFACE_NOT_FOUND
The CAN interface is not available. This message code is returned by meiCanCreate(…) if the specified controller does not support a CAN network interface. To correct this problem, use a controller that has a CAN interface.

MPICanMessageNODE_DEAD
The CAN node does not respond. This message code is returned by CAN methods that read/write from a CAN node and the node fails the health check. This message code indicates a node hardware or network connection problem. To correct this problem, verify the node operation and network connections.

MPICanMessageSDO_TIMEOUT
The CAN command failed due to a timeout. This message code is returned by CAN methods that do not get a response from a CAN node within the timeout period. To correct this problem, check your CAN nodes for proper operation.

MPICanMessageSDO_ABORT
The CAN command failed due to a user abort. This message code is returned by CAN methods when an SDO transaction is aborted.

MPICanMessageSDO_PROTOCOL
The CAN command failed due to an SDO protocol error. This message code is returned by CAN methods when an SDO transaction fails because the node did not conform to the CANOpen protocol.

MPICanMessageTX_OVERFLOW
The controller's transmit buffer overflowed. This message code is returned by CAN methods that failed to transmit a message due to an internal memory buffer overflow.

MPICanMessageRTR_TX_OVERFLOW
The controller's transmit buffer overflowed. This message code is returned by CAN methods that failed to transmit a message due to an internal memory buffer overflow.

MPICanMessageRX_BUFFER_EMPTY
The controller's receive buffer is empty. This message code is returned by CAN methods that expected to get a response from a CAN node, but the controller's receive buffer was empty.

MPICanMessageBUS_OFF
The CAN network bus is in the off state. This message code is returned by CAN methods that are not able to use the CAN network because the bus is off. To correct this problem, verify the node operation and network connections.

Capture

MPICaptureMessageFIRST
First message in list of messages, placeholder only.

MPICaptureMessageCAPTURE_INVALID
The capture number is out of range. This message code is returned by mpiCaptureCreate(…) if the capture number is less than zero or greater than or equal to MEIXmpMaxCapturesPerMotor.

MPICaptureMessageCAPTURE_TYPE_INVALID
mpiCaptureConfigSet(...) --> config.Type = = MPICaptureNOT.MAPPED.

MPICaptureMessageENCODER_INVALID
The encoder index is out of range. This message code is returned by mpiCaptureCreate(…) if the encoder index is less than MPIMotorEncoderFIRST or greater than or equal to MPIMotorEncoderLAST.

MPICaptureMessageMOTOR_INVALID
mpiCaptureConfigSet(...) --> config.captureMotorNumber is not valid. It's either greater than maxMotors or = = MPICaptureNOT.MAPPED.

MEICaptureMessageINVALID_EDGE
The encoder edge trigger type is not valid. This message code is returned by mpiCaptureConfigSet(…) if the encoder capture edge type is not a member of the MPICaptureEdge enumeration.

MEICaptureMessageGLOBAL_CONFIG_ERR
The global trigger configuration is not valid. This message code is returned by mpiCaptureConfigSet(…) if the capture's trigger source is set to global and the capture's global trigger is enabled simultaneously. To correct this problem, either set the capture's trigger source to global or enable the capture's global trigger (not both).

MEICaptureMessageGLOBAL_ALREADY_ENABLED
The global trigger is already enabled. This message code is returned by mpiCaptureConfigSet(…) if a global trigger is already enabled on another capture on the same node. Only one global trigger enable is allowed per node. To prevent this problem, do not enable a second global trigger on a single node.

MEICaptureMessageCAPTURE_NOT_ENABLED
The capture object's hardware resource is not available. This message code is returned by mpiCaptureCreate(…) if the node hardware for the specified motor and encoder is not found. During controller and network initialization the nodes and motor count for each node is discovered and mapped to the controller's motor and capture objects. A capture object cannot be created if there is no mapped hardware to support it. To correct this problem, verify that all expected nodes were found. Use meiSynqNetInfo(…) and meiSqNodeInfo(…) to determine the node topology and motor count per node. Check the node hardware power and network connections.

MEICaptureMessageNOT_MAPPED
The capture object's hardware resource is not available. This message code is returned by mpiCaptureCreate(…) if the node hardware for the specified motor and encoder is not found. During controller and network initialization the nodes and motor count for each node is discovered and mapped to the controller's motor and capture objects. A capture object cannot be created if there is no mapped hardware to support it. To correct this problem, verify that all expected nodes were found. Use meiSynqNetInfo(…) and meiSqNodeInfo(…) to determine the node topology and motor count per node. Check the node hardware power and network connections.

MEICaptureMessageUNSUPPORTED_INDEX_INVALID
This message is returned from MPICaptureConfigSet(...) when the secondary encoder's index is specified as a trigger source in conjunction with other capture sources.

MEICaptureMessageUNSUPPORTED_PRIMARY
The capture hardware does not support the primary encoder. This message code is returned by mpiCaptureCreate(…) if the node hardware's primary encoder does not support the specified capture. To correct this problem, select a different motor, encoder, or capture number.

MEICaptureMessageUNSUPPORTED_SECONDARY
The capture hardware does not support the secondary encoder. This message code is returned by mpiCaptureCreate(…) if the node hardware's secondary encoder does not support the specified capture. To correct this problem, select a different motor, encoder, or capture number.

Client

MEIClientMessageFIRST
First message in list of messages, placeholder only

MEIClientMessageCLIENT_INVALID
Not supported.

MEIClientMessageMETHOD_INVALID
The client method is out of range. This message code is returned by meiClientMethod(…) if the method number is not a member of the MEIRemoteMethod enumeration.

MEIClientMessageHEADER_INVALID
The client packet header is not valid. This message code is returned by meiClientMethod(…) if the packet header is corrupted. This indicates a problem with the message transmission. Check your network hardware.

Command

MPICommandMessageFIRST
First message in list of messages, placeholder only

MEICommandMessageCOMMAND_INVALID
Not supported.

MPICommandMessageTYPE_INVALID
The command type is not valid. This message code is returned by mpiCommandCreate(…) if the command type is not a member of the MPICommandType enumeration.

MPICommandMessagePARAM_INVALID
Not supported.

Compare

MPICompareMessageCOMPARE_INVALID
The Compare handle is invalid.

Control

MPIControlMessageFIRST
First message in list of messages, placeholder only.

MPIControlMessageLIBRARY_VERSION
The MPI Library does not match the application. This message code is returned by mpiControlInit(…) if the MPI's library (DLL) version does not match the MPI header files that were compiled with the application. To correct this problem, the application must be recompiled using the same MPI software installation version that the application uses at run-time.

MPIControlMessageADDRESS_INVALID
The controller address is not valid. This message code is returned by mpiControlInit(…) if the controller address is not within a valid memory range. mpiControlInit(…) only requires memory addresses for certain operating systems. To correct this problem, verify the controller memory address.

MPIControlMessageCONTROL_INVALID
Not supported.

MPIControlMessageCONTROL_NUMBER_INVALID
The controller number is out of range. This message code is returned by mpiControlInit(…) if the controller number is less than zero or greater than or equal to MaxBoards(8).

MPIControlMessageTYPE_INVALID
The controller type is not valid. This message code is returned by mpiControlInit(…) if the controller type is not a member of the MPIControlType enumeration.

MPIControlMessageINTERRUPTS_DISABLED
The controller interrupt is disabled. This message code is returned by mpiControlInterruptWait(…) if the controller's interrupt is not enabled. This prevents an application from waiting for an interrupt that will never be generated. To correct this problem, enable controller interrupts with mpiControlInterruptEnable(…) before waiting for an interrupt.

MPIControlMessageEXTERNAL_MEMORY_OVERFLOW
The controller's external memory will overflow. This message code is returned by mpiControlConfigSet(…) if the dynamic memory allocation exceeds the external memory available on the controller. To correct the problem, reduce the number/size of control configuration resources or use a controller model with a larger static memory component.

MPIControlMessageADC_COUNT_INVALID
The ADC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of ADCs is greater than MEIXmpMAX_ADCs.

MPIControlMessageAXIS_COUNT_INVALID
The axis count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of axes is greater than MEIXmpMAX_Axes.

MPIControlMessageCAPTURE_COUNT_INVALID
The capture count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of captures is greater than MEIXmpMAX_Captures.

MPIControlMessageCOMPARE_COUNT_INVALID
The compare count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of compares is greater than MEIXmpMAX_Compares.

MPIControlMessageCMDDAC_COUNT_INVALID
The command DAC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of command DACs is greater than MEIXmpMAX_DACs.

MPIControlMessageAUXDAC_COUNT_INVALID
The auxiliary DAC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of auxiliary DACs is greater than MEIXmpMAX_DACs.

MPIControlMessageFILTER_COUNT_INVALID
The filter count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of filters is greater than MEIXmpMAX_Filters.

MPIControlMessageMOTION_COUNT_INVALID
The motion count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of motions is greater than MEIXmpMAX_MSs.

MPIControlMessageMOTOR_COUNT_INVALID
The motor count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of motors is greater than MEIXmpMAX_Motors.

MPIControlMessageSAMPLE_RATE_TO_LOW
The controller sample rate is too small. This message code is returned by mpiControlConfigSet(…) if the sample rate is less than 1000. SynqNet does not support cyclic data rates below 1kHz. The controller's sample rate specifies the SynqNet cyclic rate.

MEIControlMessageFIRMWARE_INVALID
The controller firmware is not valid. This message code is returned by mpiControlInit(…) if the MPI library does not recognize the controller signature. After power-up or reset, the controller loads the firmware from flash memory. When the firmware executes, it writes a signature value into external memory. If mpiControlInit(…) does not recognize the signature, then the firmware did not execute properly. To correct this problem, download firmware and verify the controller hardware is working properly.

MEIControlMessageFIRMWARE_VERSION_NONE
The controller firmware version is zero. This message code is returned by control methods do not find a firmware version. This indicates the firmware did not execute at controller power-up or reset. To correct this problem, download firmware and verify the controller hardware is working properly.

MEIControlMessageFIRMWARE_VERSION
The controller firmware version does not match the software version. This message code is returned by control methods if the firmware version is not compatible with the MPI library. To correct this problem, either download compatible firmware or install a compatible MPI run-tim library.

MEIControlMessageFPGA_SOCKETS
The maximum number of FPGA socket types has been exceeded. This message code is returned by meiFlashMemoryFromFile(…) if the controller has more FPGA types than the controller has flash memory space to support them.

MEIControlMessageBAD_FPGA_SOCKET_DATA
Not supported.

MEIControlMessageNO_FPGA_SOCKET
The FPGA socket type does not exist. This message code is returned by meiFlashMemoryFromFile(…) if the controller does not support the FPGA type that was specified in the FPGA image file. To correct this problem, use a different FPGA image that is compatible with the controller.

MEIControlMessageINVALID_BLOCK_COUNT
Not supported.

MEIControlMessageSYNQNET_OBJECTS
Not supported.

MEIControlMessageSYNQNET_STATE
The controller's SynqNet state is not expected. This message code is returned by mpiControlInit(…), mpiControlReset(…) and mpiControlConfigSet(…) if the SynqNet network initialization fails to reach the SYNQ state. To correct this problem, check your node hardware and network connections.

MEIControlMessageIO_BIT_INVALID
The controller I/O bit is not valid. This message code is returned by meiControlIoBitGet(...) or meiControlIoBitSet(…) if the controller I/O bit is not a member of the MEIControlIoBit enumeration.

Element

MEIElementMessageFIRST
Internal

MEIElementMessageELEMENT_INVALID
The element is not valid. This message code is used internally to guarantee an element module and element number are valid.

Event

MPIEventMessageFIRST
First message in list of messages, placeholder only.

MPIEventMessageEVENT_INVALID
The event type is not valid. This message code is returned by mpiEventStatusSet(…) if the event type is not a member of the MPIEventType or MEIEventType enumerations.

EventMgr

MPIEventMgrMessageFIRST
First message in list of messages, placeholder only

MPIEventMgrMessageEVENTMGR_INVALID
Not supported.

Filter

MPIFilterMessageFIRST
First message in list of messages, placeholder only

MPIFilterMessageFILTER_INVALID
The filter number is out of range. This message code is returned by mpiFilterCreate(…) if the filter number is less than zero or greater than or equal to MEIXmpMAX_Filters.

MPIFilterMessageINVALID_ALGORITHM
The filter algorithm is not valid. This message code is returned by mpiFilterIntegratorReset(…) if the filter algorithm is not a member of the MEIXmpAlgorithm enumeration (does not support integrators). This problem occurs if the filter type is set to user or an unknown type with mpiFilterConfigSet(…).

MPIFilterMessageINVALID_DRATE
The filter derivative rate is not valid. This message code is returned by mpiFilterConfigSet(…) if the filter derivative rate is less than 0 or greater than 7. NOTE: The derivative rate for all gain tables must be in the range [0,7], not just the derivative rate for the current gain table.

Flash

MEIFlashMessageFIRST
First message in list of messages, placeholder only

MEIFlashMessageFLASH_INVALID
The flash object is not valid. This message code is returned by meiFlashMemoryFromFile(…), meiFlashMemoryFromFileType(…), meiFlashMemoryToFile(…), or meiFlashMemoryVerify(…) if the flash object's memory cache has not been allocated. The flash memory cache is allocated in mpiFlashCreate(…). To prevent this problem, create flash objects with mpiFlashCreate(…) and check the return value.

MEIFlashMessageFLASH_READ_ERROR
The flash memory read failed. This message code is returned by meiFlashMemoryVerify(…) if the read from flash memory does not match the read from the file. This indicates the specified flash file is different from the flash memory. This message code can also be returned from meiFlashMemoryFromFile(…), since it calls meiFlashMemoryVerify(…). To correct this problem, first check that the specified file is the one you intended. If the specified file is correct, use meiFlashMemoryFromFile(…) to download the file.

MEIFlashMessageFLASH_WRITE_ERROR
The flash memory write failed. This message code is returned by meiFlashMemoryErase(…), meiFlashMemoryFromFile(…), or meiFlashMemoryFromFileType(…) if the flash memory write fails. This indicates a problem in the flash memory component or subsystem.

MEIFlashMessagePATH
The flash file path is too long. This message code is returned by meiFlashMemoryFromFile(…) if the file path is longer than MEIFlashFileMaxPathChars. To correct this problem, use a shorter path.

MEIFlashMessageNETWORK_TOPOLOGY_WARNING
The network topology has not been saved to flash. This message code is returned by object flash config set methods if the network topology has not been previously saved to flash. This message code serves as a warning of a potential safety problem. Saving object configurations to flash will cause those values to be sent to nodes during the next network intialization, even if the flash configurations are not compatible with the network topology. If the network topology is saved to flash, then the controller will automatically verify the topology before sending object configuration values to the nodes. To prevent this message code return, use meiControlTopologyToFlash(…) to save the network topology to the controller's flash. For more information, please see SynqNet Network Topology Verification or Saving Current SynqNet Topology to Flash.

List

MEIListMessageFIRST
First message in list of messages, placeholder only

MEIListMessageLIST_INVALID
List invalid.

MEIFlashMessageELEMENT_NOT_FOUND
The element is not a member of the list. This message code is returned by meiListElement(…) if the index to the list is greater than or equal to the list count. This message code is used by the MPI internally to check object list handling.

MEIFlashMessageELEMENT_INVALID
The element is not valid. This message code is returned by meiListInsertNow(…) or meiListRemoveNow(…) if the element cannot be inserted or removed from the list. This message code is used by the MPI internally to check object list handling.

Map

MEIMapMessageFIRST
First message in list of messages, placeholder only.

MEIMapMessageNAME_INVALID
The map name is not valid. This message code is returned by meiMapNameToParams(…) if the name is not a member of a map.

MEIMapMessageNAME_NOT_FOUND
The map name is not found. This message code is returned by meiMapCreate(…), meiMapNameToParams(…), or meiMapNameParse(…) if the name is not found in the map.

MEIMapMessageINDEX_INVALID
The map index is not valid. This message code is returned by meiMapNameToParams(…) if the map index is less than 0 or greater than or equal to the maximum instance count.

MEIMapMessageFILE_INVALID
The map file is not valid. This message code is returned by meiMapNameParse(…) if the map file cannot be parsed.

Motion

MPIMotionMessageMOTION_INVALID
The motion supervisor number is out of range. This message code is returned by mpiMotionCreate(…) if the motion supervisor number is less than zero or greater than or equal to MEIXmpMAX_MSs.

MPIMotionMessageAXIS_NOT_FOUND
The specified axis object is not available. This message is returned from mpiMotionAxisRemove(…) if the axis that is being removed is not a member of the motion object.

MPIMotionMessageAXIS_COUNT
The number of axes is out of range. This message is returned from mpiMotionConfigSet(…), mpiMotionStart(…), or mpiMotionModify(…) if there are no axes associated with the motion object or if the axis count exceeds MEIXmpMAX_COORD_AXES.

MPIMotionMessageTYPE_INVALID
The motion type or motion attribute is not valid. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) if the motion type or motion attribute mask is not recognized by the library. To correct the problem, select a motion type/attribute from the MPI and/or MEI enumerations.

MPIMotionMessageATTRIBUTE_INVALID
The motion attribute is not valid. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) if the motion attribute mask is not compatible with the specified motion type. To correct the problem, do not use the motion attribute mask with the specified motion type or select a different motion type.

MPIMotionMessageIDLE
All motion supervisor axes are not moving and are ready to move. This message code is returned from mpiMotionModify(…) when the motion supervisor is in the IDLE state. A motion cannot be modified if no motion is in progress. To correct the problem, use the AUTO_START attribute for mpiMotionModify(…) or use mpiMotionStart(…) instead. This message code is also returned from mpiMotionAction(…) when a STOP or RESUME is commanded when the motion supervisor is in the IDLE state. A motion cannot be stopped if there is no motion in progress and a motion cannot be resumed if there is no motion profile pending.

MPIMotionMessageMOVING
At least one motion supervisor axis is moving. This message code is returned from mpiMotionStart(…) when the motion supervisor is in the MOVING state. A motion cannot be started if a motion is in progress. To correct the problem, use mpiMotionModify(…) instead. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the MOVING state. A motion cannot be resumed or reset while a motion is in progress.

MPIMotionMessageSTOPPING
Motion supervisor axes are stopping due to a STOP action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the STOPPING state. A motion cannot be commanded when a stop is in progress. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the STOPPING state. A motion cannot be resumed or reset while a stop is in progress.

MPIMotionMessageSTOPPED
Motion supervisor axes are stopped due to a STOP action. This message code is returned from mpiMotionAction(…) when a STOP action is commanded while the motion supervisor is already in the STOPPED state.

MPIMotionMessageSTOPPING_ERROR
Motion supervisor axes are stopping due to an E_STOP or ABORT action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the STOPPING_ERROR state. A motion cannot be commanded when a stopping on error action is in progress. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the STOPPING state. A motion cannot be resumed or reset while a stopping on error action is in progress.

MPIMotionMessageERROR
Motion supervisor axes are in an error state due to an E_STOP or ABORT action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the ERROR state. A motion cannot be commanded when the motion supervisor is in an error state. This message code is also returned from mpiMotionAction(…) when a STOP or RESUME is commanded when the motion supervisor is in the ERROR state. To correct the problem, fix the condition that caused the E_STOP or ABORT action and then clear the ERROR state using mpiMotionAction(…) with a RESET.

MPIMotionMessageAUTO_START
The motion modify was automatically converted to a motion start. This message code is returned from mpiMotionModify(…) when the AUTO_START attribute mask was specified and the motion was commanded while the motion supervisor is in the IDLE state. This message code is useful for notifying an application of an auto-start, it is not an error condition.

MPIMotionMessagePROFILE_ERROR
The motion profile is not possible with the specified constraints. This message code is returned by mpiMotionModify(…) when the NO_REVERSAL attribute mask is specified, but the specified target position is in the reverse direction. To correct the problem, either remove the NO_REVERSAL constraint or specify a target position that is in the same direction as the motion profile in progress.

MPIMotionMessagePROFILE_ERROR_NOT_SUPPORTED
The controller firmware does not support the specified motion profile type. This message code is returned by mpiMotionStart(…) or mpiMotionModify(…) when an S_CURVE_JERK or VELOCITY_JERK motion type is commanded, but not supported by the controller firmware. Due to programming memory space constraints, specific revisions of controller firmware may not support jerk motion types. To correct the problem, use the S_CURVE or VELOCITY motion instead.

MPIMotionMessagePATH_ERROR
The specified multi-point motion path is not valid. This message code is returned by mpiMotionStart(…) or mpiMotionModify(…) when the final point is not specified or the time slice is less than one controller sample.

MPIMotionMessageFRAMES_LOW
The controller's frame buffer is low. This message code is returned by meiMotionFramesLow(…). This is an internal message code used by the library to manage the frame buffering.

MPIMotionMessageFRAMES_EMPTY
The controller's frame buffer is empty. This message code is returned by meiMotionFramesLow(…). This is an internal message code used by the library to manage the frame buffering.

MEIMotionMessageRESERVED0
Reserved for specialized use.

MEIMotionMessageRESERVED1
Reserved for specialized use.

MEIMotionMessageRESERVED2
Reserved for specialized use.

MEIMotionMessageNO_AXES_MAPPED
The motion object has no axes. This message code is returned by mpiMotionStart(…), mpiMotionModify(…) or mpiMotionAction(…) if there are no axes mapped to the motion object. To correct this problem, make sure there is at least one axis object associated with the motion object before commanding any motion or motion actions.

Motor

MPIMotorMessageFIRST
First message in list of messages, placeholder only.

MPIMotorMessageMOTOR_INVALID
The motor number is out of range. This message code is returned by mpiMotorCreate(…) if the motor number is less than zero or greater than or equal to MEIXmpMAX_Motors.

MEIMotorMessageMOTOR_NOT_ENABLED
The motor number is not active in the controller. This message code is returned by mpiMotorEventConfig(…) if the specified motor is not enabled in the controller. To correct the problem, use mpiControlConfigSet(…) to enable the motor object, by setting the motorCount to greater than the motor number. For example, to enable motor 0 to 3, set motorCount to 4.

MEIMotorMessageSECONDARY_ENCODER_NA
The motor's secondary encoder is not available. This message code is returned by mpiMotorConfigSet(…) or mpiMotorEventConfigSet(…) if the encoder fault trigger is configured for a secondary encoder when the hardware does not support a secondary encoder. To correct the problem, do not select the secondary encoder when configuring the encoder fault conditions.

MEIMotorMessageHARDWARE_NOT_FOUND
The motor object's hardware resource is not available. This message code is returned by mpiMotorConfig(…) if the node hardware for the motor is not found. During controller and network initialization the nodes and motor count for each node is discovered and mapped to the controller's motor objects. An application should not configure a motor object if there is no mapped hardware to receive the service commands. To correct this problem, verify that all expected nodes were found. Use meiSynqNetInfo(…) and meiSqNodeInfo(…) to determine the node topology and motor count per node. Check the node hardware power and network connections.

MEIMotorMessageSTEPPER_INVALID
The motor object stepper configuration is not valid. These message codes are returned by mpiMotorConfig(…) if the motor type is configured for stepper while the disable action is configured for command position equals actual position. The disable action feature sets the command position equal to the actual position when the amp enable signal is set to disable. Stepper motor types are driven by a digital pulse, which is triggered by the controller's command position. Do not use disable action set to command equals actual with stepper motor types.

MEIMotorMessageDISABLE_ACTION_INVALID
The motor object stepper configuration is not valid. These message codes are returned by mpiMotorConfig(…) if the motor type is configured for stepper while the disable action is configured for command position equals actual position. The disable action feature sets the command position equal to the actual position when the amp enable signal is set to disable. Stepper motor types are driven by a digital pulse, which is triggered by the controller's command position. Do not use disable action set to command equals actual with stepper motor types.

Notify

MPINotifyMessageFIRST
First message in list of messages, placeholder only.

MPINotifyMessageNOTIFY_INVALID
The notify object is not valid. This message code is returned by a notify method if the notify object handle is not valid. This problem can be caused by failed mpiNotifyCreate(…). To prevent this problem, check your notify objects after creation by using mpiNotifyValidate(…).

MPINotifyMessageWAIT_IN_PROGRESS
The notify object is waiting for an event. This message code is returned by mpiNotifyEventWait(…) if the notify object is already waiting for an event in another thread. To prevent this problem, make sure a thread does not share notify objects with other threads.

Packet

MEIPacketMessageFIRST
First message in list of messages, placeholder only.

MEIPacketMessagePACKET_INVALID
Not supported.

MEIPacketMessageADDRESS_INVALID
The server socket address is not valid. This message code is returned by mpiControlInit(…) or mpiControlReset(…) if the server name is not specified or the server address is not valid. This message code comes from a lower level routine, meiPacketClient(…). To correct the problem, make sure the server is operational and the server name or address is valid.

MEIPacketMessageCOMM_ERROR
The socket communication failed. This message code is returned by a packet method that fails to send or receive data correctly. This usually indicates a hardware problem. To correct this problem, make sure your network hardware is functioning properly and all network connections are reliable.

MEIPacketMessageCONNECTION_CLOSED
The socket communication connection is closed. This message code is returned by meiPacketRecv(…) or meiPacketSend(…) if zero bytes of data are sent or received. This usually means the socket communication was not opened or was closed. To correct this problem, make sure meiPacketCreate(…) was successful and that another thread did not close the socket connection.

MEIPacketMessageRECV_ERROR
Not supported. See MEIPacketMessageCOMM_ERROR.

MEIPacketMessageSEND_ERROR
Not supported. See MEIPacketMessageCOMM_ERROR.

Path

MPIPathMessageFIRST
First message in list of messages, placeholder only.

MPIPathMessagePATH_INVALID
The path object is not valid. This message code is returned by a path method if the path object handle is not valid. This problem can be caused by a failed mpiPathCreate(…). To prevent this problem, check your path objects after creation by using mpiPathValidate(…).

MPIPathMessageILLEGAL_DIMENSION
The path dimensions are not valid. This message code is returned by mpiPathParamsSet(…) or mpiPathMotionParamsGenerate(…) if the path dimension is less than one or greater than or equal to MPIPathPointDIMENSION_MAX. Also, this message code is returned if specific path element types have dimension restrictions. For example, the ARC type is limited to 2 dimensions and the ARC_END_POINT type is limited to 3 dimensions. To correct this problem, select an appropriate dimension for the path element type.

MPIPathMessageILLEGAL_ELEMENT
The path element type is not valid. This message code is returned by mpiPathAppend(…) if the specified path element type is not a member of the MPIPathElementType enumeration.

MPIPathMessageARC_ILLEGAL_DIMENSION
Illegal arc dimension (too many axes in arc). Arc dimension is out of range. This message code occurs when the specified dimension is out of range. An arc element dimension must be 2.

MPIPathMessageHELIX_ILLEGAL_DIMENSION
Not supported.

MPIPathMessageILLEGAL_RADIUS
The path element arc radius is not valid. This message code is returned by mpiPathAppend(…) if the ARC element radius is less than or equal to zero. To correct this problem, set the arc radius to a value greater than zero.

MPIPathMessagePATH_TOO_LONG
The path length is not valid. This message code is returned by mpiPathMotionParamsGenerate(…) if the path length is greater than MAX_PATH_POINTS. To correct the problem, specify a path with fewer points than MAX_PATH_POINTS.

MPIPathMessageILLEGAL_VELOCITY
The path element velocity is not valid. This message code is returned by mpiPathAppend(…) if the specified velocity is less than or equal to zero. To correct this problem, set the element velocity to a value greater than zero.

MPIPathMessageILLEGAL_ACCELERATION
The path element velocity is not valid. This message code is returned by mpiPathAppend(…) if the specified velocity is less than or equal to zero. To correct this problem, set the element velocity to a value greater than zero.

MPIPathMessageILLEGAL_TIMESLICE
The path element time slice is not valid. This message code is returned by mpiPathAppend(…) if the specified time slice is less than or equal to zero. To correct this problem, set the element time slice to a value greater than zero.

MPIPathMessageINVALID_BLENDING
The path element blending is not valid. This message code is returned by mpiPathMotionParamsGenerate(…) if the element blending is set to TRUE and the motion type does not support blending. To correct this problem, either set the element blending to FALSE or select a different motion type.

Platform

MEIPlatformMessageFIRST
First message in list of messages, placeholder only.

MEIPlatformMessagePLATFORM_INVALID
The platform object is not valid. This message code is returned by a platform method if the platform object handle is not valid. Most applications do not use the platform module. The MPI library uses the platform module internally. If an application needs a platform handle, use meiControlPlatform(…). Do NOT create your own platform object with meiPlatformCreate(…).

MEIPlatformMessageDEVICE_INVALID
The platform device driver is not valid. This message code is returned by mpiControlInit(…) or mpiControlReset(…) if the platform device handle is not valid. This message code comes from the lower level routines, meiPlatformInit(…) or meiPlatformDeviceClose(…). To correct the problem, make sure the device driver is installed and operational.

MEIPlatformMessageDEVICE_ERROR
The platform device failed. This message code is returned by the platform methods that fail to access a controller via a device driver. It occurs if the specified board type is not a member of the MEIPlatformBoardType enumeration. It also occurs if the device driver fails to read/write controller memory or there is an interrupt handling failure. To correct the problem, verify the platform has support for your controller and the device drive is installed and operational. Check for any resource conflicts (memory range, I/O port range, and interrupts) with other devices.

MEIPlatformMessageDEVICE_MAP_ERROR
The platform device memory mapping failed. This message code is returned by mpiControlInit(…) or mpiControlReset(…) if the controller memory could not be mapped to the operating system's memory space. To correct this problem, verify there are no memory resource conflicts. Also, make sure the host computer and operating system have enough free memory for the controller (XMP-Series requires 8 Mbytes).

Recorder

MPIRecorderMessageFIRST
First message in list of messages, placeholder only.

MPIRecorderMessageRECORDER_INVALID
The recorder object is not valid. This message code is returned by a recorder method if the recorder object handle is not valid. This problem can be caused by a failed mpiRecorderCreate(…). To prevent this problem, check your recorder objects after creation by using mpiRecorderValidate(…).

MPIRecorderMessageSTARTED
The data recorder is already running. This message code is returned by mpiRecorderStart(…) if the data recorder has already been started. If this is a problem, call mpiRecorderStop(…) to stop the data recorder or wait for the recorder to collect the number of specified records and stop.

MPIRecorderMessageSTOPPED
The data recorder is not running. This message code is returned by mpiRecorderStop(…) if the data recorder has already been stopped. If this is a problem, call mpiRecorderStart(…) to start the data recorder.

MPIRecorderMessageNOT_CONFIGURED
The data recorder has not been configured. This message code is returned by mpiRecorderRecordGet(…) if the data address count has not been configured. To correct this problem, configure the data recorder with mpiRecorderConfigSet(…).

Sequence

MPISequenceMessageFIRST
First message in list of messages, placeholder only.

MPISequenceMessageSEQUENCE_INVALID
The sequence number is out of range. This message code is returned by mpiSequenceCreate(…) if the sequence number is less than zero or greater than or equal to MEIXmpMAX_PSs. This message code is also returned if the specified sequence number is not active in the controller. To correct this problem, use mpiControlConfigSet(…) to enable the sequence object, by setting the sequenceCount to greater than the sequence number. For example, to enable sequence 0 to 3, set sequenceCount to 4. This message code is returned by mpiSequenceLoad(…) if the sequence buffer size and the sequence page size are not equal. This indicates an internal MPI Library problem.

MPISequenceMessageCOMMAND_COUNT
The sequence command count is out of range. This message code is returned by mpiSequenceStart(…) or meiSequenceCompile(…) if the sequence command count is less than or equal to zero. To correct this problem, set the command count to a value greater than zero.

MPISequenceMessageCOMMAND_NOT_FOUND
The sequence command is not found. This message code is returned by mpiSequenceLoad(…), mpiSequenceStart(…), or meiSequenceCompile(…) if the specified command is not a member of the sequence. To correct this problem, specify a command that is a member of the sequence.

MPISequenceMessageSTARTED
The program sequencer is already running. This message code is returned by mpiSequenceResume(…), mpiSequenceStart(…), or mpiSequenceStep(…) if the program sequencer has already been started. If this is a problem, call mpiSequenceStop(…) to stop the program sequencer or monitor the sequence status and wait for the state to equal STOPPED.

MPISequenceMessageSTOPPED
The program sequencer is not running. This message code is returned by mpiSequenceStop(…) if the program sequencer has already been stopped. If this is a problem, call mpiSequenceStart(…) to start the program sequencer.

Server

MEIServerMessageFIRST
First message in list of messages, placeholder only.

MEIServerMessageSERVER_INVALID
Not supported.

MEIServerMessageMETHOD_INVALID
The server method is out of range. This message code is returned by meiServerMethod(…) if the method number is not a member of the MEIRemoteMethod enumeration.

MEIServerMessageHEADER_INVALID
The server packet header is not valid. This message code is returned by meiServerMethod(…) if the packet header is corrupted. This indicates a problem with the message transmission. Check your network hardware.

SqNode

MEISqNodeMessageFIRST
First message in list of messages, placeholder only.

MEISqNodeMessageINVALID
The SqNode type is out of range. This message code is returned by SynqNet node methods if the node type is not a member of the SQNodeLibNodeType enumeration.

MEISqNodeMessageCONFIG_FILE_FORMAT_INVALID
A file with an incorrect format was used in meiSqNodeDriveMapParamFileSet.

MEISqNodeMessageMAP_CONFIG_FILE
The parameter name or number specified in meiSqNodeDriveMapParamFileSet was not found.

MEISqNodeMessageMAP_CONFIG_MISMATCH
The parameter name or number specified in meiSqNodeDriveMapParamFileSet was not valid for the specified drive.

MEISqNodeMessageMAP_NETWORK_MISMATCH
The type of map file specified in meiSqNodeDriveParamFileSet does not match the type of drive found on the network.

SynqNet

MEISynqNetMessageFIRST
First message in list of messages, placeholder only.

MEISynqNetMessageSYNQNET_INVALID
The SynqNet number is out of range. This message code is returned by meiSynqNetCreate(…) if the SynqNet network number is less than zero or greater than or equal to MEIXmpMaxSynqNets.

MEISynqNetMessageMAX_NODE_ERROR
The SynqNet node number is out of range. This message code is returned by a SynqNet method if the specified node number is greater than or equal to MEIXmpMaxSynqNetBlocks.

MEISynqNetMessageSTATE_ERROR
The SynqNet network state is not valid. This message code is returned by any method that initializes a SynqNet network if the controller's network state is not a member of the MEIXmpSynqNetState or MEIXmpSynqNetInternalState enumeration. The most commonly used methods that initialize the SynqNet network are: mpiControlInit(…), mpiControlReset(…) and meiSynqNetInit(…). This message code indicates a failure in the controller's initialization sequence. To correct this problem, call mpiControlReset(…).

MEISynqNetMessageCOMM_ERROR
The SynqNet network communication failed. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_CRC
The SynqNet network communication failed due to excessive CRC errors. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_RX
The SynqNet network communication failed due to a Rincon receive error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_RX_LEN
The SynqNet network communication failed due to a Rincon receive length error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_RX_FIFO
The SynqNet network communication failed due to a Rincon receive buffer error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_RX_DRIBBLE
The SynqNet network communication failed due to a Rincon receive dribble error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageCOMM_ERROR_RX_CRC
The SynqNet network communication failed due to a Rincon receive CRC error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageINTERFACE_NOT_FOUND
The controller does not support a SynqNet interface. This message code is returned by meiSynqNetValidate(…), meiSynqNetTopologySave(…), meiSynqNetTopologyClear(…), mpiControlInit(…), and mpiControlReset(…) if the controller does not have a SynqNet hardware interface. To correct this problem, use a controller that supports SynqNet.

MEISynqNetMessageTOPOLOGY_MISMATCH
The network topology does not match the expected network topology. This message code is returned by mpiControlInit(…) or meiSynqNetInit(…) if the discovered network topology does not match the controller's expected network topology (stored in dynamic memory). During the first network initialization the controller stores node identification information (manufacturer, product, and unique values) into it's dynamic memory. This message code indicates the number of nodes, the node order, or types of nodes have changed since the initial network initialization. To correct this problem, either change the network topology to the original configuration or clear the controller's memory with mpiControlReset(…).

MEISynqNetMessageTOPOLOGY_MISMATCH_FLASH
The network topology does not match the expected network topology. This message code is returned by mpiControlInit(…) or meiSynqNetInit(…) if the discovered network topology does not match the controller's expected network topology (stored in flash memory). During the first network initialization the controller stores node identification information (manufacturer, product, and unique values) into it's dynamic memory. Later, when meiSynqNetTopologySave(…) is called the topology information is stored into flash memory. This message indicates the number of nodes, the node order, or types of nodes have changed since the topology information was stored in flash. To correct this problem, either change the network topology to the saved configuration or clear the controller's flash topology with meiSynqNetTopologyClear(…).

MEISynqNetMessageRESET_REQ_TIMEOUT
The network reset request packet exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiSynqNetInit(…) if the reset request packet fails to traverse the network in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageRESET_ACK_TIMEOUT
The network reset complete packet exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiSynqNetInit(…) if the reset complete packet fails to traverse the network in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageDISCOVERY_TIMEOUT
The network topology discovery exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiSynqNetInit(…) if the controller failed to discover the network topology in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageNO_NODES_FOUND
The controller did not find network nodes. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiSynqNetInit(…) if the controller failed to discover any nodes during network initialization. This message code indicates the first node has failed or the network connection from the controller to the first node is faulty. To correct this problem, check your network wiring and node condition.

MEISynqNetMessageNODE_UNAVAILABLE
The node number is not available on the network. This message code is returned by MPI methods that fail a service command transaction due to the specified node number is greater than or equal to the total number of nodes discovered during network initialization. To correct this problem, check the discovered node count with meiSynqNetInfo(…). If the node count is not what you expected check your network wiring, node condition, and re-initialize the network with mpiControlReset(…).

MEISynqNetMessageNO_TIMING_DATA_AVAIL
The corresponding SynqNet node module does not contain timing data, so the network cannot be initialized. Contact MEI or drive manufacturer for an updated node module.

MEISynqNetMessageRESPONSE_TIMEOUT
The node failed to respond to a service command within the timeout. This message code is returned by MPI methods that fail a service command transaction because the node failed to respond within the allotted amount of time. To correct this problem, check your node hardware. There are 32 possible message codes for this error. Each message code specifies a different node, from node number 0 to 31.

MEISynqNetMessageREADY_TIMEOUT
The node failed to be ready for a service command within the timeout. This message code is returned by MPI methods that fail a service command transaction because the node is not ready to accept service commands. To correct this problem, check your node hardware. There are 32 possible message codes for this error. Each message code specifies a different node, from node number 0 to 31.

MEISynqNetMessageSRVC_ERROR
The service command failed. This message code is returned by MPI methods that fail a service command transaction. To correct this problem, check your node hardware. There are 32 possible message codes for this error. Each message code specifies a different node, from node number 0 to 31.

MEISynqNetMessageSRVC_UNSUPPORTED
The node does not support the service command. This message code is returned by MPI methods that fail a service command transaction because the node does not support it. Contact MEI or the node manufacturer for updated software or firmware to correct this problem. There are 32 possible message codes for this error. Each message code specifies a different node, from node number 0 to 31.

MEISynqNetMessageINTERNAL_BUFFER_OVERFLOW
The controller's SynqNet buffer size was exceeded. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiControlInit(…) if the controller's SynqNet buffer could not be allocated due to overflow. This message code indicates the controller does not have enough memory to initialize the network topology. To correct the problem, either reduce the network nodes or use a different controller model.

MEISynqNetMessageINVALID_MOTOR_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more motors than supported by the node.

MEISynqNetMessageINVALID_AUX_ENC_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more secondary encoders than supported by the node.

MEISynqNetMessageINCOMPLETE_MOTOR
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a motor configuration that is missing feedback or command fields.

MEISynqNetMessageINVALID_COMMAND_CFG
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a different command configuration than is supported by the node.

MEISynqNetMessageINVALID_ENCODER_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more encoders than supported by the node.

MEISynqNetMessageINVALID_CAPTURE_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger capture count than is supported by the node.

MEISynqNetMessageINVALID_COMPARE_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger compare count than is supported by the node.

MEISynqNetMessageINVALID_INPUT_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger ioInput count than is supported by the node.

MEISynqNetMessageINVALID_OUTPUT_COUNT
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger ioOutput count than is supported by the node.

MEISynqNetMessageINVALID_MONITOR_CFG
This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more monitor fields than the node can support.

MEISynqNetMessageLINK_NOT_IDLE
This message is returned by meiSynqNetIdleCableStatus(...) when the cable number supplied is not the idle link. The status check can only be run on an idle cable. See meiSynqNetIdleCableListGet(…).

MEISynqNetMessageIDLE_LINK_UNKNOWN
This message is returned by meiSynqNetIdleCableListGet (...) when an idle cable number in a ring topology cannot be determined. This is due to one or more failed nodes on a ring topology. Be sure to check the status of the nodes.

MEISynqNetMessageRECOVERING
The network is recovering from a fault condition. This message is returned by meiSynqNetIdleCableStatus(...) during network fault recovery, because the network traffic is being redirected around the faulted cable and a new idle cable is in the process of being assigned. If you receive this message, wait for recovery to complete and then check the identity of the idle cable with meiSynqNetIdleCableListGet(…).

MEISynqNetMessageRING_ONLY
This message is returned by meiSynqNetIdleCableListGet (...) and meiSynqNetIdleCableStatus(…) because idle cables exist on ring topologies only. It is also returned by meiSynqNetConfigSet(...) when attempting to enable SynqNet recovery mode, which is only supported for ring topologies.

MEISynqNetMessageCABLE_LENGTH_UNSUPPORTED
This message is returned when a cable on the network is too long.

MEISynqNetMessageCABLE_LENGTH_MISMATCH
This message is returned at network initialization when topology has been saved to flash and a cable length is detected that lies outside the MEISynqNetConfig.cableLength[n].minimum and maximum. Check cable length (if necessary) and save new cable length values to flash.

MEISynqNetMessageCABLE_LENGTH_INVALID_NOMINAL
The nominal cable length is too long.

MEISynqNetMessageCABLE_LENGTH_INVALID_MIN
The minimum cable length is too long or exceeds nominal value.

MEISynqNetMessageCABLE_LENGTH_INVALID_MAX
The maximum cable length is too long or is less than nominal value.

MEISynqNetMessageNODE_FPGA_VERSION
The node FGPA version is out of date. Use sqNodeFlash.exe to load most current FPGA version to node.

MEISynqNetMessageMAX_MOTOR_ERROR
The number of motors on the network exceeds the number set by MEISynqNetMaxMOTORS.

MEISynqNetMessagePLL_ERROR
The node PLL is unable to lock with drive.


MPI Software Documentation Data Type Home

.

Search by Object

ex: "MPIMotorEventConfig"

Step 1
 Step 2

Search by Data Type
Search by Method
Error Messages


MPI Software Documentation Method Home

.

Search by Object

ex: "mpiAxisConfigSet"

Step 1
 Step 2

Search by Data Type
Search by Method
Error Messages


Axis Objects

.

Axis Objects

Introduction

An Axis object manages a single physical axis on a motion controller. It represents a reference line in a coordinate system. The controller calculates an axis's command position every sample based on the motion commanded by the Motion Supervisor. The Axis object contains command, actual, and error position data, plus status.

An Axis can have one or more Filters associated with it and each Filter can have one or more Motors associated with it. The Filter and Motor objects ensure the Axis command path is followed and that the control signals get to the correct motor. Complex mechanical systems with two (or more) motors can be mapped to a single axis of motion, abstracting the details of the physical hardware and making motion software much easier to develop.

For simple systems, there is a one to one relationship between the Axis, Filter and Motor objects.

Methods

Create, Delete, Validate Methods
 | mpiAxisCreate | Create Axis object
 | mpiAxisDelete | Delete Axis object
 | mpiAxisValidate | Validate Axis object

Configuration and Information Methods
 | mpiAxisActualPositionGet | Get actual position
 | mpiAxisActualPositionSet | Set actual position
 | mpiAxisActualVelocity | Get actual velocity
 | mpiAxisConfigGet | Get Axis configuration
 | mpiAxisConfigSet | Set Axis configuration
 | mpiAxisCommandPositionGet | Get command position
 | mpiAxisCommandPositionSet | Set command position
 | mpiAxisFlashConfigGet | Get Axis flash config
 | mpiAxisFlashConfigSet | Set Axis flash config
 | mpiAxisOriginGet | Get Axis origin
 | mpiAxisOriginSet | Set Axis origin
 | mpiAxisPositionError | Get position error of an Axis
 | mpiAxisStatus | Get Axis status
 | mpiAxisTrajectory | Get Axis trajectory

Event Methods
 | mpiAxis EventNotifyGet | Get event mask
 | mpiAxis EventNotifySet | Set event mask
 | mpiAxis EventReset |

Memory Methods
 | mpiAxisMemory | Set Axis memory address
 | mpiAxisMemoryGet | Copy bytes of Axis memory to application memory
 | mpiAxisMemorySet | Copy bytes of application memory to Axis memory

Relational Methods
 | mpiAxisControl | Return handle of Control associated with Axis
 | mpiAxisFilterMapGet | Get object map of Filters
 | mpiAxisFilterMapSet | Set object map of Filters
 | mpiAxisMotorMapGet | Get object map of Motors
 | mpiAxisNumber | Get index of Axis

Data Types

MPIAxisConfig / MEIAxisConfig
MPIAxisInPosition
MPIAxisMessage


MPIAxisConfig / MEIAxisConfig

MPIAxisConfig

typedef struct MPIAxisConfig {
    MPIAxisInPosition    inPosition;
    MPIObjectMap         filterMap;
}MPIAxisConfig;

Description
 | inPosition | See MPIAxisInPosition.
 | filterMap | bitmap indicating which Filter objects are mapped to the Axis. See MPIObject for more details.

MEIAxisConfig

typedef struct MEIAxisConfig {
    MEIXmpAPosInput	   APos [MEIXmpAxisAPosInputs];
    MEIXmpAxisFilter       Filter;
    MEIXmpAxisGear         Gear;
}MEIAxisConfig;
Description
APos - an array of structures that set Actual position inputs. The structure has two elements:
  • Ptr - Pointer to Actual position input register. Default value is corresponding encoder input.
  • Coeff - Value of Actual position input register
Filter
  • Input
  • Output
  • Delta
  • Delay
  • Timer
  • Pointer
Gear - Coefficients for gearing off a position input
  • Ptr - Host pointer to a gear master

Example:
MEIXmpData           *firmware;
MEIXmpBufferData   *bufferData;

mpiControlMemory(control,&firmware,&bufferData);
...
msgCHECK(mpiAxisConfigGet(axis, &axisConfig, &axisConfigXmp));
axisConfigXmp.Gear.Ptr = &bufferData->PreFilter[0].Output;
                    msgCHECK(mpiAxisConfigSet(axis, &axisConfig, &axisConfigXmp));

  • Ratio.A - numerator of multiplier
  • Ratio.B - denominator of multiplier
  • Ratio.Old -
  • Ratio.Remainder -
  • Position - final geared position

See Also | mpiAxisConfigGet | mpiAxisConfigSet | MPIAxisInPosition | MPIObject


MPIAxisInPosition

MPIAxisInPosition

typedef struct MPIAxisInPosition {
    struct {
        float   positionFine;
        long    positionCoarse;
        float   velocity;
    } tolerance;
        float   settlingTime;  /* seconds */
        long    settleOnStop;
        long    settleOnEstop
        long    settleOnEstopCmdEqAct;
} MPIAxisInPosition;
Description
tolerance | Includes the following 3 elements that determine settling tolerances for an axis.
positionFine | Value, in counts, from the move target position at which the controller sets the "in fine position" status flag. This parameter is used as part of the Axis settling criteria to determine when a point-to-point motion is complete and when MPIEventTypeMOTION_DONE and MEIEventTypeSETTLEDevents are generated.
positionCoarse | Value, in counts, from a move target position at which the controller sets the "in coarse position" status flag. This value does not affect the settling time status.
velocity

Value, in counts/second, from the final move velocity at which the controller sets the "at velocity" status flag. This parameter is used as part of the Axis settling criteria to determine when:

- a position-based move is complete and an MPIEventTypeMOTION_DONE event is generated

- a velocity move is complete and an MPIEventTypeMOTION_AT_VELOCITY event is generated

- an axis is settled and an MPIEventTypeSETTLED event is generated
settlingTime | Duration in seconds that an axis must satisfy the positionFine and/or velocity tolerance, before the respective status flag is set.
settleOnStop

If TRUE, the controller will use settle on stop mode. If FALSE, the controller will not use the settle on stop mode.

When in settleOnStop mode and a STOP event has occurred, the axis will stay in an MPIStateSTOPPING state until:

1. The settling criteria are satisfied AND

2. The stop duration for the axis' Motion Supervisor has elapsed.

3. This state can be read with mpiAxisStatus(MPIAxis axis, MPIStatus *status, void *external).

The value to look for is (MPIState) status.state. If settleOnStop = FALSE, the axis will stay in an MPIStateSTOPPING state only until the stop duration for the axis' Motion Supervisor has elapsed.
settleOnEstop

If TRUE, the controller will use settle on Estop mode. If FALSE, the controller will not use the settle on Estop mode.

When in settleOnEstop mode and a ESTOP event has occurred, the axis will stay in an MPIStateSTOPPING_ERROR state until:

1. The settling criteria are satisfied AND

2. The Estop duration for the axis' Motion Supervisor has elapsed.

3. This state can be read with mpiAxisStatus(MPIAxis axis, MPIStatus *status, void *external).

The value to look for is (MPIState) status.state. If settleOnEStop = FALSE, the axis will stay in an MPIStateSTOPPING_ERROR state only until the Estop duration for the axis' Motion Supervisor has elapsed.
settleOnEstopCmdEqAct

If TRUE, the controller will use settle on EstopCmdEqAct mode. If FALSE, the controller will not use the settle on EstopCmdEqAct mode.

***settleOnEstopCmdEqAct mode is not recommended***

SettleOnEstopCmdEqAct is an alternative to Estop mode. When this mode is enabled, the following things happen:

- During normal motion, there is no difference.

- During an Estop, Cmd Eq Act action, the command position is set equal to the actual position from the previous servo sample. This can have a damping effect in some systems with some tuning parameters, causing the stage to slow. The behavior of the stage in this mode can be vastly different than in normal servoing mode. Approach this mode with great caution. The axis will stay in this mode for the amount of time that the Axis' Motion Supervisor Estop time.

- After the Estop time elapses, the axis' motors will disable the amplifiers.
Sample Code

/*
    Set the settling time of an axis.  Sample usage:
    returnValue =
        setAxisSettlingTime(axis, 0.05);
*/
long setAxisSettlingTime(MPIAxis axis, double settlingTime)
{
    MPIAxisConfig config;
    long returnValue;

    returnValue =
        mpiAxisConfigGet(axis, &config, NULL);

    if (returnValue == MPIMessageOK)
    {
        config.inPosition.settlingTime = (float) settlingTime;
        returnValue =
            mpiAxisConfigSet(axis, &config, NULL);
}

    return returnValue;
}
See Also

MPIAxisConfig | MPIAction

Axis Tolerances and How Motion Related Events are Generated
How Motion Completion Events are Generated

Special Note on Configuration of IN_POSITION and Done Events after STOP or E_STOP Events


MPIAxisMessage

MPIAxisMessage

typedef enum {
    MPIAxisMessageAXIS_INVALID,
    MPIAxisMessageCOMMAND_NOT_SET,
    MPIAxisMessageNOT_MAPPED_TO_MS,
}MPIAxisMessage;
Description

AxisMessage is an enumeration of Axis error messages that can be returned by the MPI library.

MPIAxisMessageAXIS_INVALID
 | The axis number is out of range. This message code is returned by mpiAxisCreate(…) if the axis number is less than zero or greater than or equal to MEIXmpMAX_Axes.
MPIAxisMessageCOMMAND_NOT_SET
 | The axis command position did not get set. This message code is returned by mpiAxisCommandPositionSet(…) if the controller's command position does not match the specified value. Internally, the mpiAxisCommandPositionSet(…) method requests the controller to change the command position, waits for the controller to process the request, and reads back the controller's command position. There are several cases where the controller will calculate a new command position to replace the requested command position. For example, if motion is in progress, stopped, or if the amp enable is disabled (when the motor's disableAction is configured for command equals actual), the controller will calculate a new command position every sample. To prevent this problem, set the command position when the motion is in an IDLE state and the motor's disableAction is configured for no action.
MPIAxisMessageNOT_MAPPED_TO_MS
 | An axis is not mapped to the motion supervisor. This message code is returned by mpiMotionDelete(…), mpiMotionAxisList(…), or mpiMotionAxisRemove(…) when an axis is associated with a motion object, but not mapped to a motion supervisor. To correct this problem, map the axes to the motion supervisor in the controller by calling: mpiMotionAction(…) with MEIActionMAP or MPIActionRESET, mpiMotionStart(…), mpiMotionModify(…), or mpiMotionEventNotifySet(…).
See Also


mpiAxisActualPositionGet

Declaration
long mpiAxisActualPositionGet(MPIAxis  axis,
                              double   *actual)
Required Header stdmpi.h
Description
axis | a handle to an Axis object
*actual | a pointer to the Axis actual position returned by the method.
Return Values
MPIMessageOK if AxisActualPositionGet successfully gets and writes the value of the actual postion of axis to the location.
See Also | mpiAxisActualPositionSet | Using the Origin Variable


mpiAxisActualPositionSet

Declaration
long mpiAxisActualPositionSet(MPIAxis  axis,
                              double   actual)
Required Header stdmpi.h
Description AxisActualPositionSet sets the value of the actual position of an Axis (axis) to actual.
axis | a handle to the Axis object
actual | value to which the Axis actual position will be set
Return Values
MPIMessageOK if AxisActualPositionSet successfully sets the value of the actual postion of an Axis to actual
See Also | AxisCommandPositionSet | Using the Origin Variable


mpiAxisActualVelocity

Declaration
long mpiAxisActualVelocity(MPIAxis   axis,
                           double    *actual)
Required Header stdmpi.h
Description AxisActualVelocity reads the value of the actual velocity (in counts per servo sample) on an Axis (axis) and writes it in the location pointed to by actual.
Return Values
MPIMessageOK if AxisActualVelocity succesfully gets and writes the value of the actual velocity of axis to the location.
See Also


mpiAxisConfigGet

Declaration
long mpiAxisConfigGet(MPIAxis       axis,
                      MPIAxisConfig *config,
                      void          *external)
Required Header stdmpi.h
Description

AxisConfigGet gets the configuration of an Axis (axis) and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

axis | a handle to the Axis object
*config | pointer to the MPIAxisConfig structure
*external | pointer to an external. See remarks below

Remarks
 | For XMP controllers, external either points to a structure of type MEIAxisConfig{} or is NULL.
Return Values
MPIMessageOK if AxisConfigGet successfully gets the Axis configuration and writes it into the structure(s)
See Also | MPIAxisConfig | mpiAxisConfigSet | MEIAxisConfig


mpiAxisConfigSet

Declaration
long mpiAxisConfigSet(MPIAxis       axis,
                      MPIAxisConfig *config,
                      void          *external)
Required Header stdmpi.h
Description

AxisConfigSet sets the configuration of an Axis (axis) using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

axis | a handle to the Axis object
*config | pointer to an MPIAxisConfig structure.
*external | pointer to an external. See remarks below.
XMP Only
 external either points to a structure of type MEIAxisConfig{} or is NULL.
Return Values
MPIMessageOK if AxisConfigSet successfully sets the Axis configuration
See Also | mpiAxisConfigGet | MEIAdcConfig | MEIAxisConfig


mpiAxisCommandPositionGet

Declaration
long mpiAxisCommandPositionGet(MPIAxis axis,
                               double  *command)
Required Header stdmpi.h
Description

AxisCommandPositionGet gets the value of the command position of an Axis (axis) and puts it in the location pointed to by command.

axis | a handle to the Axis object
*command | a pointer to the Axis command position returned by the method
Return Values
MPIMessageOK if AxisCommandPositionGet successfully gets the value of the command position of axis and puts it in the location
See Also | mpiAxisCommandPositionSet


mpiAxisCommandPositionSet

Declaration
long mpiAxisCommandPositionSet(MPIAxis  axis,
                               double   command)
Required Header stdmpi.h
Description

AxisCommandPositionSet sets the value of the command position of an Axis (axis) from command.

axis | a handle to the Axis object
command | value to which the Actual command position will be set

Remarks
Setting the Axis Command Position may cause the axis to jump. See the discussion of the Axis Origin before using the AxisActualPositionSet and AxisCommandPositionSet methods.
Return Values
MPIMessageOK if AxisCommandPositionSet successfully sets the value of the command position of axis from command
Axis: unable to set command position

Indicates that the motor associated to this axis is configured to mode MEIMotorDisableActionCMD_EQ_ACT and the motor is disabled. When the motor is disabled and in the MEIMotorDisableActionCMD_EQ_ACT mode, the command position is continually set to the actual position.

To set the command position, enable the motor or take the motor out of the MEIMotorDisableActionCMD_EQ_ACT mode.

Alternatively, setting the origin for the motor can often perform an equivalent result in this situation, as the command position will be set to the actual position the next sample.

See Also


mpiAxisControl

Declaration
MPIControl mpiAxisControl(MPIAxis  axis)
Required Header stdmpi.h
Description

AxisControl returns a handle to the motion controller (Control) with which an Axis (axis) is associated.
axis a handle to the Axis object
Return Values
MPIHandleVOID if axis is invalid
See Also


mpiAxisCreate

Declaration
MPIAxis MPIAxis mpiAxisCreate(MPIControl  control,
                              long        number)
Required Header stdmpi.h
Description

AxisCreate creates an axis object associated with the axis identified by number located on motion controller control. AxisCreate is the equivalent of a C++ constructor.

control | a handle to Axis object.
number | the number specifies which Axis object is being created. The number corresponds to an Axis object in XMP memory.

Remarks
 | An Axis represents a physical axis in space such as X, Y, Z, Theta, or other axes. An Axis may be comprised of one or more motors, such as with a gantry system.

Return Values
handle | to an Axis object
MPIHandleVOID | if the object could not be created

See Also | mpiAxisDelete | mpiAxisValidate


mpiAxisDelete

Declaration
long mpiAxisDelete(MPIAxis  axis)
Required Header stdmpi.h
Description

AxisDelete deletes an Axis object and invalidates its handle (axis).
AxisDelete is the equivalent of a C++ destructor.

axis | the Axis handle to be deleted

Remarks
All objects that are created in an application should be deleted in reverse order at the end of the code.
Return Values
MPIMessageOK if AxisDelete successfully deletes an Axis object and invalidates its handle
See Also | mpiAxisCreate | mpiAxisValidate


mpiAxisEventNotifyGet

Declaration
long mpiAxisEventNotifyGet(MPIAxis        axis,
                           MPIEventMask   *eventMask,
                           void           *external)
Required Header stdmpi.h
Description

AxisEventNotifyGet writes the event mask (that specifies the event type(s) for which host notification has been requested) to the location pointed to by eventMask, and also writes it into the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventMask, i.e, the event notification information in eventMask and in external is not the same information. Note that eventMask or external can be NULL (but not both NULL).

axis | a handle to the Axis object
*eventMask | pointer to an MPIEventMask
*external | pointer to an external. See remarks below
XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL.

The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).

Return Values
MPIMessageOK if AxisEventNotifyGet successfully writes the event mask to the location(s)
See Also | MEIEventNotifyData | MEIEventStatusInfo | mpiAxisEventNotifySet


mpiAxisEventNotifySet

Declaration
long mpiAxisEventNotifySet(MPIAxis       axis,
                           MPIEventMask  eventMask,
                           void          *external)
Required Header stdmpi.h
Description

AxisEventNotifySet requests host notification of the event(s) that are generated by axis and specified by eventMask, and also specified by the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventMask, i.e, the event notification information in eventMask and in external is not the same information. Note that eventMask or external can be NULL (but not both NULL).

axis | a handle to the Axis object
eventMask | pointer to an MPIEventMask
*external | pointer to an external
XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL.

The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).

To... | Then...
enable host notification of all events | configure eventmask with mpiEventMaskALL(eventMask)
disable host notification of all events | configure eventmask with mpiEventMaskCLEAR(eventMask)
Return Values
MPIMessageOK if AxisEventNotifySet successfully requests host notification of the event(s) that are specified by eventMask and generated by motion
See Also | MEIEventNotifyData | MEIEventStatusInfo | MPIEventMask | MPIEventType | mpiEventMaskALL | mpiEventMaskCLEAR | mpiAxisEventNotifyGet | MEIEventNotifyData


mpiAxisEventReset

Declaration
long mpiAxisEventReset(MPIAxis      axis,
                       MPIEventMask eventMask)
Required Header stdmpi.h
Description

To... | Then...
enable host notification of all events | configure eventmask with mpiEventMaskALL(eventMask)
disable host notification of all events | configure eventmask with mpiEventMaskCLEAR(eventMask)
Return Values
MPIMessageOK if AxisEventNotifySet successfully requests host notification of the event(s) that are specified by eventMask and generated by motion
Remarks

Event notification is enabled for event types specified in eventMask, a bit mask generated by the logical OR of the MPIEventMask bits associated with the desired MPIEventType values. Configuration of the eventMask should be done with Event macros. Event notification is disabled for event types that are not specified in eventMask.

The mask of event types generated by a Motion object consists of bits from MPIEventMaskMOTION and MPIEventMaskAXIS.

See Also
MEIEventNotifyData | MEIEventStatusInfo | MPIEventType | mpiEventMaskALL
mpiEventMaskCLEAR | MPIEventMaskMOTION | MPIEventMaskAXIS | MPIEventMask


mpiAxisFlashConfigGet

Declaration
long mpiAxisFlashConfigGet(MPIAxis       axis,
                           void          *flash,
                           MPIAxisConfig *config,
                           void          *external)
Required Header stdmpi.h
Description

AxisFlashConfigGet gets the flash configuration for an Axis (axis) and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by sexternal (if external is not NULL).

The Axis flash configuration information in external is in addition to the Axis flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

axis | a handle to the Axis object
*flash |
*config | pointer to an MPIAxisConfig structure
*external | pointer to an external. See remarks below.
Remarks
 | For XMP controllers, external either points to a structure of type MEIAxisConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
Return Values
MPIMessageOK if AxisEventNotifySet successfully requests host notification of the event(s) that are specified by eventMask and generated by motion
See Also | MEIFlash | mpiAxisFlashConfigSet |MEIAxisConfig


mpiAxisFlashConfigSet

Declaration
long mpiAxisFlashConfigSet(MPIAxis        axis,
                           void           *flash,
                           MPIAxisConfig  *config,
                           void           *external)
Required Header stdmpi.h
Description

AxisFlashConfigSet sets the flash configuration for for an Axis (axis) using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Axis flash configuration information in external is in addition to the Axis flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

axis | a handle to the Axis object
*flash |
*config | pointer to an MPIAxisConfig structure
*external | pointer to an external. See remarks below.
XMP Only

external either points to a structure of type MEIAxisConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.

Return Values
MPIMessageOK if AxisFlashConfigSet successfully sets the Axis flash configuration using data from the structure(s)
See Also | MEIFlash | mpiAxisFlashConfigGet | MEIAxisConfig


mpiAxisFilterMapGet

Declaration
long mpiAxisFilterMapGet(MPIAxis       axis,
                         MPIObjectMap  *filterMap)
Required Header stdmpi.h
Description

AxisFilterMapGet gets the object map of the Filters [associated with an Axis (axis)] and writes it into the structure pointed to by motorMap.

axis | a handle to the Axis object
*filterMap | a pointer to an ObjectMap of Filters mapped to the axis
Remarks
MPIObjectMap is a long that maps the Filters in controller memory to each bit. E.g. A map value of 1 would indicate Filter 0 is mapped the Axis. A value of 6 would indicate that Filters 2 and 3 are mapped to the Axis.
Return Values
MPIMessageOK if AxisFilterMapGet successfully gets and writes the object map to the structure
See Also | mpiAxisFilterMapSet


mpiAxisFilterMapSet

Declaration
long mpiAxisFilterMapSet(MPIAxis      axis,
                         MPIObjectMap filterMap)
Required Header stdmpi.h
Description

AxisFilterMapSet sets the Filters [associated with an Axis (axis)] using data from the object map specified by filterMap.

axis | a handle to the Axis object
filterMap | a list of Filters to be mapped to the axis
Remarks
MPIObjectMap is a long that maps the Filters in controller memory to each bit. E.g. A map value of 1 will map Filter 0 to the Axis. A value of 6 will map both Filters 2 and 3 to the Axis.
Return Values
MPIMessageOK if AxisFilterMapSet successfully sets the Filters using data from the object map
See Also | mpiAxisFilterMapGet | MPIObjectMap


mpiAxisMemory

Declaration
long mpiAxisMemory(MPIAxis  axis,
                   void     **memory)
Required Header stdmpi.h
Description

AxisMemory writes an address (that is used to access Axis memory) to the contents of memory. This address (or an address calculated from it) is passed as the src argument to mpiAxisMemoryGet(...) and as the dst argument to mpiAxisMemorySet(...).

axis | a handle to the Axis object
Return Values
MPIMessageOK if AxisMemory successfully writes the Axis memory address to the contents of memory
See Also | mpiAxisMemoryGet | mpiAxisMemorySet


mpiAxisMemoryGet

Declaration
long mpiAxisMemoryGet(MPIAxis axis,
                      void    *dst,
                      void    *src,
                      long    count)
Required Header stdmpi.h
Description

AxisMemoryGet copies count bytes of Axis (axis) memory (starting at address src) to application memory (starting at address dst).

axis | a handle to the Axis object
*dst | pointer to the destination location to where the memory will be written
*src | pointer to the source location of memory being read
count | size of memory to be read
Return Values
MPIMessageOK if AxisMemory successfully writes the Axis memory address to the contents of memory
See Also | mpiAxisMemory | mpiAxisMemorySet


mpiAxisMemorySet

Declaration
long mpiAxisMemorySet(MPIAxis axis,
                      void    *dst,
                      void    *src,
                      long    count)
Required Header stdmpi.h
Description

AxisMemorySet copies count bytes of application memory (starting at address src) to Axis (axis) memory (starting at address dst).

axis | a handle to the Axis object
*dst | pointer to the destination location to where the memory will be written
*src | pointer to the source location of memory being read
*count | size of memory to be written
Return Values
MPIMessageOK if AxisMemorySet successfully copies count bytes of application memory to Axis memory
See Also | mpiAxisMemory | mpiAxisMemoryGet


mpiAxisMotorMapGet

Declaration
long mpiAxisMotorMapGet(MPIAxis      axis,
                        MPIObjectMap *motorMap)
Required Header stdmpi.h
Description

AxisMotorMapGet gets the object map [of the Motors associated with an Axis (axis)] and writes it into the structure pointed to by motorMap.

axis | a handle to the Axis object.
*motorMap | a pointer to an ObjectMap of Motors mapped to the axis
Remarks

MPIObjectMap is a long that maps the Motors in controller memory to each bit. E.g. A map value of 1 would indicate Motor 0 is mapped the Axis. A value of 6 would indicate that Motors 2 and 3 are mapped to the Axis.

Remember that Motors are mapped to Axes through the Filter object. To configure the Axis/Motor map, the application will need to set the AxisFilterMap and FilterMotorMap.

Return Values
MPIMessageOK if AxisMotorMapGet successfully gets the object map and writes it into the structure
See Also


mpiAxisNumber

Declaration
long mpiAxisNumber(MPIAxis  axis,
                   long     *number)
Required Header stdmpi.h
Description

AxisNumber writes the index of an Axis (axis, on the motion controller that the Axis is associated with) to the contents of number.

axis | a handle to the Axis object
*number | pointer to the number
Return Values
MPIMessageOK if AxisNumber successfully writes the index of Axis to the contents of number
See Also


mpiAxisOriginGet

Declaration
long mpiAxisOriginGet(MPIAxis  axis,
                      double   *origin)
Required Header stdmpi.h
Description

AxisOriginGet gets the value of the origin of an Axis (axis) and writes it into the location pointed to by origin.

axis | a handle to the Axis object.
*origin | pointer to the Origin value returned by the method
Return Values
MPIMessageOK if AxisOriginGet successfully gets the value of the origin of the Axis and writes it to the location
See Also | mpiAxisOriginSet | Using the Origin Variable


mpiAxisOriginSet

Declaration
long mpiAxisOriginSet(MPIAxis  axis,
                      double   origin)
Required Header stdmpi.h
Description

AxisOriginSet sets the value of the origin of an Axis (axis) to origin.

axis | a handle to the Axis object
origin | Value to which the Axis Origin will be set
Return Values
MPIMessageOK if AxisOriginSet successfully sets the origin of an Axis to origin
See Also | mpiAxisOriginGet | Using the Origin Variable


mpiAxisPositionError

Declaration
long mpiAxisPositionError(MPIAxis  axis,
                          double   *error)
Required Header stdmpi.h
Description

AxisPositionError gets the value of the position error of an Axis (axis) and puts it in the location pointed to by error. The position error is equal to (command position - actual position).

axis | a handle to the Axis object
*error | a pointer to the Axis position error returned by the method
Return Values
MPIMessageOK if AxisPositionError successfully gets and writes the value of the position error into *error
See Also | mpiAxisCommandPositionGet | mpiAxisActualPositionGet


mpiAxisStatus

Declaration
long mpiAxisStatus(MPIAxis    axis,
                   MPIStatus  *status,
                   void       *external)
Required Header stdmpi.h
Description

AxisStatus gets the status of an Axis (axis) and writes it into the structure pointed to by status.

axis | a handle to the Axis object
*status | pointer to MPIStatus structure.
*external | pointer to an external.
XMP Only

external should always be set to NULL.

Return Values
MPIMessageOK if AxisStatus successfully gets the Axis status and writes it into the structure(s)
See Also


mpiAxisTrajectory

Declaration
long mpiAxisTrajectory(MPIAxis       axis,
                       MPITrajectory *trajectory)
Required Header stdmpi.h
Description

AxisTrajectory reads the current velocity and acceleration of axis and writes it into the structure pointed to by trajectory.

NOTE: deceleration, jerkPercent, accelerationJerk, and decelerationJerk fields of trajectory cannot be read from the controller and consequently are set to zero.

axis | a handle to the Axis object.
*trajectory | pointer to the MPITrajectory structure
Remarks
The default MPITrajectory structure can be used by the mpiMotionStart(...) and mpiMotionModify() methods.
Return Values
MPIMessageOK if AxisTrajectory successfully gets the Axis trajectory and writes it into the structure
See Also | mpiMotionStart | mpiMotionModify | MPITrajectory


mpiAxisValidate

Declaration
long mpiAxisValidate(MPIAxis   axis)
Required Header stdmpi.h
Description

AxisValidate validates the Axis object and its handle (axis). AxisValidate should be called immediately after an object is created.

axis | a handle to the Axis object to be validated
Return Values
MPIMessageOK if Axis is a handle to a valid object.
See Also | mpiAxisCreate | mpiAxisDelete


Configuration of IN_POSITION and DONE Events

.

Configuration of IN_POSITION and DONE Events
after STOP or E-STOP Events

Two fields, settleOnStop and settleOnEstop are incorporated into the MPIAxisInPosition{} structure. These fields control the generation and use of IN_FINE_POSITION, and DONE status bits and events. A value of FALSE in these fields causes the IN_FINE_POSITION to be held false after STOP (or E-STOP) events and DONE to be based solely on command velocity (i.e. DONE is true as soon as the command velocity reaches 0). A value of TRUE in these fields causes IN_FINE_POSITION and DONE to be calculated in the same manner as that for normal motion, except that the position where the command velocity reaches zero is used for a target rather than the original Target Position.

The following table shows the generation of these status bits with settleOnStop (settleOnEstop) = FALSE (the default value):

Motion Status | After S-curve or Trapezoidal Move | During Velocity Move | After STOP (E-STOP) | After ABORT
IN_FINE_POSITION | Based on target distance (see note 3) | FALSE | FALSE | FALSE
IN_COARSE_POSITION | Based on target distance | FALSE | FALSE | FALSE
AT_TARGET | TRUE when command = target | FALSE | FALSE | FALSE
DONE | TRUE if both TC and IN_FINE_POSITION are true | FALSE | TRUE when command velocity = 0 | TRUE
The following table shows the generation of these status bits with settleOnStop (settleOnEstop) = TRUE:

Motion Status | After S-curve or Trapezoidal Move | During Velocity Move | After STOP (E-STOP) | After ABORT
IN_FINE_POSITION | Based on target distance (see note 3) | FALSE | Based on position error (see note 1) | FALSE
IN_COARSE_POSITION | Based on target distance | FALSE | FALSE | FALSE
AT_TARGET | TRUE when command = target | FALSE | FALSE | FALSE
DONE | TRUE if both TC and IN_FINE_POSITION are true | FALSE | Same as IN_FINE_ POSITION | TRUE

NOTE 1: IN_FINE_POSITION is based on four criteria:

  • The trajectory has completed (see note 2).
  • |command position – actual position| < fine position tolerance.
  • Target velocity – actual velocity| < velocity tolerance (the default setting for velocity tolerance so large that this criteria is ignored).
  • The above 3 criteria have been satisfied for the duration specified by the settling time parameter.

NOTE 2: The reference to “TC” above refers to TRAJECTORY_COMPLETE, an internal status that is set when all of the current motion segments (frames) have completed.

NOTE 3: The criteria used for calculation of IN_FINE_POSITION after s-curve or trapezoidal motion has changed to the following: (This is the same as the MPI-1 criteria.)

  • The trajectory has completed (see note 2).
  • |target position – actual position| < fine position tolerance.
  • |command velocity – actual velocity| < velocity tolerance (the default setting for velocity tolerance so large that this criteria is ignored).
  • The above 3 criteria have been satisfied for a duration specified by the settling time parameter.

Return to MPIAxisInPosition


CAN Objects

.

CAN Objects

Introduction

The CAN object allow the user easy access to the I/O nodes connected to a controller's CANOpen interface.

If a controller does not support the CANOpen interface, the meiCanValidate function will return MEICanMessageINTERFACE_NOT_FOUND.

The CAN system uses the MEICanConfig and MEICanNodeConfig structures to hold all of the user configurable quantities. These structures are stored in non-volatile flash memory. When the XMP is released from reset (normally soon after the host powers up or after a call to mpiControlReset), the CAN Processor will initialize itself with data from MEICanConfig and MEICanNodeConfig before starting to scanning the network for nodes.

The functions meiCanConfigGet, meiCanConfigSet, meiCanNodeConfigGet and meiCanNodeConfigSet allow the user to modify the current configuration of the CAN Processor, and meiCanFlashConfigGet, meiCanFlashConfigSet, meiCanFlashNodeConfigGet, and meiCanFlashNodeConfigSet functions allow the user to modify the configuration that the CAN system will use after the next reset.

The MEICanVersion structure returns the version information about the CAN system on a controller.

After the CAN processor has finished scanning the network, it will have completed the MEICanNodeInfo structures for each node. The user can call the meiCanNodeInfo function to query this initial configuration for each of the nodes.

Bit Rate | Transmission Types | Bus State | CAN Hardware |
Node Health | Emergency Messages | Handling Events | XMP Overview |

Methods

Create, Delete, Validate Methods
 | meiCanCreate | Create Can object
 | meiCanDelete | Delete Can object
 | meiCanValidate | Validate Can object

Configuration and Information Methods
 | meiCanConfigGet | Get Can’s configuration
 | meiCanConfigSet | Set Can’s configuration
 | meiCanCommand | Get Can’s flash configuration
 | meiCanFlashConfigGet | Get Can’s flash configuration
 | meiCanFlashConfigSet | Set Can’s flash configuration
 | meiCanFlashNodeConfigGet | Get the flash configuration of the Can node
 | meiCanFlashNodeConfigSet | Set the flash configuration of the Can node
 | meiCanStatus | Get status of the CAN controller.
 | meiCanVersion | Returns the version information about a controller's CAN system.

Event Methods
 | meiCanEventNotifyGet | Get event mask of events for which host notification has been requested
 | meiCanEventNotifySet | Set event mask of events for which host notification will be requested

Action Methods
 | meiCanFirmwareDownload | Downloads firmware to the Can controller
 | meiCanFirmwareErase | Erases firmware on the Can controller
 | meiCanFirmwareUpload | Uploads firmware from the Can controller

Memory Methods
 | meiCanMemory | Get address to Can’s memory
 | meiCanMemoryGet | Copy data from Can memory to application memory
 | meiCanMemorySet | Copy data from application memory to Recorder memory

Relational Methods
 | meiCanNodeAnalogInputGet | Get current analog input
 | meiCanNodeAnalogOutputGet | Get current analog output
 | meiCanNodeAnalogOutputSet | Set current analog output
 | meiCanNodeConfigGet | Return a copy of the current configuration
 | meiCanNodeConfigSet | Update the current configuration that the specified CAN node is using.
 | meiCanNodeDigitalInputGet | Get the current state of the digital input bit.
 | meiCanNodeDigitalInputsGet | Get the current state of ALL the digital input bits.
 | meiCanNodeDigitalOutputGet | Get the current state of the digital output bit.
 | meiCanNodeDigitalOutputsGet | Get the current state of all the digital output bits.
 | meiCanNodeDigitalOutputSet | changes the state of the digital output bit.
 | meiCanNodeDigitalOutputsSet | Changes the current state of all the digital output bits.
 | meiCanNodeInfo | Return the node information after the XMP finishes scanning the network.
 | meiCanNodeStatus | Get the instantaneous state of the local CAN interface.

Data Types

MEICanBitRate
MEICanBusState
MEICanCallback
MEICanCommand
MEICanCommandType
MEICanConfig
MEICanDigitalIO
MEICanHealthType
MEICanMessage
MEICanNodeConfig
MEICanNodeInfo
MEICanNodeStatus
MEICanNodeType
MEICanNMTState
MEICanStatus
MEICanTransmissionType
MEICanVersion


MEICanBitRate

MEICanBitRate

typedef enum {
    MEICanBitRate1000K = 0,
    MEICanBitRate800K,
    MEICanBitRate500K,
    MEICanBitRate250K,
    MEICanBitRate125K,
    MEICanBitRate50K,
    MEICanBitRate20K,
    MEICanBitRate10K
} MEICanBitRate;

Description
 | CanBitRate enumerates all the valid bit rates that the CANOpen interface can use. These are the recommended bit rates that the CANOpen standard defines. For more information see the Bit Rate section.
See Also


MEICanBusState

MEICanBusState

typedef enum {
    MEICanBusStateOFF,
    MEICanBusStatePASSIVE,
    MEICanBusStateOPERATIONAL
} MEICanBusState;

Description
 | CanBusState enumerates the bus states that the controller’s CAN interface can take. To see how the CanBusState is displayed in Motion Console, click here.

See Also | Documentation on CAN Bus State


MEICanCallback

MEICanCallback

typedef long (*MEICanCallback)(long percentage);

Description
 | CanCallback is the definition of a call back function used during the firmware download.
See Also


MEICanConfig

MEICanConfig

typedef struct MEICanConfig {
    MEICanBitRate    bitRate;
    unsigned  long   cyclicPeriod;
    unsigned  long   healthPeriod;
    unsigned  long   nodeNumber;
    unsigned  long   inhibitTime;
} MEICanConfig;
Description

CanConfig holds the configuration of the CAN object. The default state for this structure is held in the controller's flash. Use the meiCanConfigGet/Set and meiCanNodeConfigGet/Set to interrogate and change to what the CAN system is currently using or the default.

bitRate | The bit rate the CAN bus uses.
cyclicPeriod | The period (milliseconds) between sending consecutive SYNC messages. A value of zero will disable the SYNC messages from being produced.
healthPeriod | The period (milliseconds) used for checking the health of nodes. A value of zero will disable the health checking protocol. For nodes that use the node guarding protocol, this is the node guarding period. For nodes that use the heartbeating protocol, this is the heartbeat consumer time (the heartbeat producers are half this period).
nodeNumber | The node number of the controller on the CAN network. CANOpen requires that the master node has a valid node number to implement the heartbeat protocol.
inhibitTime | The global time used for the node health protocols. See also CAN Transmission Types.
See Also | meiCanConfigGet | meiCanConfigSet | meiCanNodeConfigGet | meiCanNodeConfigSet | Documentation on CAN Node Health. Documentation on CAN Transmission Types.


MEICanCommand

MEICanCommand

typedef struct MEICanCommand {
    MEICanCommandType   type;
    long                data[6];
} MEICanCommand;
Description

CanCommand holds the command request and response for an meiCanCommand.

type | The type of CAN command.
data | Data associated with the command.
See Also | meiCanCommand


MEICanCommandType

MEICanCommandType

typedef enum {
    MEICanCommandTypeSDO_READ,
    MEICanCommandTypeSDO_WRITE,
    MEICanCommandTypeCLEAR_STATUS_BITS,
    MEICanCommandTypeBUS_START,
    MEICanCommandTypeBUS_STOP,
    MEICanCommandTypeNMT_STOP,
    MEICanCommandTypeNMT_START
} MEICanCommandType;
Description

CanCommandType enumerates the different type of commands that can be used with meiCanCommand.

MEICanCommandTypeSDO_READ | This command reads the remote nodes object dictionary using the SDO protocol. Command data: data[0] = Node data[1] = Index data[2] = SubIndex data[3] = Length Returned data: data[0] = Error code data[4] = Low Data word data[5] = High Data word
MEICanCommandTypeSDO_WRITE | This command writes to a remote nodes object dictionary using the SDO protocol. Command data: data[0] = Node data[1] = Index data[2] = SubIndex data[3] = Length data[4] = Low Data word data[5] = High Data word Returned data: data[0] = Error code
MEICanCommandTypeCLEAR_STATUS_BITS | Clear selected MEICanStatusBits. Command data: data[0], Bit map of MEICanStatusBits to clear. Returned data: data[0] = Error code
MEICanCommandTypeBUS_START | This puts the CAN bus into operational state if it is Bus off. Command data: None Returned data: data[0] = Error code
MEICanCommandTypeBUS_STOP | This puts the CAN bus into operational state if it is Bus off. Command data: None Returned data: data[0] = Error code
MEICanCommandTypenNMT_STOP | This puts a node into NMT stopped state. Command data: data[0], node to stop, zero is all nodes Returned data: data[0] = Error code
MEICanCommandTypenNMT_START | This puts the node into NMT operational state. Command data: data[0], node to start, zero is all nodes Returned data: data[0] = Error code
See Also | meiCanCommand


MEICanDigitalIO

MEICanDigitalIO

typedef struct MEICanDigitalIO {
    unsigned  long   data[2];
} MEICanDigitalIO;
Description

CanDigitalIO holds the state of all the digital inputs or outputs on a CANOpen node.

NOTE: the maximum number of inputs or outputs on a single node supports is 64.

data | Data associated with the command.
See Also


MEICanHealthType

MEICanHealthType

typedef enum {
    MEICanHealthTypeNODE_GUARDING,
    MEICanHealthTypeHEART_BEATING
} MEICanHealthType;

Description
 | CanHealthType is used to report the health protocol that the XMP is using with each node.
See Also


MEICanMessage

MEICanMessage

typedef enum {
    MEICanMessageFIRMWARE_INVALID,
    MEICanMessageFIRMWARE_VERSION,
    MEICanMessageNOT_INITALIZED,
    MEICanMessageIO_NOT_SUPPORTED,
    MEICanMessageFILE_FORMAT_ERROR,
    MEICanMessageUSER_ABORT,
    MEICanMessageCOMMAND_PROTOCOL,
    MPICanMessageINTERFACE_NOT_FOUND,
    MEICanMessageNODE_DEAD,
    MEICanMessageSDO_TIMEOUT,
    MEICanMessageSDO_ABORT,
    MEICanMessageSDO_PROTOCOL,
    MEICanMessageTX_OVERFLOW,
    MEICanMessageRTR_TX_OVERFLOW,
    MEICanMessageRX_BUFFER_EMPTY,
    MEICanMessageBUS_OFF,
} MEICanMessage;

Description
MEICanMessageFIRMWARE_INVALID
 | The CAN firmware is not valid. This message code is returned by meiCanCreate(…) if the CAN hardware bootloader detects no firmware has been loaded or the firmware signature is not recognized. To correct this problem, download valid firmware with meiCanFirmwareDownload(…).
MEICanMessageFIRMWARE_VERSION
 | The CAN firmware version does not match the software version. This message code is returned by meiCanCreate(…), meiCanFirmwareDownload(…), or meiCanFirmwareUpload(…) if the CAN firmware version is not compatible with the MPI library. To correct this problem, download the proper firmware version with meiCanFirmwareDownload(…).
MEICanMessageNOT_INITIALIZED
 | The CAN firmware did not initialize. This message code is returned by meiCanCreate(…) if the controller did not copy the configuration structure from flash to memory after power-on or controller reset. To correct this problem, verify the controller firmware is correct and the controller hardware is operating properly.
MEICanMessageIO_NOT_SUPPORTED
 | The CAN node does not support the specified I/O. This message code is returned by CAN methods that read/write to a digital or analog input/output that is out of range. To prevent this problem, specify a supported I/O bit.
MEICanMessageFILE_FORMAT_ERROR
 | The CAN firmware file format has an error. This message code is returned by meiCanFirmwareDownload(…) if the specified file has an error in its internal headers. This indicates a corrupted file. To correct this problem, use the original CAN firmware file or reinstall the software distribution.
MEICanMessageUSER_ABORT
 | The CAN firmware loading was aborted. This message code is returned by meiCanFirmwareDownload(…) or meiCanFirmwareUpload(…) when the firmware loading is aborted by the user via the callback function. This message code is returned for application notification. It is not an error.
MEICanMessageCOMMAND_PROTOCOL
 | The CAN command failed due to a protocol error. This message code is returned by CAN methods that do not get a valid response from a CAN node. To correct this problem, check your CAN nodes for proper operation.
MPICanMessageINTERFACE_NOT_FOUND
 | The CAN interface is not available. This message code is returned by meiCanCreate(…) if the specified controller does not support a CAN network interface. To correct this problem, use a controller that has a CAN interface.
MEICanMessageNODE_DEAD
 | The CAN node does not respond. This message code is returned by CAN methods that read/write from a CAN node and the node fails the health check. This message code indicates a node hardware or network connection problem. To correct this problem, verify the node operation and network connections.
MEICanMessageSDO_TIMEOUT
 | The CAN command failed due to a timeout. This message code is returned by CAN methods that do not get a response from a CAN node within the timeout period. To correct this problem, check your CAN nodes for proper operation.
MEICanMessageSDO_ABORT
 | The CAN command failed due to a user abort. This message code is returned by CAN methods when an SDO transaction is aborted.
MEICanMessageSDO_PROTOCOL
 | The CAN command failed due to an SDO protocol error. This message code is returned by CAN methods when an SDO transaction fails because the node did not conform to the CANOpen protocol.
MEICanMessageTX_OVERFLOW
 | The controller's transmit buffer overflowed. This message code is returned by CAN methods that failed to transmit a message due to an internal memory buffer overflow.
MEICanMessageRTR_TX_OVERFLOW
 | The controller's transmit buffer overflowed. This message code is returned by CAN methods that failed to transmit a message due to an internal memory buffer overflow.
MEICanMessageRX_BUFFER_EMPTY
 | The controller's receive buffer is empty. This message code is returned by CAN methods that expected to get a response from a CAN node, but the controller's receive buffer was empty.
MEICanMessageBUS_OFF
 | The CAN network bus is in the off state. This message code is returned by CAN methods that are not able to use the CAN network because the bus is off. To correct this problem, verify the node operation and network connections.
See Also


MEICanNodeConfig

MEICanNodeConfig

typedef struct MEICanNodeConfig {
    MEICanTransmissionType digitalOutTransmissionType;
    MEICanTransmissionType analogOutTransmissionType;
    MEICanTransmissionType digitalInTransmissionType;
    MEICanTransmissionType analogInTransmissionType;
} MEICanNodeConfig;

Description
 | CanNodeConfig is the configuration of each node on the CAN bus. You can select which type of communication (event or cyclic) is to be used for the different types of IO data that a node supports. For more information, see the CAN Transmission Types section.
See Also


MEICanNodeInfo

MEICanNodeInfo

typedef struct MEICanNodeInfo {
    MEICanNodeType   type;
    unsigned long    digitalInputCount;
    unsigned long    digitalOutputCount;
    unsigned long    analogInputCount;
    unsigned long    analogOutputCount;
    MEICanHealthType healthType;
} MEICanNodeInfo;

Description
 | CanNodeInfo describes how many of the different types of I/O are on this node.

type | An enumeration indicating the type of node found at startup, or MEICanNodeTypeNONE if no node was found.
digitalInputCount | The number of digital inputs supported by this node.
digitalOutputCount | The number of digital outputs supported by this node.
analogInputCount | The number of analog inputs supported by this node.
analogOutputCount | The number of analog outputs supported by this node.
healthType | The type of health checking protocol being used with this node.

See Also | Documentation on CAN Node Health.


MEICanNodeStatus

MEICanNodeStatus

typedef struct MEICanNodeStatus {
    unsigned long    live;
    MEICanNMTState   nmtState;
} MEICanNodeStatus;
Description

CanNodeStatus holds the current status of a node.

live | Set if the node is alive, clear if the node is dead.
nmtState | The current NMT state that the node is reporting.
See Also | Documentation on CAN Node Health.


MEICanNodeType

MEICanNodeType

typedef enum {
    MEICanNodeTypeNONE = 0,
    MEICanNodeTypeIO   = 0x0191
} MEICanNodeType;

Description
 | CanNodeType enumerates the different types of nodes that the XMP has detected. MEICanNodeTypeNONE is returned if no node is found or an unsupported node type is detected.
See Also


MEICanNMTState

MEICanNMTState

typedef enum {
    MEICanNMTStateBOOT_UP,
    MEICanNMTStateSTOPPED,
    MEICanNMTStateOPERATIONAL,
    MEICanNMTStatePRE_OPERATIONAL,
    MEICanNMTStateUNKNOWN,
} MEICanNMTSTATE;

Description
 | CanNMTState enumerates the NMT (network management) states of a node on a CANOpen network. The XMP's CAN controller will automatically put all nodes into the Operational state during the initialization of the network.
See Also


MEICanStatus

MEICanStatus

typedef struct MEICanStatus {
    MEICanBusState    busState;
    long              transmitErrorCounter;
    long              receiveErrorCounter;
    long              messageRate;
    long              tick;
    long              softwareReceiveOverflow;
    long              hardwareReceiveOverflow;
} MEICanStatus;
Description

CanStatus holds the current status of the XMP’s CAN object.

busState | The current bus state of the XMP’s CAN interface.
transmitErrorCounter | The current value of the transmit error counter.
receiveErrorCounter | The current state of the receive error counter.
messageRate | The number of messages received and transmitted per second.
tick | This is incremented every 1ms by the CAN firmware.
softwareReceiveOverflow | This bit will be set if software receive buffer has overflowed. This bit can be cleared by using the CLEAR_STATUS_BITS command.
hardwareReceiveOverflow | This bit will be set if the CAN interface hardware has detected an overflow. This bit can be cleared by using the CLEAR_STATUS_BITS command.
See Also


MEICanTransmissionType

MEICanTransmissionType

typedef enum {
    MEICanTransmissionTypeCYCLIC = 0,
    MEICanTransmissionTypeEVENT  = 1,
} MEICanTransmissionType;

Description
 | CanTransmissionType enumerates the transmission types a node can use. For more information, see the CAN Transmission Types section.
See Also


MEICanVersion

MEICanVersion

typedef struct MEICanVersion {
    long    bootloaderVersion;
    long    firmwareVersion;
    char    firmwareRevision;
    long    firmwareSubRevision;
} MEICanVersion;
Description

CanVersion holds the version information about the XMP’s CAN object.

bootloaderVersion | The version number of the CAN bootloader.
firmwareVersion | The CAN firmware version.
firmwareRevsion | The CAN firmware revision.
firmwareSubRevision | The CAN firmware subrevision.
See Also


meiCanConfigGet

Declaration
long meiCanConfigGet(MEICan           can,
                     MEICanConfig*    config);
Required Header stdmei.h
Description

CanConfigGet returns a copy of the current configuration of the CAN controller.

can | a handle to the CAN object
config | a pointer to the CAN configuration structure that will be filled in by this function..
Return Values
MPIMessageOK if CanConfigGet successfully returns the copy of the current configuration of the CAN controller.
See Also | meiCanConfigSet


meiCanConfigSet

Declaration
long meiCanConfigSet(MEICan           can,
                     MEICanConfig*    config);
Required Header stdmei.h
Description

CanConfigSet updates the current configuration of the CAN controller.

can | a handle to the CAN object
config | a pointer to the CAN configuration structure containing the new configuration.
Return Values
MPIMessageOK if CanConfigSet successfully updates the current configuration of the CAN controller.
See Also | meiCanConfigGet


meiCanCommand

Declaration
long meiCanCommand(MEICan           can,
                   MEICanCommand*   command);
Required Header stdmei.h
Description

CanCommand allows a set of basic commands to be performed. The type field of the MEICanCommand structure specifies the type of command to perform.

can | a handle to the CAN object
command | a pointer to a structure which contains the details of the command to be issued. On the functions return, it will contain the result of the requested command.
Return Values
MPIMessageOK if CanCommand successfully performs the set of specified commands.
See Also | MEICanCommand


mpiCanCreate

Declaration
MEICan meiCanCreate(MPIControl  control,
                    long        network);
Required Header stdmei.h
Description

CanCreate creates a CAN object handle that is used subsequently to address the CAN network on this controller. You will need a valid CAN handle to use the MPI’s CANOpen functionality.

control | a handle to the controller object that contains the CAN object.
network | the number of the CAN network on the specified controller. For most controllers with a single CAN network interface this will be zero. Network numbers are zero based.
Example Code
The following sample code shows the creation ad destruction
of valid a CAN handle.

     MPIControl ControlHandle;
     MEICan CANHandle;
     long Result;

     /* Create, validate and initalise a handle to the controller. */
     ControlHandle = mpiControlCreate( MPIControlTypeDEFAULT, NULL );
     Result = mpiControlValidate( ControlHandle );
     assert( Result == MPIMessageOK );

     Result = mpiControlInit( ControlHandle );
     assert( Result == MPIMessageOK );

     /* Create and validate a handle to the CAN object. */
     CANHandle = meiCanCreate( ControlHandle, 0 );
     Result = meiCanValidate( CANHandle );
     assert( Result == MPIMessageOK );

     /* Use the CAN object here */

     /* Delete the CAN and Controller objects */
     Result = meiCanDelete( CANHandle );
     assert( Result == MPIMessageOK );
     Result = mpiControlDelete( ControlHandle );
     assert( Result == MPIMessageOK );

Return Values
handle | Handle to the CAN object created or MPIHandleVOID.
MPIHandleVOID | if the object could not be created

See Also | mpiCanDelete | mpiCanValidate


meiCanDelete

Declaration
long meiCanDelete(MEICan  can);
Required Header stdmei.h
Description

CanDelete deletes the specified CAN object.

can | handle to the CAN object to delete.
Example Code

See meiCanCreate for an example of how to use meiCanDelete.
Return Values
MPIMessageOK if CanDelete successfully deletes a CAN object and invalidates its handle
See Also | meiCanCreate | meiCanValidate


meiCanEventNotifyGet

Declaration
long meiCanEventNofityGet(MEICan          can,
                          MPIEventMask    *eventMask,
                          void            *external);
Required Header stdmei.h
Description

CanEventNotifyGet gets the current CAN event mask.

can | handle to the CAN object.
*eventMask | a pointer to the MPI event mask that will be filled in by this function.
*external | external points to an implementation specific structure. Since there is currently no implementation specific data, NULL should be used.
Return Values
MPIMessageOK if EventNotifyGet successfully gets the current CAN event mask.
See Also | meiCanNotifySet


meiCanEventNotifySet

Declaration
long meiCanEventNofitySet(MEICan          can,
                          MPIEventMask    eventMask,
                          void            *external);
Required Header stdmei.h
Description

CanEventNotifySet updates the current CAN event mask.

can | handle to the CAN object.
eventMask | a pointer to the new MPI event mask that will be filled in by this function.
*external | external points to an implementation specific structure. Since there is currently no implementation specific data, NULL should be used.
Return Values
MPIMessageOK if CanEventNotifySet successfully sets the current CAN event mask.
See Also | meiCanEventNotifyGet


meiCanFlashConfigGet

Declaration
long meiCanFlashConfigGet(MEICan          can,
                          void*           flash,
                          MEICanConfig*   config);
Required Header stdmei.h
Description

CanFlashConfigGet returns a copy of the current flash configuration that the CAN controller is using.

can | handle to the CAN object
flash | normally NULL
config | a pointer to the CAN configuration structure that will be filled in by this function.
Return Values
MPIMessageOK if CanFlashConfigGet successfully returns a copy of the current flash configuration that the CAN controller is using.
See Also | meiCanFlashConfigSet


meiCanFlashConfigSet

Declaration
long meiCanFlashConfigSet(MEICan          can,
                          void*           flash,
                          MEICanConfig*   config);
Required Header stdmei.h
Description

CanFlashConfigSet updates the current flash configuration that the CAN sun-system is using.

can | handle to the CAN object
flash | normally NULL
config | a pointer to the CAN configuration structure that will be filled in by this function.
Return Values
MPIMessageOK if CanFlashConfigSet successfully updates the current flash configuration that the CAN sun-system is using.
See Also | meiCanFlashConfigGet


meiCanFlashNodeConfigGet

Declaration
long meiCanFlashNodeConfigGet(MEICan             can,
                              void*              flash,
                              long               node,
                              MEICanNodeConfig*  nodeConfig);
Required Header stdmei.h
Description

CanFlashNodeConfigGet returns a copy of the current flash configuration of the CAN controller.

can | a handle to the CAN object
flash | normally NULL
node | the node number of the CANOpen node
nodeConfig | a pointer to the CAN node configuration structure that will be filled in by this function
Return Values
MPIMessageOK if CanFlashNodeConfigGet successfully returns the copy of the current flash configuration of the CAN controller.
See Also | meiCanFlashNodeConfigSet


meiCanFlashNodeConfigSet

Declaration
long meiCanFlashNodeConfigSet(MEICan             can,
                              void*              flash,
                              long               node,
                              MEICanNodeConfig*  nodeConfig);
Required Header stdmei.h
Description

CanFlashNodeConfigSet updates the current flash configuration for the node.

can | a handle to the CAN object
flash | normally NULL
node | the node number of the CANOpen node
nodeConfig | a pointer to the CAN node configuration structure containing the new configuration.
Return Values
MPIMessageOK if CanFlashNodeConfigSet successfully updates the current flash configuration for the node.
See Also | meiCanFlashNodeConfigGet


meiCanFirmwareDownload

Declaration
long meiCanFirmwareDownload(MEICan            can,
                            char*             filename,
                            MEICanCallback    callback);
Required Header stdmei.h
Description

CanFirmwareDownload allows the user to upgrade the CAN controller’s firmware.

This operation will take some time (between 10 and 30 seconds) to perform the download process. Therefore, the callback function is provided to allow the current status of the download operation to be reported to the calling application and to also allow the calling application to abort the download if required. The callback function passes the progress of the download process to the calling application. The calling applications normally returns a 0 unless it wants to abort the upgrade. If the upgrade is aborted, it returns a 1.

can | handle to the CAN object
filename | the filename of the CAN controller firmware (*.out file).
callback | a pointer to the call back function. (Pass an address of zero if you do not have a callback function.)
Return Values
MPIMessageOK if CanFirmwareDownload successfully uploads the CAN controller's firmware.
See Also | meiCanFirmwareErase | meiCanFirmwareUpload


meiCanFirmwareErase

Declaration
long meiCanFirmwareErase(MEICan   can);
Required Header stdmei.h
Description

CanFirmwareErase allows the user to erase the CAN controllers firmware.

Return Values
MPIMessageOK if CanFirmwareErase successfully erases the CAN controller's firmware.
See Also | meiCanFirmwareDownload | meiCanFirmwareUpload


meiCanFirmwareUpload

Declaration
long meiCanFirmwareUpload(MEICan            can,
                          char*             filename,
                          MEICanCallback    callback);
Required Header stdmei.h
Description

CanFirmwareUpload allows the user to get a copy of the current CAN controller’s firmware.

This operation will take some time (between 10 and 30 seconds) to perform the upload process. Therefore, the callback function is provided to allow the current status of the upload operation to be reported to the calling application and to also allow the calling application to abort the upgrade (if required). The callback function passes the progress of the upgrade process to the calling application. The calling applications normally returns 0 unless it wants to abort the upgrade. If the upgrade is aborted, it returns a 1.

can | handle to the CAN object
filename | the filename of the CAN controller firmware (*.out file).
callback | a pointer to the call back function. (Pass an address of zero if you do not have a callback function.)
Return Values
MPIMessageOK if CanFirmwareUpload successfully retrieves a copy of the current CAN controller's firmware.
See Also | meiCanFirmwareErase | meiCanFirmwareDownload


meiCanMemory

Declaration
long meiCanMemory(MEICan   can,
                  void**   memory);
Required Header stdmei.h
Description

CanMemory returns a pointer to the base of the CAN processors DPR. This function is generally not used and is provided for implementing advanced features of the MPI.

can | handle to the CAN object
memory | a pointer to the base of the CAN processors DPR.
Return Values
MPIMessageOK if CanMemory successfully returns a pointer to the base of the CAN processors DPR.
See Also | meiCanMemoryGet | meiCanMemorySet


meiCanMemoryGet

Declaration
long meiCanMemoryGet(MEICan   can,
                     void*    dst,
                     void*    src,
                     long     count);
Required Header stdmei.h
Description

CanMemoryGet copies the specified number of bytes from controller’s memory to the application's memory. This function is generally not used and is provided for implementing advanced features of the MPI.

can | handle to the CAN object
dst | the base address of the destination
src | the base address of the source
count | the number of bytes to copy
Return Values
MPIMessageOK if CanMemoryGet successfully copies the specified number of bytes to the application's memory.
See Also | meiCanMemory | meiCanMemorySet


meiCanMemorySet

Declaration
long meiCanMemorySet(MEICan   can,
                     void*    dst,
                     void*    src,
                     long     count);
Required Header stdmei.h
Description

CanMemorySet copies the specified number of bytes from the application's memory to the controller's memory. This function is generally not used and is provided for implementing advanced features of the MPI.

can | handle to the CAN object
dst | the base address of the destination
src | the base address of the source
count | the number of bytes to copy
Return Values
MPIMessageOK if CanMemorySet successfully copies the specified number of bytes to the controller's memory.
See Also | meiCanMemory | meiCanMemoryGet


meiCanNodeAnalogInputGet

Declaration
long meiCanNodeAnalogInputGet(MEICan    can,
                              long      node,
                              long      index,
                              double*   data);
Required Header stdmei.h
Description

CanNodeAnalogInputGet gets the current analog input from the specified CAN Node. The analog data returned is scaled to between ±1.0.

can | handle to the CAN object
node | the node number of the CANOpen node.
index | the index to the analog input on the node.
data | a pointer to where the current analog input is returned.
Return Values
MPIMessageOK if CanNodeAnalogInputGet successfully gets the current analog input from the specified CAN Node.
See Also


meiCanNodeAnalogOutputGet

Declaration
long meiCanNodeAnalogOutputGet(MEICan    can,
                               long      node,
                               long      index,
                               double*   data);
Required Header stdmei.h
Description

CanNodeAnalogOutputGet gets the current analog output from the specified CAN node and channel. The analog data returned is scaled to between ±1.0.

can | handle to the CAN object
node | the node number of the CANOpen node.
index | the index to the analog input on the node.
data | a pointer to where the current analog output is returned.
Return Values
MPIMessageOK if CanNodeAnalogOutputGet successfully gets the current analog output from the specified CAN Node and channel.
See Also | meiCanNodeAnalogOutputSet


meiCanNodeAnalogOutputSet

Declaration
long meiCanNodeAnalogOutputSet(MEICan    can,
                               long      node,
                               long      index,
                               double*   data);
Required Header stdmei.h
Description

CanNodeAnalogOutputSet sets the current analog output for the specified CAN node and channel. The analog data used is assumed to be between ±1.0.

can | handle to the CAN object
node | the node number of the CANOpen node.
index | the index to the analog input on the node.
data | the new analog value to be output.
Return Values
MPIMessageOK if CanNodeAnalogOutputSet successfully sets the current analog output for the specified CAN Node and channel.
See Also | meiCanNodeAnalogOutputGet


meiCanNodeConfigGet

Declaration
long meiCanNodeConfigGet(MEICan               can,
                         long                 node,
                         MEICanNodeConfig*    nodeConfig);
Required Header stdmei.h
Description

CanNodeConfigGet returns a copy of the current configuration that the specified CAN node is using.

can | a handle to the CAN object
node | the node number of the CANOpen node
nodeConfig | a pointer to the CAN node configuration structure that will be filled in by this function.
Return Values
MPIMessageOK if CanNodeConfigGet successfully returns the copy of the current configuration of the specified CAN node.
See Also | meiCanNodeConfigSet | meiCanConfigGet | meiCanConfigSet


meiCanNodeConfigSet

Declaration
long meiCanNodeConfigSet(MEICan               can,
                         long                 node,
                         MEICanNodeConfig*    nodeConfig);
Required Header stdmei.h
Description

CanNodeConfigSet updates the current configuration that the specified CAN node is using.

can | a handle to the CAN object
node | the node number of the CANOpen node
nodeConfig | a pointer to the CAN node configuration structure containing the new configuration.
Return Values
MPIMessageOK if CanNodeConfigSet successfully updates the current configuration of the specified CAN node.
See Also | meiCanNodeConfigGet | meiCanConfigGet | meiCanConfigSet


meiCanNodeDigitalInputsGet

Declaration
long meiCanNodeDigitalInputsGet(MEICan             can,
                                long               node,
                                MEICanDigitalIO*   data);
Required Header stdmei.h
Description

CanNodeDigitalInputsGet gets the current state of all the digital input bits on the specified CAN node.

(Not to be confused with meiCanNodeDigitalInputGet.)

can | handle to the CAN object
node | the node number of the CANOpen node.
data | a pointer to where the current digital bits are returned.
Return Values
MPIMessageOK if CanNodeDigitalInputsGet successfully gets the current state of all the digital input bits on the specified CAN Node.
See Also | meiCanNodeDigitalInputGet


meiCanNodeDigitalInputGet

Declaration
long meiCanNodeDigitalInputGet(MEICan    can,
                               long      node,
                               long      bit,
                               long*     data);
Required Header stdmei.h
Description

CanNodeDigitalInputGet gets the current state of the digital input bit on the specified CAN node.

(Not to be confused with meiCanNodeDigitalInputsGet.)

can | handle to the CAN object
node | the node number of the CANOpen node
bit | Which bit on this node
data | a pointer to where the current digital bit is returned
Example Code
The following sample code shows how to interrogate the current state
of a single digital input bit on a controller. The variable Bit will
contain either one or zero depending on the electrical signal being
applied to the input pin on the CANOpen node. See meiCanCreate on
how to create the CANHandle.

     long Bit;
     long Result;
     Result = meiCanNodeDigitalInputGet(CANHandle,
                                        3, /*node*/
                                        0, /*bit*/
                                        &Bit );
     assert( Result == MPIMessageOK );
Return Values
MPIMessageOK if CanNodeAnalogInputGet successfully gets the current analog input from the specified CAN Node.
See Also | meiCanCreate


meiCanNodeDigitalOutputsGet

Declaration
long meiCanNodeDigitalOutputsGet(MEICan              can,
                                 long                node,
                                 MEICanDigitalIO*    data);
Required Header stdmei.h
Description

CanNodeAnalogOutputGet gets the current state of all the digital output bits on the specified CAN node.

(Not to be confused with meiCanNodeDigitalOutputsGet.)

can | handle to the CAN object
node | the node number of the CANOpen node.
data | a pointer to where the current digital bit is returned.
Return Values
MPIMessageOK if CanNodeDigitalOutputsGet successfully gets the current digital output bits on the specified CAN node.
See Also | meiCanNodeDigitalOutputGet | meiCanNodeDigitalOutputSet | meiCanNodeDigitalOutputsSet


meiCanNodeDigitalOutputGet

Declaration
long meiCanNodeDigitalOutputGet(MEICan    can,
                                long      node,
                                long      bit,
                                long*     data);
Required Header stdmei.h
Description

CanNodeAnalogOutputGet gets the current state of the digital output bit on the specified CAN Node.

(Not to be confused with meiCanNodeDigitalOutputsGet.)

can | handle to the CAN object
node | the node number of the CANOpen node.
bit | which bit on this node.
data | a pointer to where the current digital bit is returned.
Return Values
MPIMessageOK if CanNodeDigitalOutputGet successfully gets the current digital output bit on the specified CAN Node.
See Also | meiCanNodeDigitalOutputSet | meiCanNodeDigitalOutputsGet | meiCanNodeDigitalOutputsSet


meiCanNodeDigitalOutputsSet

Declaration
long meiCanNodeDigitalOutputsSet(MEICan              can,
                                 long                node,
                                 MEICanDigitalIO*    data);
Required Header stdmei.h
Description

CanNodeDigitalOutputsSet changes the current state of all the digital output bits on the specified CAN node.

(Not to be confused with meiCanNodeDigitalOutputSet.)

can | handle to the CAN object
node | the node number of the CANOpen node.
data | the new data of the digital bits.
Return Values
MPIMessageOK if CanNodeDigitalOutputsSet successfully changes the current state of all the digital output bits on the specified CAN node.
See Also | meiCanNodeDigitalOutputGet | meiCanNodeDigitalOutputSet | meiCanNodeDigitalOutputsGet


meiCanNodeDigitalOutputSet

Declaration
long meiCanNodeDigitalOutputSet(MEICan    can,
                                long      node,
                                long      bit,
                                long      data);
Required Header stdmei.h
Description

CanNodeDigitalOutputSet changes the state of the digital output bit on the specified CAN Node.

(Not to be confused with meiCanNodeDigitalOutputsSet.)

can | handle to the CAN object
node | the node number of the CANOpen node.
bit | which bit on this node.
data | the new state of the digital bit.
Return Values
MPIMessageOK if CanNodeDigitalOutputSet successfully changes the state of the digital output bit on the specified CAN Node.
See Also | meiCanNodeDigitalOutputGet | meiCanNodeDigitalOutputsGet | meiCanNodeDigitalOutputsSet


meiCanNodeInfo

Declaration
long meiCanNodeInfo(MEICan            can,
                    long              node,
                    MEICanNodeInfo*   nodeInfo);
Required Header stdmei.h
Description

CanNodeInfo returns the node information for the specified node on the CAN network that was generated when the XMP finished scanning the network.

can | handle to the CAN object
node | the filename of the CAN controller firmware (*.out file).
nodeInfo | a pointer to where this function will put the node information.
Return Values
MPIMessageOK if CanNodeInfo successfully returns the node information for the specified node.
See Also | meiCanNodeStatus | meiCanStatus


meiCanNodeStatus

Declaration
long meiCanNodeStatus(MEICan              can,
                      long                node,
                      MEICanNodeStatus*   nodeStatus);
Required Header stdmei.h
Description

CanNodeStatus gets the instantaneous state of the specified node on the CAN network.

can | handle to the CAN object
node | the node number of the CANOpen node.
nodeStatus | a pointer to where this function will put the node status.
Return Values
MPIMessageOK if CanNodeStatus successfully gets the instantaneous state of the specified node on the CAN network.
See Also | meiCanNodeInfo | meiCanStatus


meiCanStatus

Declaration
long meiCanStatus(MEICan          can,
                  MEICanStatus*   status);
Required Header stdmei.h
Description

CanNodeStatus gets the instantaneous state of the local CAN interface to the CAN network.

can | handle to the CAN object
node | the node number of the CANOpen node.
status | a pointer to where this function will put the status.
Return Values
MPIMessageOK if CanStatus successfully gets the instantaneous state of the local CAN interface to the CAN network.
See Also | meiCanNodeInfo | meiCanNodeStatus


meiCanValidate

Declaration
long meiCanValidate(MEICan   can);
Required Header stdmei.h
Description

CanValidate validates the specified CAN handle.

can | handle to the CAN object
Example Code

See meiCanCreate for an example of how to use meiCanValidate.

Return Values
MPIMessageOK | if CanValidate successfully validates that the XMP is properly fitted for the CANOpen interface.
MPIMessageUNSUPPORTED | indicates that the XMP is not properly fitted for the CANOpen interface.

See Also | meiCanNodeInfo | meiCanNodeStatus


meiCanVersion

Declaration
long meiCanVersion(MEICan           can,
                   MEICanVersion*   version);
Required Header stdmei.h
Description

CanVersion returns the version of the firmware being used by the CAN controller.

can | handle to the CAN object
version | a pointer to where this function will put the version information.
Return Values
MPIMessageOK if CanVersion successfully returns the version of the firmware being used by the CAN controller.
See Also


CAN Bit Rate

.

CAN Bit Rate

The CANOpen standard defines a set of bit rates that can be supported. Any CANOpen node must support at least one of these bit rates. All the nodes on the CAN network must be operating at the same bit rate. Any of these standard bit rates can be used with the XMP.

Due to the electrical characteristics of a CAN network, the maximum length of a CAN network (and the corresponding drop lengths) is dependent upon the bit rate that is chosen. See the table below.

CANOpen Bit Rates
Bit Rate | Max Bus Length (m) | Max Drop Length (m) | Max Cumulative Drop Length (m)
1M | 25* | 2 | 10
800k | 50* | 3 | 15
500k | 100 | 6 | 30
250k | 250 | 12 | 60
125k | 500 | 24 | 120
50k | 1000 | 60 | 300
20k | 2500 | 150 | 750
10k | 5000 | 300 | 1500


CAN Bus State

.

CAN Bus State

All CAN hardware maintains two error counters that are increased when transmit or receive errors are detected, and decreased when successful transmissions or receptions are achieved. In an error free operational system, these counters should be zero. The magnitude of these counters control the following state machine:

When a node is in the Operational state it will participate fully with all communications over the network, as the errors increase the CAN hardware will become Passive (detecting errors but not generating error messages), before turning Off and isolating the node from the network once the TxErrorCount exceeds 255 error messages. This feature allows nodes that are either malfunctioning or not configured correctly to be isolated for the network, thereby allowing the remaining nodes to successfully communicate.


CAN Emergency Messages

.

CAN Emergency Messages

Every type of CANOpen node can transmit an emergency message. These messages are designed to report errors and warnings, as well as fatal problems on a node. The contents of these emergency messages are very dependent upon the node manufacturer and node type. To interpret this data, you will need to refer to the node manufacture’s data. If an emergency message is generated by a node, the event handling scheme described in the events section below allows the user’s application to receive the emergency message data.


Handling Events

.

Handling Events

The CAN interface on the XMP generates many different types of asynchronous events such as:

  • a change in the XMP’s bus state
  • a change in a node’s health
  • a change in the state of an input node’s analog or digital inputs
  • an emergency message is transmitted by a node
  • a boot message is transmitted by a node
  • a lost message is detected by the XMP CAN firmware

The events above have been appended to the standard MPI event handling scheme in order to provide the user the ability to respond to these events. The diagram below shows an overview of how events are relayed to the user's application.

  1. The CANOpen firmware detects one of the CAN events.
  2. There is a mask within the XMP firmware that allows only a specified set of events to reach the host. This mask is interrogated and modified with the meiCanEventNotifyGet and meiCanEventNotifySet functions.
  3. Like all other events in the MPI, the user must install an Event Manager on the host. You will find the serviceCreate and serviceDelete functions from apputils convenient for installing an Event Manager.
  4. For each thread that needs to know about CAN events, the user will need to create a notify object, specifying a mask for the required events.
  5. The user’s application can use the mpiNotifyEventWait function to either poll or wait for a CAN event to be generated. A valid event returned from mpiNotifyEventWait may also contain extra fields of information relevant to the event produced. (ex: the new bus state or node number).


CAN Hardware

.

CAN Hardware

CANOpen is a serial network that uses a bus topology. The CANOpen bus always contains two signal wires, CAN+ and CAN-, which carry the differential serial data and a ground (GND). It is also common for most CANOpen nodes to provide a shield connection.

Similar to most industrial buses, the signal wires need to be terminated. CANOpen requires a 120ohm resistor at both ends of the main bus. If these resistors are not fitted, the network will not function properly. Some node suppliers build the terminating resistor into the node and provide a jumper or switch to enable it. You will need to check your nodes' datasheets for the inclusion of a terminating resistor. The XMP does not have any terminating resistors.

For pinout information, go to the XMP's CAN D-9 connector page.

A CANOpen node either has an opto-isolated or non-isolated interface. The use of optoisolation is primarily provided as an EMC countermeasure and is used to cope with potential differences in the ground. These effects are more pronounced for large machines and cable lengths. Therefore, the use of opto-couplers is recommended for bus lengths greater that 200m. The disadvantage of opto-couplers is that they reduce the maximum permissible bus length for a given bit rate.

The XMP CAN interface is available with or without opto-isolation. This option needs to be specified at the time your XMP is ordered.

Most types of nodes require a separate power supply to drive the local logic and the I/O interfaces. For nodes that use opto-isolated interfaces, a separate supply of +7 to 24V needs to be provided to power the interface circuitry. The user must also supply an external 24V to the XMP (CAN_V+) if the opto-isolated interface option is being used.

Each node on the network must have a unique node number, in the range of 1 to 127. The node number is commonly set with a bank of DIP switches on each node. If two nodes are given the same node number, network errors are generated and unpredictable problems will be encountered. The node number of the XMP can be changed from the factory default of 1 using the meiCanConfigSet function. See meiCanConfigSet for more info.

In order for all nodes to communicate they must all use the same bit rate. Normally the bit rate that a node uses is set by DIP switches. If all of the nodes on a CANOpen network do not use the same bit rate then the whole network or some of the nodes on the network will not work properly. The bit rate of the XMP is set via software (meiCanConfigSet). See meiCanConfigSet for more info.


CAN Node Health

.

CAN Node Health

All networks including CAN are vulnerable to faults such as breaks in the bus wiring or loss of power by some of the nodes. CANopen defines two methods for the master node (the XMP in our case) to periodically check the presence of nodes on the network—node guarding and heart beating.

Using these services the XMP can monitor the health of the communications to each of the nodes. The current health of each node is reported in the live field of the MEICANNodeStatus structure.

It is mandatory for a node to either support the node guarding or heart beating protocols, or to support both. The heartbeat protocol has recently been introduced to CANOpen (in June 1999), and will probably NOT be supported on many nodes, but its adoption is recommended for all new nodes. The XMP’s implementation will operate with either protocol and will automatically detect the protocol that each node supports and then use the most appropriate protocol for the CAN network. The healthType field of the MEICanNodeInfo structure reports the health checking protocol being used with each node.

Node Guarding protocol

The Node Guarding protocol has the master sending an RTR message to all nodes on the network and checks to see whether a response is received from each of the nodes.

Heart Beating protocol

In the Heart Beating protocol, each node periodically broadcasts a heartbeat message. The period between transmitting the heartbeat messages is half the health period. If the XMP does not receive a message within a specific time window, it generates a heartbeat error for that node.

The advantage of the Heart Beating protocol over the Node Guarding protocol is that the number of messages is reduced in half, thereby freeing up bandwidth for other messages.

Health Period

The healthPeriod field of the MEICanConfig structure allows the user to specify the Node Guard and Heartbeat times for the health protocols according to the following table. The same period is used for all nodes.

Node Health Times
Protocol Times | Value
Node Guard Time | healthPeriod
Heartbeat Producer Time | healthPeriod / 2
Heatbeat Consumer Time | healthPeriod

For most applications it is recommended that the healthPeriod should be set to ten times the cyclic period.


Supported Nodes

.

Supported Nodes

The XMP CANOpen interface is designed to support any CANOpen node conforming to CANOpen I/O Node Profile, DS401 version 2.0. The interface has been fully tested with nodes from the following manufacturers: Beckhoff, Wago, and Selectron.


CAN Transmission Types

.

CAN Transmission Types

Introduction

The XMP CANOpen interface uses four messages (serial packets of data on the CAN bus) to pass I/O data between the XMP and an I/O node. Each message contains either the digital input, digital output, analog input, or analog output data. The XMP supports two standard communication methods to transmit I/O data between the XMP and each of the I/O nodes—cyclic transmission and event transmission. For most applications, cyclic messaging (the default) will be sufficient, but the transmission type fields within the MEICanNodeConfig structure allow the user to select an alternative transmission type for each of the I/O messages going to and from a node.

Cyclic Transmission

The Cyclic Transmission type, transfers I/O data messages between the XMP and the nodes using a cyclic protocol. The trigger for each cycle is a synchronization message that is transmitted at a regular rate by the XMP. When a node receives the synchronization message, it latches and transmits the current state of its inputs. Immediately after receiving the synchronization message, the master also transmits command messages to all the nodes with their new output states, which will get applied on the next synchronization message. An idle period is also needed to allow time for any non-cyclic messages to be transmitted.

The advantage of this scheme is that it generates a predicable loading of data on the bus. The latency on transmitted data is predictable, but the latency is not the absolute minimum that can be achieved.

Cyclic Period

The cyclicPeriod field within the MEICanConfig structure allows the user to specify the period (in milliseconds) that the XMP will use between the successive transmission of synchronization messages. The minimum cyclic period that can be used is dependent upon the chosen bit rate and the number of nodes. Assuming that all the nodes have inputs and outputs that are analog and digital, the minimum cyclic period that can be used is given in the following table.

CANOpen Cyclic Period
Bit Rate | < 5 Nodes | < 10 Nodes | < 50 Nodes | < 128 Nodes
1M | 3 | 5 | 30 | 60
800k | 3 | 6 | 30 | 80
500k | 5 | 10 | 50 | 200
250k | 10 | 18 | 89 | 300
125k | 19 | 36 | 200 | 500
50k | 46 | 90 | 500 | 2000
20k | 200 | 300 | 2000 | 3000
10k | 300 | 500 | 3000 | 6000

Event Transmission

The Event Transmission type, only transmits I/O data messages when an “event” occurs on the source node (either the XMP or the I/O node) to change the I/O data. The event that forces the transmission is either a new state of an input that is detected on an I/O node or a new output state that is commanded on the XMP.

The advantage of this type of messaging is that short reaction times are attainable, but this is accomplished at the expense of variable network traffic, and the possibility of saturating the network. In many cases, the reaction time is not significant in relation to other time delays in the system (ex: the user’s application or delays in task switching).

Inhibit Time

If the source node’s events occur at a very fast rate, the number of messages generated can swamp the network and consequently block out other messages. To prevent an excess of messages, nodes can optionally support inhibit times for their transmit PDOs. This value defines the minimum time between two successive PDO messages.

The inhibitTime field within the MEICanConfig structure allows the user to specify the period (in milliseconds) that all nodes on the network will use. A reasonable inhibit time is half a cyclic period.


XMP Overview

.

XMP Overview

In the example below, the XMP uses a dedicated CAN processor to handle the network. This ensures that the motion will not be affected by the CAN network. The XMP operates as a master node on the network with all the I/O nodes being slaves. This arrangement implies that there may only be one XMP on any CAN Network.

The XMP operates as a master node on the network with all the IO nodes being slaves. This arrangement implies that there may only be one XMP on any CAN Network.


Capture Object

.

Capture Object

Introduction

A Capture object manages a single position capture logic block. It represents the physical hardware capture logic and data. When configured and armed, the capture logic block can latch a motor's position based on one or more source input triggers.

The Capture object's number, motor input trigger sources, edge, type, feedback source, and capture index are all configurable. There are two capture types: Position and Time based. For the Position type, the position counters are latched in the FPGA and are read directly by the controller. This methodology works well for incremental quadrature encoders. For the Time type, the FPGA latches the clock and the controller reads the clock value and position value for that sample period. The controller interpolates the position value from the previous sample's position, the present sample's position, and the clock data. This methodology works very well for cyclic feedback data that is digitally transmitted from the drive to the FPGA. Many drives have a proprietary serial encoder that decodes the encoder position and sends the position information to the FPGA once per sample. In these cases, time-based capture is more accurate than position-based capture.

For the Position type, the motor number for the input sources and the feedback motor number must be the same.

For the Time type, the motor number and feedback motor number can be different. This makes is possible to use inputs from one node to capture positions on another node.

When using captures, the controller must have enough enabled captures to process the specified capture number. The controller will process the enabled captures (captureCount) every sample period. Since each capture object is configurable, use the minimum number of captures possible for best controller performance. For example, if you want to use 2 captures for motor 0 and motor 3, set the capture count to 2 and use capture number 0 and 1.

Methods

Create, Delete, Validate Methods
 | mpiCaptureCreate | Create Capture object
 | mpiCaptureDelete | Delete Capture object
 | mpiCaptureValidate | Validate Capture object

Configuration and Information Methods
 | mpiCaptureConfigGet | Get Capture configuration
 | mpiCaptureConfigSet | Set Capture configuration
 | mpiCaptureStatus | Get status of Capture
 | mpiCaptureConfigReset |

Action Methods
mpiCaptureArm Arm capture object

Memory Methods
 | mpiCaptureMemory | Set address to Capture memory
 | mpiCaptureMemoryGet | Copy Capture memory to application memory
 | mpiCaptureMemorySet | Copy application memory to Capture memory

Relational Methods
mpiCaptureNumber Get index of Capture (for Control list)

Data Types

MPICaptureConfig
MPICaptureEdge
MPICaptureMessage / MEICaptureMessage
MPICaptureSource
MPICaptureState
MPICaptureStatus
MPICaptureTrigger
MPICaptureTriggerGlobal
MPICaptureType

Constants

MPICaptureNOT_MAPPED


MPICaptureConfig

MPICaptureConfig

typedef struct MPICaptureConfig {
    MPICaptureTrigger         source[MPICaptureSourceCOUNT];
                                   /* use MPICaptureSource to index */
    MPICaptureEdge            edge;
    MPICaptureTriggerGlobal   global;
    MPICaptureType            type;
    long                      captureMotorNumber;
    long                      feedbackMotorNumber; /* the same as
                                  captureMotorNumber for POSITION capture */
    MPIMotorEncoder           encoder;
    long                      captureIndex;    /* 0,1,... */
} MPICaptureConfig;

Description
 | source[MPICaptureSourceCOUNT] | An array of capture trigger source inputs. The capture can be configured to trigger from one or more sources. See MPICaptureTrigger and MPICaptureSourceCOUNT.
 | edge | An enumerated index to the trigger edge type. The capture can be configured to trigger from a variety of logic. See MPICaptureEdge.
 | global | A structure to configure the global capture, to chain capture block triggering. See MPICaptureTriggerGlobal.
 | type | Either Position or Time.
 | captureMotorNumber | The number of the motor whose "source" (MPICaptureTrigger) is used to capture position.
 | feedbackMotorNumber | The number of the motor whose position is being returned from the captured event. (same as captureMotorNumber for position capture).
 | encoder | A motor's Primary or Secondary Encoder Feedback is being captured.
 | captureIndex | Each axis on a node has a given number of captures associated with it. Normally, each axis has only 1 capture, but they can have up to 4 captures.


MPICaptureEdge

MPICaptureEdge

typedef enum MPICaptureEdge {
    MPICaptureEdgeNONE,
    MPICaptureEdgeRISING,
    MPICaptureEdgeFALLING,
    MPICaptureEdgeEITHER,
} MPICaptureEdge;
Description

CaptureEdge is an enumeration of input trigger edge logic for a capture.

MPICaptureEdgeRISING | Triggers on a 0 to 1 transition.
MPICaptureEdgeFALLING | Triggers on a 1 to 0 transition.
MPICaptureEdgeEITHER | Triggers on either 0 to 1 or 1 to 0 transitions.

See Also | MPICaptureTrigger


MPICaptureMessage / MEICaptureMessage

MPICaptureMessage

typedef enum {
    MPICaptureMessageMOTOR_INVALID,
    MPICaptureMessageCAPTURE_TYPE_INVALID,
    MPICaptureMessageCAPTURE_INVALID,
    MPICaptureMessageENCODER_INVALID,

} MPICaptureMessage;
Description

CaptureMessage is an enumeration of Capture error messages that can be returned by the MPI library.

MEICaptureMessageMOTOR_INVALID
 | mpiCaptureConfigSet(...) --> config.captureMotorNumber is not valid. It's either greater than maxMotors or = = MPICaptureNOT.MAPPED.
MEICaptureMessageCAPTURE_TYPE_INVALID
 | mpiCaptureConfigSet(...) --> config.Type = = MPICaptureNOT.MAPPED.
MPICaptureMessageCAPTURE_INVALID
 | The capture number is out of range. This message code is returned by mpiCaptureCreate(…) if the capture number is less than zero or greater than or equal to MEIXmpMaxCapturesPerMotor.
MPICaptureMessageENCODER_INVALID
 | The encoder index is out of range. This message code is returned by mpiCaptureCreate(…) if the encoder index is less than MPIMotorEncoderFIRST or greater than or equal to MPIMotorEncoderLAST.

See Also | mpiCaptureCreate | mpiControlConfigSet

MEICaptureMessage

typedef enum {
    MEICaptureMessageINVALID_EDGE,
    MEICaptureMessageGLOBAL_CONFIG_ERR,
    MEICaptureMessageGLOBAL_ALREADY_ENABLED,
    MEICaptureMessageCAPTURE_NOT_ENABLED,
    MEICaptureMessageCAPTURE_STATE_INVALID,
    MEICaptureMessageNOT_MAPPED,
    MEICaptureMessageUNSUPPORTED_PRIMARY,
    MEICaptureMessageUNSUPPORTED_SECONDARY,
    MEICaptureMessageSECONDARY_INDEX_INVALID,
} MEICaptureMessage;

Description
MEICaptureMessageINVALID_EDGE
 | The encoder edge trigger type is not valid. This message code is returned by mpiCaptureConfigSet(…) if the encoder capture edge type is not a member of the MPICaptureEdge enumeration.
MEICaptureMessageGLOBAL_CONFIG_ERR
 | The global trigger configuration is not valid. This message code is returned by mpiCaptureConfigSet(…) if the capture's trigger source is set to global and the capture's global trigger is enabled simultaneously. To correct this problem, either set the capture's trigger source to global or enable the capture's global trigger (not both).
MEICaptureMessage_GLOBAL_ALREADY_ENABLED
 | The global trigger is already enabled. This message code is returned by mpiCaptureConfigSet(…) if a global trigger is already enabled on another capture on the same node. Only one global trigger enable is allowed per node. To prevent this problem, do not enable a second global trigger on a single node.
MEICaptureMessageCAPTURE_NOT_ENABLED
 | This value is returned by mpiCatureCreate(...) when the capture number specified is greater than the number of captures enabled in firmware. See MPIControlConfig.
MEICaptureMessageCAPTURE_STATE_INVALID
 | This value is returned by mpiCaptureStatus(...) when the communication between the controller and the capture logic on the node fails resulting in an invalid capture state. See MPICaptureState.
MEICaptureMessageNOT_MAPPED
 | The capture object's hardware resource is not available. This message code is returned by mpiCaptureCreate(…) if the node hardware for the specified motor and encoder is not found. During controller and network initialization the nodes and motor count for each node is discovered and mapped to the controller's motor and capture objects. A capture object cannot be created if there is no mapped hardware to support it. To correct this problem, verify that all expected nodes were found. Use meiSynqNetInfo(…) and meiSqNodeInfo(…) to determine the node topology and motor count per node. Check the node hardware power and network connections.
MEICaptureMessageUNSUPPORTED_PRIMARY
 | The capture hardware does not support the primary encoder. This message code is returned by mpiCaptureCreate(…) if the node hardware's primary encoder does not support the specified capture. To correct this problem, select a different motor, encoder, or capture number.
MEICaptureMessageUNSUPPORTED_SECONDARY
 | The capture hardware does not support the secondary encoder. This message code is returned by mpiCaptureCreate(…) if the node hardware's secondary encoder does not support the specified capture. To correct this problem, select a different motor, encoder, or capture number.
MEICaptureMessageSECONDARY_INDEX_INVALID
 | This message is returned from MPICaptureConfigSet(...) when the secondary encoder's index is specified as a trigger source in conjunction with other capture sources.

See Also | mpiCaptureCreate


MPICaptureNOT_MAPPED

Declaration
#define MPICaptureNOT_MAPPED (-1)
Required Header stdmpi.h
Description

Capture objects are associated with the controller and are not mapped to any hardware resources under default conditions. MPICaptureNOT_MAPPED will be assigned to:

     long    captureMotorNumber;
     long    feedbackMotorNumber;

when mpiCaptureConfigGet() is called for the first time on a capture object. After a capture object has been used once, the resource mapping will remain in place until it is reassigned.

See Also


MPICaptureSource

MPICaptureSource

typedef enum MPICaptureSource {
    MPICaptureSourceHOME,
    MPICaptureSourceINDEX,
    MPICaptureSourceLIMIT_HW_NEG,
    MPICaptureSourceLIMIT_HW_POS,
    MPICaptureSourceGLOBAL,
    MPICaptureSourceMOTOR_IO_0,
    MPICaptureSourceMOTOR_IO_1,
    MPICaptureSourceMOTOR_IO_2,
    MPICaptureSourceMOTOR_IO_3,
    MPICaptureSourceMOTOR_IO_4,
    MPICaptureSourceMOTOR_IO_5,
    MPICaptureSourceMOTOR_IO_6,
    MPICaptureSourceMOTOR_IO_7,
    MPICaptureSourceINDEX_SECONDARY,
    MPICaptureSourceCOUNT,
} MPICaptureSource;
Description

CaptureSource is an enumeration of input trigger sources for a capture.

MPICaptureSourceHOME | a capture trigger source is the HOME input in the dedicated I/O input.
MPICaptureSourceINDEX | a capture trigger source is the encoder INDEX input in the dedicated I/O input.
MPICaptureSourceLIMIT_HW_NEG | a capture trigger source is the Hardware Negative Limit input in the dedicated I/O input.
MPICaptureSourceLIMIT_HW_POS | a capture trigger source is the Hardware Positive Limit input in the dedicated IO word. Please see MPIMotorDedicatedIn.
MPICaptureSourceGLOBAL | a capture trigger source is the Global capture signal found on the node. Please see MPICaptureTriggerGlobal.
MPICaptureSourceMOTOR_IO_0 | a capture trigger source is the 0 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_1 | a capture trigger source is the 1 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_2 | a capture trigger source is the 2 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_3 | a capture trigger source is the 3 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_4 | a capture trigger source is the 4 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_5 | a capture trigger source is the 5 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_6 | a capture trigger source is the 6 bit in the motor's configurable I/O.
MPICaptureSourceMOTOR_IO_7 | a capture trigger source is the 7 bit in the motor's configurable I/O.
MPICaptureSourceINDEX_SECONDARY | A a capture trigger source is the index on the secondary encoder. If position based capture is selected with the feedback source being the secondary encoder, this is the only valid capture source.
MPICaptureSourceCOUNT | Total number of possible input sources for a capture.

See Also | MPICaptureTrigger | MEIMotorIoMask


MPICaptureState

MPICaptureState

typedef enum {
    MPICaptureStateIDLE,
    MPICaptureStateARMED,
    MPICaptureStateCAPTURED,
    MPICaptureStateCLEAR,
} MPICaptureState;

Description
 | MPICaptureStateIDLE | Capture is not armed. This is the default state.
 | MPICaptureStateARMED | Capture is armed, but has not triggered yet.
 | MPICaptureStateCAPTURED | Capture triggered and position data is valid.
 | MPICaptureStateCLEAR | Capture is not armed, but has not transitioned to the IDLE state yet. This is an internal transitional state between CAPTURED and IDLE. It occurs when a capture is disarmed.

See Also | MPICaptureStatus


MPICaptureStatus

MPICaptureStatus

typedef struct MPICaptureStatus {
    MPICaptureState	state;
    double            latchedValue;
} MPICaptureStatus;

Description
 | state | An enumerated value representing the present state of the capture logic
 | latchedValue | The captured position value. This value is only valid when the state is CAPTURED.

See Also | MPICaptureState


MPICaptureTrigger

MPICaptureTrigger

typedef struct MPICaptureTrigger {
    long enabled;   /* TRUE/FALSE */
    long invert;    /* TRUE = invert, FALSE = normal */
} MPICaptureTrigger;
Description

The CaptureTrigger structure specifies the trigger configurations for a capture.

enabled | Enables or disables the trigger. A value of TRUE enables the trigger, FALSE disables the trigger.
invert | Normal or inverted trigger polarity. A value of FALSE indicates normal polarity, TRUE indicates inverted polarity.

See Also | MPICaptureSource


MPICaptureTriggerGlobal

MPICaptureTriggerGlobal

typedef struct MPICaptureTriggerGlobal {
    long    enabled;    /* TRUE/FALSE */
} MPICaptureTriggerGlobal;
Description

The CaptureTriggerGlobal structure specifies the global input trigger configuration for a capture.

enabled | Enables or disables the global input trigger. A value of TRUE enables the trigger, FALSE disables the trigger.

See Also | MPICaptureConfig


MPICaptureType

MPICaptureType

typedef enum  {
    MPICaptureTypePOSITION,
    MPICaptureTypeTIME,
} MPICaptureType;

Description
 | MPICaptureTypePOSITION | An actual position is captured by the Node from its feedback source.
 | MPICaptureTypeTIME | An internal timer is captured by the node and then a captured position is interpolated by the XMP firmware.
See Also


mpiCaptureArm

Declaration
long mpiCaptureArm(MPICapture  capture,
                   long        arm)   /* TRUE/FALSE */
Required Header stdmpi.h
Description CaptureArm arms or disarms capture.
Value of "arm" | Action of mpiCaptureArm
FALSE | Disarms capture and sets the state of capture to MPICaptureStateIDLE
TRUE | Arms capture and sets the state of capture to MPICaptureStateARMED
Return Values
MPIMessageOK if the Capture object is successfully armed or disarmed
See Also | MPICaptureState


mpiCaptureConfigGet

Declaration
long mpiCaptureConfigGet(MPICapture       capture,
                         MPICaptureConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

CaptureConfigGet gets a Capture object’s (capture) configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The a Capture object’s configuration information in external is in addition to the Capture object’s configuration information in config, i.e, the Capture object’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEICaptureConfig{} or is NULL.

Return Values
MPIMessageOK if CaptureConfigGet successfully writes the Capture object’s configuration to the structure(s)
See Also | mpiCaptureConfigSet


mpiCaptureConfigReset

Declaration
long mpiCaptureConfigReset(MPICapture   capture);
Required Header stdmpi.h
Description

CaptureConfigReset return the capture object to its unmapped state.

A capture object has no assumed resources, and is unmapped under default conditions. When a capture is first created, its captureMotorNumber and feedbackMotorNumber are unmapped. Once a capture has been configured, the next time that the capture object is created, it will retain the captureMotorNumber and feedbackMotorNumber that was previously assigned. mpiCaptureConfigReset(...) will return the capture object to its unmapped state.

capture | a handle to a Capture object
See Also


mpiCaptureConfigSet

Declaration
long mpiCaptureConfigSet(MPICapture       capture,
                         MPICaptureConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

CaptureConfigSet sets a Capture object’s (capture) configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Capture object’s configuration information in external is in addition to the Capture object’s configuration information in config, i.e, the Capture object’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEICaptureConfig{} or is NULL.

Return Values
MPIMessageOK if CaptureConfigSet successfully sets the Capture object’s configuration using data from the structure(s)
See Also | mpiCaptureConfigGet


mpiCaptureCreate

Declaration
MPICapture mpiCaptureCreate(MPIControl     congtrol,
                            long           number);
Required Header stdmpi.h
Description

CaptureCreate creates a Capture object. The Capture object is identified by its association with a motor object, the motor's encoder and the encoder's capture number. SynqNetCreate is the equivalent of a C++ constructor.

control | a handle to a Control object
number | An index to the encoder's capture block.

Return Values
handle | to a Capture object
MPIHandleVOID | if the object could not be created

See Also | mpiCaptureNumber


mpiCaptureDelete

Declaration
long mpiCaptureDelete(MPICapture  capture)
Required Header stdmpi.h
Description

CaptureDelete deletes a Capture object and invalidates its handle (capture). CaptureDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if CaptureDelete successfully deletes the Capture object and invalidates its handle
See Also | mpiCaptureCreate | mpiCaptureValidate


mpiCaptureMemory

Declaration
long mpiCaptureMemory(MPICapture  capture,
                      void        **memory)
Required Header stdmpi.h
Description

CaptureMemory writes an address [which is used to access a Capture object’s (capture) memory] to the contents of memory. This address, or an address calculated from it, can be passed as the src parameter to mpiCaptureMemoryGet(...) and as the dst parameter to mpiCaptureMemorySet(...).

Return Values
MPIMessageOK if CaptureMemory successfully writes the Capture object’s memory address to the contents of memory
See Also | mpiCaptureMemoryGet | mpiCaptureMemorySet


mpiCaptureMemoryGet

Declaration
long mpiCaptureMemoryGet(MPICapture  capture,
                         void        *dst,
                         void        *src,
                         long        count)
Required Header stdmpi.h
Description

CaptureMemoryGet copies count bytes of a Capture object’s (capture) memory (starting at address src) and writes them into application memory (starting at address dst).

Return Values
MPIMessageOK if CaptureMemoryGet successfully copies data from Capture memory to application memory
See Also | mpiCaptureMemory | mpiCaptureMemorySet


mpiCaptureMemorySet

Declaration
long mpiCaptureMemorySet(MPICapture capture,
                         void       *dst,
                         void       *src,
                         long       count)
Required Header stdmpi.h
Description

CaptureMemorySet copies count bytes of application memory (starting at address src) and writes them into a Capture object’s (capture) memory (starting at address dst).
Return Values
MPIMessageOK if CaptureMemorySet successfully copies count bytes of application memory to Capture memory
See Also | mpiCaptureMemory | mpiCaptureMemoryGet


mpiCaptureNumber

Declaration
long mpiCaptureNumber(MPICapture   capture,
                      long         *number)
Required Header stdmpi.h
Description

CaptureNumber reads the index of the capture block associated with the capture object and writes it into the contents of a long pointed to by encoder.

capture | a handle to a capture object
*number | pointer to the capture number.
Return Values
MPIMessageOK if CaptureNumber successfully writes the index of a Capture object to the contents of number
See Also | mpiCaptureCreate


mpiCaptureStatus

Declaration
long mpiCaptureStatus(MPICapture         capture,
                      MPICaptureStatus   *status,
                      void               *external)
Required Header stdmpi.h
Description

CaptureStatus writes a Capture object’s (capture) status into the structure pointed to by status, and also into the implementation-specific structure pointed to by external (if external is not NULL).

external is reserved for future functionality and should be set to NULL.

Return Values
MPIMessageOK if CaptureStatus successfully writes the status of a Capture object to the structure(s)
See Also


mpiCaptureValidate

Declaration
long mpiCaptureValidate(MPICapture  capture)
Required Header stdmpi.h
Description

CaptureValidate validates the Capture object and its handle. CaptureValidate should be called immediately after an object is created.

capture | a handle to a capture object
Return Values
MPIMessageOK if Capture is a handle to a valid object.
See Also | mpiCaptureCreate | mpiCaptureDelete


Command Objects

.

Command Objects

Introduction

The Command object specifies one of a variety of program Sequence commands. These include motion, conditional branch, computational, and time delay commands.

Methods

Create, Delete, Validate Methods
 | mpiCommandCreate | Create Command object
 | mpiCommandDelete | Delete Command object
 | mpiCommandValidate | Validate Command object

Configuration and Informational Methods
 | mpiCommandLabel | Get pointer to Command label
 | mpiCommandParams | Get Command parameters
 | mpiCommandType | Return Command type

Other Methods
 | mpiCommandAxisListGet | Get the axisCount and axisList from a Command object.

Data Types

MPICommandAddress
MPICommandConstant
MPICommandExpr
MPICommandMessage
MPICommandMotion
MPICommandOperator
MPICommandParams
MPICommandType


MPICommandAddress

MPICommandAddress

typedef union {
    long    *l;
    float   *f;
} MPICommandAddress;
Description

CommandAddress defines a generic pointer that can specify either a long or a float pointer.

*l | is used to access the long pointer of MPICommandAddress.
*f | is used to access the float pointer of MPICommandAddress.

See Also | MPICommandConstant


MPICommandConstant

MPICommandConstant

typedef union {
    long    l;
    float   f;
} MPICommandConstant;
Description

CommandConstant defines a generic variable that can specify either a long or float value.

l | is used to access the long value of MPICommandConstant.
f | is used to access the float value of MPICommandConstant.

See Also | MPICommandAddress


MPICommandExpr

MPICommandExpr

 typedef struct MPICommandExpr {
    MPICommandOperator	oper;
    MPICommandAddress	address;
    union {
        MPICommandConstant	value;	/* [*'address'] 'oper' ['value'] */
        MPICommandAddress	ref;	/* [*'address'] 'oper' [*'ref']  */
    } by;
} MPICommandExpr;
Description

CommandExpr is a structure that represents an expression for an MPICommand object.

The expression is evaluated as either:
 | *address oper value
 | *address oper *ref
depending on the command type.

See Also | MPICommand | MPICommandParams | MPICommandType


MPICommandMessage

MPICommandMessage

 typedef enum {
    MPICommandMessageCOMMAND_INVALID,
    MPICommandMessageTYPE_INVALID,
    MPICommandMessagePARAM_INVALID,
} MPICommandMessage;

Description
MPICommandMessageCOMMAND_INVALID
 | Currently not supported and is reserved for future use.
MPICommandMessageTYPE_INVALID
 | The command type is not valid. This message code is returned by mpiCommandCreate(…) if the command type is not a member of the MPICommandType enumeration.
MPICommandMessagePARAM_INVALID
 | Currently not supported and is reserved for future use.

See Also | MPICommandType


MPICommandMotion

MPICommandMotion

typedef enum {
    MPICommandMotionABORT,
    MPICommandMotionE_STOP,
    MPICommandMotionE_STOP_ABORT,
    MPICommandMotionE_STOP_CMD_EQ_ACT,
    MPICommandMotionMODIFY,
    MPICommandMotionRESET,
    MPICommandMotionRESUME,
    MPICommandMotionSTART,
    MPICommandMotionSTOP,
} MPICommandMotion;
Description

CommandMotion is an enumeration of motion specific controller commands that can be used in a program sequence. It specifies a single motion action for the controller to execute. The CommandMotion also defines the command parameters that must be passed to mpiCommandCreate(...). For MPICommandMotion, there is a corresponding motion{...} structure in the MPICommandParams{...} structure.

MPICommandMotionABORT | Commands an Abort action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionABORT for details.
MPICommandMotionE_STOP | Commands an E-Stop action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionE_STOP for details.
MPICommandMotionE_STOP_ABORT | Commands an E-Stop, then Abort action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionE_STOP_ABORT for details.
MPICommandMotionE_STOP_CMD_EQ_ACT | Commands an E-Stop (command position = actual position) action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionE_STOP_CMD_EQ_ACT for details.
MPICommandMotionMODIFY | Commands a Motion Modify on the motion supervisor associated with the motion object. Make sure to specify the MPIMotionType and MPIMotionParams in the MPICommandParams{...} structure. See mpiMotionModify(...) for details.
MPICommandMotionRESET | Commands a Reset action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionRESET for details.
MPICommandMotionRESUME | Commands a Resume action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionRESUME for details.
MPICommandMotionSTART | Commands a Motion Start on the motion supervisor associated with the motion object. Make sure to specify the MPIMotionType and MPIMotionParams in the MPICommandParams{...} structure. See mpiMotionStart(...) for details.
MPICommandMotionSTOP | Commands a Stop action on the motion supervisor associated with the motion object. See mpiMotionAction(...), MPIActionSTOP for details.

See Also | MPIAction | MPICommand | MPICommandParams


MPICommandOperator

MPICommandOperator

 typedef enum {
    /* Arithmetic operators */
    MPICommandOperatorADD,
    MPICommandOperatorSUBTRACT,
    MPICommandOperatorMULTIPLY,
    MPICommandOperatorDIVIDE,

    MPICommandOperatorAND,
    MPICommandOperatorOR,
    MPICommandOperatorXOR,

    /* Logical operators */
    MPICommandOperatorALWAYS,

    MPICommandOperatorEQUAL,
    MPICommandOperatorNOT_EQUAL,

    MPICommandOperatorGREATER_OR_EQUAL,
    MPICommandOperatorGREATER,

    MPICommandOperatorLESS_OR_EQUAL,
    MPICommandOperatorLESS,

    MPICommandOperatorBIT_CLEAR,
    MPICommandOperatorBIT_SET,
} MPICommandOperator;
Description

The following are operators used by the MPICommand and MPICompare objects.

Arithmetic Operators
MPICommandOperatorADD | Performs an addition. Equivalent to the C operator (+).
MPICommandOperatorSUBTRACT | Performs a subtraction. Equivalent to the C operator (-).
MPICommandOperatorMULTIPLY | Performs a multiplication. Equivalent to the C operator (*).
MPICommandOperatorDIVIDE | Performs a divison. Equivalent to the C operator (/).
MPICommandOperatorAND | Performs a logical AND. Equivalent to the C operator (&).
MPICommandOperatorOR | Performs a logical OR. Equivalent to the C operator ( | ).
MPICommandOperatorXOR | Performs a logical XOR. Equivalent to the C operator (^).

Logical Operators
MPICommandOperatorALWAYS | Always evaluates TRUE. Equivalent in C to (1) or TRUE.
MPICommandOperatorEQUAL | Performs an equality comparison. Equivalent to the C operator (= =)
MPICommandOperatorGREATER_OR_EQUAL | Performs an inequality comparison. Equivalent to the C operator (!=)
MPICommandOperatorGREATER_OR_EQUAL | Performs a greater than or equal to comparison. Equivalent to the C operator (>=)
MPICommandOperatorGREATER | Performs a greater than comparison. Equivalent to the C operator (>)
MPICommandOperatorLESS_OR_EQUAL | Performs a less than or equal to comparison. Equivalent to the C operator (< =)
MPICommandOperatorLESS | Performs a less than comparison. Equivalent to the C operator (<)
MPICommandOperatorBIT_CLEAR | Clears specified bits. Equivalent in C to the statement: variable &= ~(bits)
MPICommandOperatorBIT_SET | Sets specified bits. Equivalent in C to the statement: variable | = (bits)

See Also | MPICommand | MPICommandExpr | MPICommandParams | MPIComparePosition | MPICompareParams


MPICommandParams

MPICommandParams

typedef union {
    struct {  /* *'dst' = 'value' */
        MPICommandAddress    dst;
        MPICommandConstant   value;
        MPIControl           control;	/* Ignored by Sequence */
    } assign;

    struct {  /* branch to 'label' on 'expr' */
        char            *label;   /* NULL => stop sequence */
        MPICommandExpr  expr;     /* expr.oper => MPICommandOperatorLogical */
        MPIControl      control;  /* Ignored by Sequence */
    } branch;

    struct {  /* branch to 'label' on MPIEventMask('handle') 'oper' 'mask' */
        char                *label; /* NULL => stop sequence */
        MPIHandle           handle; /* [MPIMotor|MPIMotion|...] */
        MPICommandOperator  oper;   /* EQUAL/NOT_EQUAL/BIT_CLEAR/BIT_SET */
        MPIEventMask        mask;   /* MPIEventMask('handle') 'oper' 'mask' */
    } branchEvent;

    struct {  /* branch to 'label' on Io.input 'oper' 'mask' */
        char               *label; /* NULL => stop sequence */
        MPIIoType          type;   /* MOTOR,   USER */
        MPIIoSource        source; /* MPIMotor	index */
        MPICommandOperator oper;   /* EQUAL/NOT_EQUAL/BIT_CLEAR/BIT_SET */
        long               mask;   /* [motor|user]Io.input 'oper' 'mask' */
    } branchIO;

    struct {  /* *'dst' = 'expr' */
        MPICommandAddress   dst;
        MPICommandExpr      expr;    /* expr.oper => MPICommandOperatorArithmetic */
        MPIControl          control; /* Ignored by Sequence */
    } compute;

    struct {  /* Io.output = Io.output 'oper' 'mask' */
        MPIIoType          type;    /* MOTOR,   USER */
        MPIIoSource        source;  /* MPIMotor    index */
        MPICommandOperator oper;    /* AND/OR/XOR */
        long               mask;
    } computeIO;

    struct {  /* memcpy(dst, src, count) */
        void         *dst;
        void         *src;
        long         count;
        MPIControl   control;  /* Ignored by Sequence */
    } copy;

    float  delay;  /* seconds */

    struct {
        long         value;    /* MPIEventStatus.type    = MPIEventTypeEXTERNAL */
                               /*               .source  = MPISequence/MPIProgram */
                               /*               .info[0] = value */
        MPIEventMgr  eventMgr; /* Ignored by Sequence */
    } event;

    struct {  /* mpiMotion[Abort|EStop|Reset|Resume|Start|Stop](motion[, type, params]) */
        MPICommandMotion    motionCommand;
        MPIMotion           motion;
        MPIMotionType       type;    /* MPICommandMotionSTART */
        MPIMotionParams     params;  /* MPICommandMotionSTART */
    } motion;

    struct {  /* wait until 'expr' */
        MPICommandExpr      expr;    /* expr.oper => MPICommandOperatorLogical */
        MPIControl          control; /* Ignored by Sequence */
    } wait;

    struct {  /* wait until MPIEventMask('handle') 'oper' 'mask' */
        MPIHandle           handle; /* [MPIMotor|MPIMotion|...] */
        MPICommandOperator  oper;   /* EQUAL/NOT_EQUAL/BIT_CLEAR/BIT_SET */
        MPIEventMask        mask;   /* MPIEventMask('handle') 'oper' 'mask' */
    } waitEvent;

    struct {  /* wait until Io.input 'oper' 'mask' */
        MPIIoType           type;     /* MOTOR,   USER */
        MPIIoSource         source;   /* MPIMotor   index */
        MPICommandOperator  oper;     /* EQUAL/NOT_EQUAL/BIT_CLEAR/BIT_SET */
        long                mask;     /* [motor|user]Io.input 'oper' 'mask' */
    } waitIO;
} MPICommandParams;

Description
 | assign | Assign a value to a particular controller address: *dst = value assign.control is currently not supported and is reserved for future use.
 | branch | Branch to a particular command (similar to a goto statement) if a particular comparison evaluates to TRUE: branch to label on expr If label = NULL, then no more commands will be executed if the comparison evaluates to TRUE. branch.control is currently not supported and is reserved for future use.
 | branchEvent | Branch to a particular command (similar to a goto statement) if a particular event occurs or has occured: branch to label on MPIEventMask(handle) oper mask If label = NULL, then no more commands will be executed if a particular event occurs or has occured.
 | branchIO | Branch to a particular command (similar to a goto statement) if a particular i/o state matches a specified condition: branch to label on Io.input oper mask If label = NULL, then no more commands will be executed if a particular i/o state matches a specified condition.
 | compute | perform some computation and place the result at some controller address: *dst = expr compute.control is currently not supported and is reserved for future use.
 | computeIO | Performs a computation on a set of i/o bits: Io.output = Io.output oper mask
 | copy | Copies controller memory from one place to another: memcpy(dst, src, count); Remember: count represents the number of bytes copied, NOT the number of controller words. event.control is currently not supported and is reserved for future use.
 | delay | Delays execution of the next command delay seconds.
 | event | Generates an event: MPIEventStatus.type = MPIEventTypeEXTERNAL MPIEventStatus.source = MPISequence MPIEventStatus.info[0] = value event.eventMgr is currently not supported and is reserved for future use.
 | motion | Commands a motion action (See MPICommandMotion): mpiMotionStart (motion, type, params]); or mpiMotionAction(motion, MPIAction[ABORT | E_STOP | E_STOP_ABORT | RESET | RESUME | STOP]);
 | wait | Delays execution of the next command until a particular comparison evaluates to TRUE: wait until expr wait.control is currently not supported and is reserved for future use.
 | waitEvent | Delays execution of the next command until a particular event occurs: wait until MPIEventMask(handle) oper mask
 | waitIO | Delays execution of the next command until a particular i/o state matches a specified condition: wait until Io.input oper mask

See Also | MPICommand | MPICommandType | mpiCommandCreate | mpiCommandParams


MPICommandType

MPICommandType
typedef enum {
    MPICommandTypeASSIGN,
    MPICommandTypeBRANCH,
    MPICommandTypeBRANCH_EVENT,
    MPICommandTypeBRANCH_IO,
    MPICommandTypeCOMPUTE,
    MPICommandTypeCOMPUTE_IO,
    MPICommandTypeCOPY,
    MPICommandTypeDELAY,
    MPICommandTypeEVENT,
    MPICommandTypeMOTION,
    MPICommandTypeWAIT,
    MPICommandTypeWAIT_EVENT,
    MPICommandTypeWAIT_IO,

    MPICommandTypeBIT_COUNT = sizeof(int) * 8,  /* sizeof(enum) */

    MPICommandTypeREF   = 0x1 << (MPICommandTypeBIT_COUNT - 1),
    MPICommandTypeFLOAT = 0x1 << (MPICommandTypeBIT_COUNT - 2),

    MPICommandTypeMASK  = ~(MPICommandTypeREF |
                             MPICommandTypeFLOAT),

    MPICommandTypeASSIGN_FLOAT      = MPICommandTypeASSIGN | MPICommandTypeFLOAT,

    MPICommandTypeBRANCH_REF        = MPICommandTypeBRANCH | MPICommandTypeREF,
    MPICommandTypeBRANCH_FLOAT      = MPICommandTypeBRANCH | MPICommandTypeFLOAT,
    MPICommandTypeBRANCH_FLOAT_REF  = MPICommandTypeBRANCH_FLOAT | MPICommandTypeREF,

    MPICommandTypeCOMPUTE_REF       = MPICommandTypeCOMPUTE | MPICommandTypeREF,
    MPICommandTypeCOMPUTE_FLOAT     = MPICommandTypeCOMPUTE | MPICommandTypeFLOAT,
    MPICommandTypeCOMPUTE_FLOAT_REF = MPICommandTypeCOMPUTE_FLOAT | MPICommandTypeREF,

    MPICommandTypeWAIT_REF          = MPICommandTypeWAIT | MPICommandTypeREF,
    MPICommandTypeWAIT_FLOAT        = MPICommandTypeWAIT | MPICommandTypeFLOAT,
    MPICommandTypeWAIT_FLOAT_REF    = MPICommandTypeWAIT_FLOAT | MPICommandTypeREF,

} MPICommandType;
Description

CommandType is an enumeration of controller commands that can be used in a program sequence. It specifies a single instruction for the controller to execute. The CommandType also defines the command parameters that must be passed to mpiCommandCreate(...). For each MPICommandType there is a corresponding structure in the MPICommandParams{...} structure. For example, when the MPICommandTypeASSIGN is specified, the assign{...} structure in MPICommandParams{...} must be filled in to specify the address and value.

Commands must be created with mpiCommandCreate(...) and then added to a sequence using mpiSequenceCommandAppend(...), mpiSequenceCommandInsert(...), or mpiSequenceCommandListSet(...). Then the command sequence can be loaded into the controller with mpiSequenceLoad(...) and started with mpiSequenceStart(...).

MPICommandTypeASSIGN | Writes a constant value (long or float) into the controller's memory at the specified address.
MPICommandTypeBRANCH | These commands branch to a particular command (similar to a goto statement) if a particular comparison evaluates to TRUE. MPICommandTypeBRANCH compares a controller address to a specified constant long value. MPICommandTypeBRANCH_REF Compares a controller address to a long value at a specified controller address.
MPICommandTypeBRANCH_EVENT | Branch to a particular command (similar to a goto statement) if a particular event occurs or has occured.
MPICommandTypeBRANCH_IO | Branch to a particular command (similar to a goto statement) if a particular I/O state matches a specified condition.
MPICommandTypeCOMPUTE | These commands perform some computation and place the result at some controller address. MPICommandTypeCOMPUTE performs a computation of some controller address and a constant long value.
MPICommandTypeCOMPUTE_IO | Performs a computation on a set of I/O bits.
MPICommandTypeCOPY | Copies controller memory from one place to another.
MPICommandTypeDELAY | Delays execution of the next command.
MPICommandTypeEVENT | Generate an event.
MPICommandTypeMOTION | Commands a motion action. See MPICommandMotion.
MPICommandTypeWAIT | These delays execution of the next command until a particular comparison evaluates to TRUE. MPICommandTypeWAIT compares a controller address to a specified constant long value. MPICommandTypeWAIT_REF Compares a controller address to a long value at a specified controller address.
MPICommandTypeWAIT_EVENT | Delays execution of the next command until a particular event occurs.
MPICommandTypeWAIT_IO | Delays execution of the next command until a particular I/O state matches a specified condition.
MPICommandTypeBIT_COUNT | Size of the MPICommandType enumeration in number of bits.
MPICommandTypeREF | Evaluate the MPICommandExpr{...} by reference. When specified, the operator is applied between the specified controller address and a reference to another controller address.
MPICommandTypeFLOAT | Evaluate the MPICommandConstant{...} as a float.
MPICommandTypeMASK | Masks off all other bits in MPICommandType that are not defined.
MPICommandTypeASSIGN_FLOAT | These commands assign a value to a particular controller address. MPICommandTypeASSIGN assigns a long value while MPICommandTypeASSIGN_FLOAT assigns a float value.
MPICommandTypeBRANCH_REF | Branch to a particular command if the comparison evaluates to TRUE. Compares a controller address to a long value at a specified controller address.
MPICommandTypeBRANCH_FLOAT | Compares a controller address to a specified constant float value.
MPICommandTypeBRANCH_FLOAT_REF | Compares a controller address to a float value at a specified controller address.
MPICommandTypeCOMPUTE_REF |
MPICommandTypeCOMPUTE_FLOAT | Performs a computation of some controller address and a constant float value.
MPICommandTypeCOMPUTE_FLOAT_REF | Performs a computation of some controller address and a float value at a specified controller address.
MPICommandTypeWAIT_REF | Compares a controller address to a long value at a specified controller address.
MPICommandTypeWAIT_FLOAT | Compares a controller address to a specified constant float value.
MPICommandTypeWAIT_FLOAT_REF | Compares a controller address to a float value at a specified controller address.

See Also | MPICommand | MPICommandMotion | MPICommandParams | mpiCommandCreate | mpiCommandType | mpiSequenceCommandAppend | mpiSequenceCommandInsert | mpiSequenceCommandListSet | mpiSequenceLoad | mpiSequenceStart |


meiCommandAxisListGet

Declaration
long meiCommandAxisListGet(MPICommand  command,
                           long        *axisCount
                           MPIAxis     *axisList)
Required Header stdmpi.h
Description

CommandAxisListGet reads number of axes and the list of axes associated with a motion type Command object (command) and writes them into the long pointed to by axisCount and the array of axis objects pointed to by axisList.

command | a handle to the Command object
*axisCount | a pointer to a long, representing the number of axes returned by the method
*axisList | a pointer to an array of axis objects returned by the method
Return Values
MPIMessageOK if CommandAxisListGet successfully gets the axisCount and axisList from a Command object.
See Also | MPICommand | MPIAxis | MPIMotion


mpiCommandCreate

Declaration
MPICommand mpiCommandCreate(MPICommandType   type,
                            MPICommandParams *params,
                            const char       *label)
Required Header stdmpi.h
Description

CommandCreate creates a Command object. The command type is specified by type. The type-specific parameters are specified by params. If label is not Null (i.e., something meaningful), then branch commands can call this Command (by using the label). CommandCreate is the equivalent of a C++ constructor.

Return Values
handle | to a Command object
MPIHandleVOID | if the object could not be created

See Also | mpiCommandDelete | mpiCommandValidate


mpiCommandDelete

Declaration
long mpiCommandDelete(MPICommand  command)
Required Header stdmpi.h
Description

CommandDelete deletes a Command object and invalidates its handle (command). CommandDelete is the equivalent of a C++ destructor.

Return Values
MPIMessageOK if CommandDelete successfully deletes the Command object and invalidates its handle
See Also | mpiCommandCreate | mpiCommandValidate


mpiCommandLabel

Declaration
long mpiCommandLabel(MPICommand  command,
                     char        **label)
Required Header stdmpi.h
Description

CommandLabel gets the string from a Command and puts it in the location pointed to by label.

command | a handle to the Command object
**label | a pointer to a string returned by the method

Return Values
pointer | to a Command’s (command) label (that is in the location pointed to by label)
MPIMessageOK | if CommandLabel successfully returns a pointer to the Command’s label that is in the location pointed to by **label

See Also | mpiCommandCreate


mpiCommandParams

Declaration
long mpiCommandParams (MPICommand       command,
                       MPICommandParams *params)
Required Header stdmpi.h
Description

CommandParams gets the parameters from a Command and puts it in the location pointed to by params.

command | a handle to the Command object
*params | a pointer to a MPICommandParams structure returned by the method

Return Values
Command (command) parameters | in the structure pointed to by params
MPIMessageOK | if CommandParams successfully gets and writes the command parameters into *params

See Also | mpiCommandCreate | MPICommandParams


mpiCommandType

Declaration
long mpiCommandType(MPICommand      command,
                    MPICommandType  *type)
Required Header stdmpi.h
Description

CommandType gets the type from a Command and puts it in the location pointed to by type.

command | a handle to the Command object
*type | a pointer to a MPICommandType returned by the method

Return Values
Command (command) parameters | in the location pointed to by type
MPIMessageOK | if CommandType successfully gets and writes the command type into *type

See Also | mpiCommandCreate | MPICommandType


mpiCommandValidate

Declaration
long mpiCommandValidate(MPICommand  command)
Required Header stdmpi.h
Description

CommandValidate validates the Command object and its handle (command).

Return Values
MPIMessageOK if the Command object and its handle are valid
See Also | mpiCommandCreate | mpiCommandValidate


Compare Objects

.

Compare Objects

Introduction

A Compare object manages a compare engine in the motion controller hardware. The compare engine compares the actual position feedback from a motor to a preloaded position value. When the actual position feedback exceeds the value, the compare engine sets an output bit to the specified state. Since the compare occurs in hardware, the latency is minimal.

Typically, the MPI is used to configure the compare engine, load the compare value, and arm the compare. The condition of the compare engine can be determined by reading its status.

Methods

Create, Delete, Validate Methods
 | mpiCompareCreate | Create Compare object
 | mpiCompareDelete | Delete Compare object
 | mpiCompareValidate | Validate Compare object

Configuration and Information Methods
 | mpiCompareConfigGet | Get Compare configuration
 | mpiCompareConfigSet | Set Compare configuration
 | mpiCompareFlashConfigGet | Get flash configuration for Compare
 | mpiCompareFlashConfigSet | Set flash configuration for Compare
 | mpiCompareStatus | Get Compare's status

Memory Methods
 | mpiCompareMemory | Set Compare memory address
 | mpiCompareMemoryGet | Copy bytes of Compare memory to application memory
 | mpiCompareMemorySet | Copy bytes of application memory to Compare memory

Action Methods
 | mpiCompareArm | Arm Compare object
 | mpiCompareLoad |

Relational Methods
 | mpiCompareControl | Return handle of Control that is assoiciated with Compare
 | mpiCompareNumber | Get index of Compare (for Control list)

Data Types

MPICompareConfig / MEICompareConfig
MPICompareMessage
MPICompareParams
MPIComparePosition
MPICompareState
MPICompareStatus

Constants

MPIComparePositionCountMAX


MPICompareConfig and MEICompareConfig

.

MPICompareConfig / MEICompareConfig

MPICompareConfig

typedef struct MPICompareConfig {
    MPIIoTrigger    trigger;    /* which output to use... */
} MPICompareConfig;
Description
trigger type, source, mask, and pattern used to select the state of the compare output bit upon reaching the compare position. For more information about setting the trigger please see MPIIoTrigger.

MEICompareConfig

typedef struct MEICompareConfig {
    long                    continuous;
    MEICompareDivByNConfig  divByN;
} MEICompareConfig;
Description

Event compare mode (default) uses a handshake to ensure hardware/software synchronization. A single rising edge and single falling edge on the compare output is guaranteed. This mode is useful when re-arming compare objects is required for multiple compare position. There is system overhead to re-arm compare events.

Continuous compare mode constantly compares the compare position register to the position counter. The compare output is toggled based on compare logic, without software system notification and without the need to re-arm. This mode is useful when a single compare position is required for a valid compare output whenever the position is past some limit. If the position feedback during a move is not monotonic at the compare value (jitters back and forth), the compare output will change state each time the position crosses the compare value.

See Also | MPIIoTrigger | mpiCompareConfigGet | mpiCompareConfigSet


MPICompareMessage

MPICompareMessage

typedef enum {
    MPICompareMessageCOMPARE_INVALID,
} MPICompareMessage;

Description
 | MPICompareMessageCOMPARE_INVALID | compare handle is invalid
See Also


MPICompareParams

MPICompareParams

typedef struct MPICompareParams {
    long                position;
    long                outputState;
    MPICommandOperator  commandOperator;
} MPICompareParams;

Description
 | position | actual position at which to toggle output bit.
 | outputState | state of output bit upon reaching the compare position. Set to TRUE (on) or FALSE (off).
 | commandOperator | logical operator for compare position.
Remarks

Valid values for commandOperator are MPICommandOperatorLESS_OR_EQUAL and
MPICommandOperatorGREATER. Based on the commandOperator, the specified outputState of the bit will be set on one side or the other of the compare position.

The commandOperator logic is usually set depending on the direction of travel toward the compare position.

See Also


MPIComparePosition

MPIComparePosition

typedef struct MPIComparePosition {
    long                number;
    long                motorNumber;
    long                position;
    MPICommandOperator  commandOperator;
} MPIComparePosition;

Description - This structure is currently not supported and is reserved for future use.
 | number | capture number
 | motorNumber | number of the motor whose position to compare
 | position | compare position on which to set the output bit
 | commandOperator | logical operator for the compare position
See Also


MPIComparePositionCountMAX

Declaration
#define MPIComparePositionCountMAX (10)
/* Maximum latches/compare */
Required Header stdmpi.h
Description

See MPICompareStatus for a description.
See Also


MPICompareState

MPICompareState

typedef enum {
    MPICompareStateINVALID,

    MPICompareStateIDLE,
    MPICompareStateARMED,
    MPICompareStateCOMPARED,
} MPICompareState;

Description
 | MPICompareStateIDLE | Not armed or compared
 | MPICompareStateARMED | Looking for compare position(s)
 | MPICompareStateCOMPARED | Compare position found

See Also | MPICompareStatus


MPICompareStatus

MPICompareStatus

#define MPIComparePositionCountMAX (10)  /* Maximum latches/compare */

typedef enum {
    MPICompareStateINVALID,

    MPICompareStateIDLE,
    MPICompareStateARMED,
    MPICompareStateCOMPARED,
} MPICompareState;

typedef struct MPICompareStatus {
    MPICompareState   state;
    double            position[MPIComparePositionCountMAX];
} MPICompareStatus;

Description
 | State- contains the current state of the compare register:
 |  | Idle | Not armed or compared
 |  | Armed | Looking for compare position(s)
 |  | Compared | Compare position found
 | Position- array containing the controller's compared position value(s).

See Also | MPICompareState


mpiCompareArm

Declaration
long mpiCompareArm(MPICompare  compare,
                   long        arm)
Required Header stdmpi.h
Description

CompareArm sets the MPICompareState to MPICompareStateIDLE (arm = FALSE), or MPICompareStateARMED (arm = TRUE).

Return Values
MPIMessageOK if the Compare object is successfully armed or disarmed.
See Also | MPICompareState


mpiCompareConfigGet

Declaration
long mpiCompareConfigGet(MPICompare       compare,
                         MPICompareConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

CompareConfigGet gets a Compare object’s (compare) configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The a Compare object’s configuration information in external is in addition to the Compare object’s configuration information in config, i.e, the Compare object’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEICompareConfig{} or is NULL.

Return Values
MPIMessageOK if CompareConfigGet successfully writes the Compare object’s configuration to the structure(s)
See Also | mpiCompareConfigSet | MEICompareConfig


mpiCompareConfigSet

Declaration
long mpiCompareConfigSet(MPICompare       compare,
                         MPICompareConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

CompareConfigSet sets a Compare object’s (compare) configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Compare object’s configuration information in external is in addition to the Compare object’s configuration information in config, i.e, the Compare object’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEICompareConfig{} or is NULL.

Return Values
MPIMessageOK if CompareConfigSet successfully sets the Compare object’s configuration using data from the structure(s)
See Also | mpiCompareConfigGet | MEICompareConfig


mpiCompareControl

Declaration
MPIControl  mpiCompareControl(MPICompare compare)
Required Header stdmpi.h
Description

CompareControl returns a handle to the motion controller (Control object) that a Compare object (compare) is associated with.

Return Values
handle | to a Control object that a Compare object is associated with
MPIHandleVOID | if the Compare object is invalid
See Also


mpiCompareCreate

Declaration
MPICompare mpiCompareCreate(MPIControl   control,
                            long         number)
Required Header stdmpi.h
Description

CompareCreate creates a Compare object associated with a number (number), that is located on a motion controller (control).

CompareCreate is the equivalent of a C++ constructor. Each motion block supports 10 compare registers. The default configuration is two compare registers per motor, while the last two (8,9) on each motion block are reserved for the Auxiliary Encoder (not supported). The compare registers are default mapped as follows: 0 and 1 for Motor0; 2 and 3 for Motor1; 10 and 11 for Motor4; etc. The first Compare for each motor uses the default (primary) encoder input for position compare. The second uses the AUX encoder input.

Return Values
handle | to a Compare object
MPIHandleVOID | if the object could not be created

See Also | mpiCompareCreate | mpiCommandValidate


mpiCompareDelete

Declaration
long mpiCompareDelete(MPICompare  compare)
Required Header stdmpi.h
Description

CompareDelete deletes a Compare object and invalidates its handle (compare). CompareDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if CompareDelete successfully deletes the Compare object and invalidates its handle
See Also | mpiCommandCreate | mpiCommandValidate


mpiCompareFlashConfigGet

Declaration
long mpiCompareFlashConfigGet(MPICompare       compare,
                              void             *flash,
                              MPICompareConfig *config,
                              void             *external)
Required Header stdmpi.h
Description

CompareFlashConfigGet gets a Compare object’s (compare) flash configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Compare object’s flash configuration information in external is in addition to the Compare object’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEICompareConfig{} or is NULL.

Return Values
MPIMessageOK if CompareFlashConfigGet successfully writes the Compare object’s flash configuration to the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIFlash | mpiCompareFlashConfigSet | MEICompareConfig


mpiCompareFlashConfigSet

Declaration
long mpiCompareFlashConfigSet(MPICompare       compare,
                              void             *flash,
                              MPICompareConfig *config,
                              void             *external)
Required Header stdmpi.h
Description

CompareFlashConfigSet sets a Compare object’s (compare) flash configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Compare object’s flash configuration information in external is in addition to the Compare object’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEICompareConfig{} or is NULL.

Return Values
MPIMessageOK if CompareFlashConfigSet successfully sets the Compare object’s flash configuration using data from the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIFlash | mpiCompareFlashConfigGet | MEICompareConfig


mpiCompareLoad

Declaration
long mpiCompareLoad(MPICompare       compare,
                    MPICompareParams *params,
                    void             *external)
Required Header stdmpi.h
Description

CompareLoad loads a Compare object’s (compare) parameters using data from the structure pointed to by params, and also using data from the implementation-specific structure.

Return Values
MPIMessageOK if CompareLoad successfully loads the Compare object's parameters using the data from the structure.
See Also


mpiCompareMemory

Declaration
long mpiCompareMemory(MPICompare   compare,
                      void         **memory)
Required Header stdmpi.h
Description

CompareMemory writes an address [which is used to access a Compare object’s (compare) memory] to the contents of memory. This address, or an address calculated from it, can be passed as the src parameter to mpiCompareMemoryGet(...) and as the dst parameter to mpiCompareMemorySet(...).

Return Values
MPIMessageOK if CompareMemory successfully writes the Compare object’s memory address to the contents of memory
See Also | mpiCompareMemoryGet | mpi CompareMemorySet


mpiCompareMemoryGet

Declaration
long mpiCompareMemoryGet(MPICompare  compare,
                         void        *dst,
                         void        *src,
                         long        count)
Required Header stdmpi.h
Description

CompareMemoryGet copies count bytes of a Compare object’s (compare) memory (starting at address src) and writes them into application memory (starting at address dst).

Return Values
MPIMessageOK if CompareMemoryGet successfully copies data from Compare memory to application memory
See Also | mpiCompareMemorySet | mpiCompareMemory


mpiCompareMemorySet

Declaration
long mpiCompareMemorySet(MPICompare  compare,
                         void        *dst,
                         void        *src,
                         long        count)
Required Header stdmpi.h
Description

CompareMemorySet copies count bytes of application memory (starting at address src) and writes them into a Compare object’s (compare) memory (starting at address dst).

Return Values
MPIMessageOK if CompareMemoryGet successfully copies data from application memory to Compare memory
See Also | mpiCompareMemoryGet | mpiCompareMemory


mpiCompareNumber

Declaration
long mpiCompareNumber(MPICompare   compare,
                      long         *number)
Required Header stdmpi.h
Description

CompareNumber writes the index of a Compare object (compare, on the motion controller that compare is associated with) to the contents of number.

Return Values
MPIMessageOK if CompareNumber successfully writes the index of a Compare object to the contents of number
See Also


mpiCompareStatus

Declaration
long mpiCompareStatus(MPICompare        compare,
                      MPICompareStatus  *status,
                      void              *external)
Required Header stdmpi.h
Description

CompareStatus writes a Compare object’s (compare) status into the structure pointed to by status, and also into the implementation-specific structure pointed to by external (if external is not NULL).

The Compare object’s status information in external is in addition to the Compare object’s status information in status, i.e, the status configuration information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEICompareStatus{} or is NULL.

Return Values
MPIMessageOK if CompareStatus successfully writes the status of a Compare object to the structure(s)
See Also


mpiCompareValidate

Declaration
long mpiCompareValidate(MPICompare  compare)
Required Header compare.h
Description

CompareValidate validates the Compare object and its handle (compare).

Return Values
MPIMessageOK if Compare is a handle to a valid object.
See Also | mpiCompareCreate | mpiCompareDelete


Control Objects

.

Control Objects

Introduction

A Control object manages a motion controller device. The device is typically a single board residing in a PC or an embedded system. A control object can read and write device memory through one of a variety of methods: I/O port, memory mapped or device driver.

For the case where the application and the motion controller device exist on two physically separate platforms connected by a LAN or serial line, the application creates a client control object which communicates via remote procedure calls with a server.

Unlike the methods of all other objects in the MPI, Control object methods are not thread-safe.

Are you using TCP/IP and Sockets? If yes, click here.

Methods

Create, Delete, Validate Methods
 | mpiControlCreate | Create Control object
 | mpiControlDelete | Delete Control object
 | mpiControlValidate | Validate Control object

Configuration and Information Methods
 | mpiControlAddress | Get original address of Control object (when it was created)
 | mpiControlConfigGet | Get Control config
 | mpiControlConfigSet | Set Control config
 | meiControlExtMemAvail |
 | mpiControlFlashConfigGet | Get Control flash config
 | mpiControlFlashConfigSet | Set Control flash config
 | meiControlGateGet | Get the closed state (TRUE or FALSE)
 | meiControlGateSet | Set the closed state (TRUE or FALSE)
 | mpiControlIoGet |
 | mpiControlIoSet |
 | meiControlIoBitGet |
 | meiControlIoBitSet |
 | meiControlSampleCounter |
 | meiControlSamplestoSeconds | Converts samples to seconds
 | meiControlSampleWait |
 | meiControlSecondstoSamples | Converts seconds to samples
 | mpiControlType | Get type of Control object (used to create Command object)
 | meiControlVersionGet | Read the version of XMP firmware
 | meiControlVersionSet | Write the version of XMP firmware

Memory Methods
 | mpiControlMemory | Get address of Control memory
 | mpiControlMemoryAlloc | Allocate bytes of firmware memory
 | mpiControlMemoryCount | Get number of bytes available in firmware
 | mpiControlMemoryFree | Free bytes of firmware memory
 | mpiControlMemoryGet | Copy count bytes of Control memory to application memory
 | mpiControlMemorySet | Copy count bytes of application memory to Control memory

Relational Methods
meiControlPlatform

Action Methods
 | mpiControlCycleWait | Wait for Control to execute count cycles
 | mpiControlInit | Initialize Control object
 | mpiControlInterruptEnable | Enable interrupts to Control object
 | mpiControlInterruptWait | Wait for controller interrupt
 | mpiControlInterruptWake | Wake all threads waiting for controller interrupt
 | mpiControlReset | Reset controller hardware
 | meiControlSampleWait | Specify how many samples the host waits for, while the XMP executes

Data Types

MPIControlAddress
MPIControlConfig / MEIControlConfig
MPIControlIo
MEIControlIoBit
MPIControlIoWords
MEIControlInput
MPIControlMessage / MEIControlMessage
MPIControlMemoryType
MEIControlOutput
MEIControlTrace
MPIControlType
MEIControlVersion


MPIControlAddress

MPIControlAddress

typedef struct MPIControlAddress {
    long	number;	/* controller number */

    union {
        void		  *mapped;	/* memory address */
        unsigned long	  ioPort;	/* I/O port number */
        char		  *device;   	/* device driver name */
        struct {
            char		*name;	/* image file name */
            MPIControlFileType   type;	/* image file type */
        } file;
        struct {
            char	*server;	/* IP address: host.domain.com */
            long	port;	   	/* socket number */
        } client;
    } type;
} MPIControlAddress;
Description

ControlAddress is a structure that specifies the location of the controller that to be accessed when mpiControlCreate() is called. Please refer to the documentation for mpiControlCreate() to see how to use this structure.

number | The controller number in the computer
type | A union that holds information about controllers on non-local computers.

See Also |
 | MPIControl | MPIControlType | mpiControlCreate


MPIControlConfig and MEIControlConfig

.

MPIControlConfig / MEIControlConfig

MPIControlConfig

typedef struct MPIControlConfig {
    long	adcCount;
    long	axisCount;
    long	captureCount;
    long	compareCount;
    long	cmdDacCount;
    long	auxDacCount;
    long	filterCount;
    long	motionCount;
    long	motorCount;
    long	recordCount;
    long	sequenceCount;
    long	userVersion;
    long	sampleRate;

} MPIControlConfig;
Description

The ControlConfig structure specifies the controller configurations. It allocates the number of resources and configurations for the controller's operation. The controller's performance is inversely related to the DSP's load. The controller configuration structure allows the user to disable/enable objects for optimum performance.

For SynqNet controllers, changing the sampleRate or TxTime will cause the SynqNet network to be shutdown and re-initialized using the new sampleRate or TxTime values.
adcCount | Number of local ADC (analog to digital converter) objects enabled for the controller. The adcCount is only valid for controllers that support local ADC hardware. For controllers that do not have local ADCs, set adcCount to zero.
axisCount | Number of axis objects enabled for the controller. The controller's axis object handles the trajectory calculations for command position. For simple systems, set the axisCount equal to the motorCount.
captureCount | Number of capture objects enabled for the controller. The controller's capture object manages the hardware resources to latch a motor's position feedback, triggered by a motor's input.
compareCount | Number of compare objects enabled for the controller. The controller's compare object manages the hardware resources to trigger a motor's output, triggered by a comparison between the motor's feedback and a pre-loaded position value.
cmdDacCount | Number of command DACs (digital to analog converter) enabled for the controller. The controller's cmdDac transmits and scales a torque demand value to a SynqNet servo drive or a physical DAC circuit. There is one cmdDac per motor. Normally, the cmdDacCount should be equal to the motorCount.
auxDacCount | Number of auxilliary DACs (digital to analog converter) enabled for the controller. The controller's auxDac transmits and scales a torque demand value to a SynqNet servo drive or a physical DAC circuit. Auxilliary DACs can be used for sinusoidal motor commutation, where the cmdDac and auxDac provide the commutation phases. Or, auxilliary DACs can be used for general purpose analog outputs. There is one auxDac per motor.
filterCount | Number of filter objects enabled for a controller. The filter object handles the closed-loop servo calculations to control the motor. For simple systems, set the filterCount equal to the motorCount.
motionCount | Number of motion supervisor obejcts enabled for a controller. The controller's motion supervisor handles coordination of motion and events for an axis or group of axes. For simple systems, set the motionCount equal to the axisCount.
motorCount | Number of motor objects enabled for a controller. The controller's motor object handles the interface to the servo or stepper drive, dedicated I/O and general purpose motor related I/O. For simple systems, the motorCount should equal the number of physical motors connected to the controller (either directly or via SynqNet).
recordCount | Number of records for the controller's data recorder buffer. Each data record is 32 bits. The controller's data recorder buffer can be dynamically allocated by changing the recordCount. A larger data recorder buffer may be required for higher sample rates, slow host computers, when running via client/server, or when a large number of data fields are being recorded.
sequenceCount | Number of sequence objects enabled for the controller. The controller's sequence object executes and manages a sequence of pre-compiled controller commands.
userVersion | A 32 bit user defined field. The userVersion can be used to mark a firmware image with an identifier. This is useful if multiple controller firmware images are saved to a file.
sampleRate

Number of controller foreground update cycles per second. For SynqNet controllers, this is also the cyclic update rate for the SynqNet network. During the controller's foreground cycle, the axis trajectories are calculated, the filters (closed-loop servo control) are calculated, motion is coordinated, the SynqNet data buffers are updated, and other time critical operations are performed.The default sample rate is 2000 (period = 500 microseconds). The minimum sampleRate for SynqNet systems is 1000 (period = 1 millisecond). The maximum is dependent on the controller hardware and processing load.

There are several factors that must be considered to find an appropriate sampleRate for a system. The servo performance, the motion profile accuracy, the SynqNet network cyclic rate, the SynqNet drive update rates, controller background cycle update rate, and controller/application performance.

For SynqNet systems, select a sampleRate that is a common multiple of the SynqNet drives connected to the network. For example, if the drive update rate is 8kHz, then appropriate controller sample rates are: 16000, 8000, 5333, 4000, 3200, 2667, 2286, 2000, 1778, 1600, 1455, 1333, 1231, 1067, and 1000

MEIControlConfig

typedef struct MEIControlConfig {
    long               preFilterCount;
    long               compensatorCount;
    long               TxTime;
    MEIXmpPreFilter    PreFilter[MEIXmpMAX_PreFilters];
    MEIXmpCompensator  Compensator[MEIXmpMAX_Compensators];
    long               CompensationTable[MEIXmpCompTableSize];
    MEIXmpUserBuffer   UserBuffer;
} MEIControlConfig;

Description
 | preFilterCount | This value defines the number of enabled pre-filters.
 | compensatorCount | This value defines the number of enabled compensators.
 | TxTime | This value determines the controller's transmit time for the SynqNet data. The units are a percentage of the sample period. The default is 75%. Smaller TxTime values will reduce the latency between when the controller receives the data, calculates the outputs, and transmits the data. If the TxTime is too small, the data will be sent before the controller updates the buffer, which will cause a TX_FAILURE event.
 | PreFilter | This array defines the configuration for each pre-filter.
 | Compensator | This array defines the configuration for each compensator.
 | CompensationTable | This array defines the compensation values for the compensators.
 | UserBuffer | This structure defines the controller's user buffer. This is used for custom features that require a controller data buffer.

See Also | mpiControlConfigGet | mpiControlConfigSet | meiControlExtMemAvail | Special Note on Dynamic Allocation of External Memory Buffers.


MPIControlIo

MPIControlIo

typedef struct MPIControlIo {
    unsigned long   input[MPIControlIoWords];
    unsigned long   output[MPIControlIoWords]
} MPIControlIo;
Description

The ControlIo structure contains controller's local digital input and output states. The digital inputs can be read and the digital outputs can be read or written through this structure.

input | An array of digital input values. Each bit mask is defined by the MEIControlInput enumeration.
output | An array of digital output values. Each bit mask is defined by the MEIControlOutput enumeration.

See Also | MEIControlOutput | MEIControlInput | mpiControlIoGet | mpiControlIoSet


MEIControlIoBit

Declaration
typedef enum {

    MEIControlIoBitUSER_0_IN,
    MEIControlIoBitUSER_1_IN,
    MEIControlIoBitUSER_2_IN,
    MEIControlIoBitUSER_3_IN,
    MEIControlIoBitUSER_4_IN,
    MEIControlIoBitUSER_5_IN,
    MEIControlIoBitUSER_0_OUT,
    MEIControlIoBitUSER_1_OUT,
    MEIControlIoBitUSER_2_OUT,
    MEIControlIoBitUSER_3_OUT,
    MEIControlIoBitUSER_4_OUT,
    MEIControlIoBitUSER_5_OUT,

} MEIControlIoBit;
Required Header stdmpi.h
Description

ControlIoBit is an enumeration of a controller's local digital I/O bit numbers.

MEIControlIoBitUSER_0_IN | controller's local input, bit number 0
MEIControlIoBitUSER_1_IN | controller's local input, bit number 1
MEIControlIoBitUSER_2_IN | controller's local input, bit number 2
MEIControlIoBitUSER_3_IN | controller's local input, bit number 3
MEIControlIoBitUSER_4_IN | controller's local input, bit number 4
MEIControlIoBitUSER_5_IN | controller's local input, bit number 5
MEIControlIoBitUSER_0_OUT | controller's local output, bit number 0
MEIControlIoBitUSER_1_OUT | controller's local output, bit number 1
MEIControlIoBitUSER_2_OUT | controller's local output, bit number 2
MEIControlIoBitUSER_3_OUT | controller's local output, bit number 3
MEIControlIoBitUSER_4_OUT | controller's local output, bit number 4
MEIControlIoBitUSER_5_OUT | controller's local output, bit number 5

Return Values
MPIMessageOK | if ControlIoGet successfully gets the I/O bits from controller and puts (writes) them in the structure.
MPIMessageARG_INVALID | if the io pointer points to NULL.

See Also | meiControlIoBitGet | meiControlIoBitSet


MPIControlIoWords

MPIControlIoWords

#define  MPIControlIoWords   (1)
Description

ControlIoWords defines the number of 32 bit Input and Output words on the controller.

See Also | MPIControlIo | MEIControlIoBit | MEIControlInput | MEIControlOutput


MEIControlInput

MEIControlInput

typedef enum {
    MEIControlInputUSER_0   = MEIXmpControlIOMaskUSER0_IN,
    MEIControlInputUSER_1   = MEIXmpControlIOMaskUSER1_IN,
    MEIControlInputUSER_2   = MEIXmpControlIOMaskUSER2_IN,
    MEIControlInputUSER_3   = MEIXmpControlIOMaskUSER3_IN,
    MEIControlInputUSER_4   = MEIXmpControlIOMaskUSER4_IN,
    MEIControlInputUSER_5   = MEIXmpControlIOMaskUSER5_IN,
    MEIControlInputXESTOP   = MEIXmpControlIOMaskXESTOP,
} MEIControlInput;
Description

ControlInput is an enumeration of a controller's local digital input bit masks. Each mask represents a discrete input.

See Also | mpiControlIoGet | mpiControlIoSet | MEIControlOutput


MPIControlMemoryType

MPIControlMemoryType

typedef enum {
    MPIControlMemoryTypeUSER,
    MPIControlMemoryTypeDEFAULT = MPIControlMemoryTypeUSER
} MPIControlMemoryType;
Description

ControlMemoryType is an enumeration of controller memory types. The controller memory contains static and dynamic regions. The controller firmware defines the regions and the MPI configures the dynamic memory.

MPIControlMemoryTypeUSER | The dynamic portion of the controller's external memory that is not in use by the controller.
MPIControlMemoryTypeDEFAULT | Defined as MPIControlMemoryTypeUSER.

See Also | mpiControlMemoryAlloc | mpiControlMemoryCount | mpiControlMemoryFree | mpiControlConfigGet | mpiControlConfigSet


MPIControlMessage and MEIControlMessage

.

MPIControlMessage / MEIControlMessage

MPIControlMessage

typedef enum {
    MPIControlMessageLIBRARY_VERSION,   /* Keep as first control message */
    MPIControlMessageADDRESS_INVALID,
    MPIControlMessageCONTROL_INVALID,
    MPIControlMessageCONTROL_NUMBER_INVALID,
    MPIControlMessageTYPE_INVALID,
    MPIControlMessageINTERRUPTS_DISABLED,
    MPIControlMessageEXTERNAL_MEMORY_OVERFLOW,
    MPIControlMessageADC_COUNT_INVALID,
    MPIControlMessageAXIS_COUNT_INVALID,
    MPIControlMessageCAPTURE_COUNT_INVALID,
    MPIControlMessageCOMPARE_COUNT_INVALID,
    MPIControlMessageCMDDAC_COUNT_INVALID,
    MPIControlMessageAUXDAC_COUNT_INVALID,
    MPIControlMessageFILTER_COUNT_INVALID,
    MPIControlMessageMOTION_COUNT_INVALID,
    MPIControlMessageMOTOR_COUNT_INVALID,
    MPIControlMessageSAMPLE_RATE_TO_LOW,
} MPIControlMessage;

Description
MPIControlMessageLIBRARY_VERSION
 | The MPI Library does not match the application. This message code is returned by mpiControlInit(…) if the MPI's library (DLL) version does not match the MPI header files that were compiled with the application. To correct this problem, the application must be recompiled using the same MPI software installation version that the application uses at run-time.
MPIControlMessageADDRESS_INVALID
 | The controller address is not valid. This message code is returned by mpiControlInit(…) if the controller address is not within a valid memory range. mpiControlInit(…) only requires memory addresses for certain operating systems. To correct this problem, verify the controller memory address.
MPIControlMessageCONTROL_INVALID
 | Not supported.
MPIControlMessageCONTROL_NUMBER_INVALID
 | The controller number is out of range. This message code is returned by mpiControlInit(…) if the controller number is less than zero or greater than or equal to MaxBoards(8).
MPIControlMessageTYPE_INVALID
 | The controller type is not valid. This message code is returned by mpiControlInit(…) if the controller type is not a member of the MPIControlType enumeration.
MPIControlMessageINTERRUPTS_DISABLED
 | The controller interrupt is disabled. This message code is returned by mpiControlInterruptWait(…) if the controller's interrupt is not enabled. This prevents an application from waiting for an interrupt that will never be generated. To correct this problem, enable controller interrupts with mpiControlInterruptEnable(…) before waiting for an interrupt.
MPIControlMessageEXTERNAL_MEMORY_OVERFLOW
 | The controller's external memory will overflow. This message code is returned by mpiControlConfigSet(…) if the dynamic memory allocation exceeds the external memory available on the controller. To correct the problem, reduce the number/size of control configuration resources or use a controller model with a larger static memory component.
MPIControlMessageADC_COUNT_INVALID
 | The ADC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of ADCs is greater than MEIXmpMAX_ADCs.
MPIControlMessageAXIS_COUNT_INVALID
 | The axis count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of axes is greater than MEIXmpMAX_Axes.
MPIControlMessageCAPTURE_COUNT_INVALID
 | The capture count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of captures is greater than MEIXmpMAX_Captures.
MPIControlMessageCOMPARE_COUNT_INVALID
 | The compare count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of compares is greater than MEIXmpMAX_Compares.
MPIControlMessageCMDDAC_COUNT_INVALID
 | The command DAC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of command DACs is greater than MEIXmpMAX_DACs.
MPIControlMessageAUXDAC_COUNT_INVALID
 | The auxiliary DAC count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of auxiliary DACs is greater than MEIXmpMAX_DACs.
MPIControlMessageFILTER_COUNT_INVALID
 | The filter count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of filters is greater than MEIXmpMAX_Filters.
MPIControlMessageMOTION_COUNT_INVALID
 | The motion count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of motions is greater than MEIXmpMAX_MSs.
MPIControlMessageMOTOR_COUNT_INVALID
 | The motor count is not valid. This message code is returned by mpiControlConfigSet(…) if the number of motors is greater than MEIXmpMAX_Motors.
MPIControlMessageSAMPLE_RATE_TO_LOW
 | The controller sample rate is too small. This message code is returned by mpiControlConfigSet(…) if the sample rate is less than 1000. SynqNet does not support cyclic data rates below 1kHz. The controller's sample rate specifies the SynqNet cyclic rate.

MEIControlMessage

typedef enum {
    MEIControlMessageFIRMWARE_INVALID,
    MEIControlMessageFIRMWARE_VERSION_NONE,
    MEIControlMessageFIRMWARE_VERSION,
    MEIControlMessageFPGA_SOCKETS,
    MEIControlMessageBAD_FPGA_SOCKET_DATA,
    MEIControlMessageNO_FPGA_SOCKET,
    MEIControlMessageINVALID_BLOCK_COUNT,
    MEIControlMessageSYNQNET_OBJECTS,
    MEIControlMessageSYNQNET_STATE,
    MEIControlMessageIO_BIT_INVALID,
} MEIControlMessage;

Description
MEIControlMessageFIRMWARE_INVALID
 | The controller firmware is not valid. This message code is returned by mpiControlInit(…) if the MPI library does not recognize the controller signature. After power-up or reset, the controller loads the firmware from flash memory. When the firmware executes, it writes a signature value into external memory. If mpiControlInit(…) does not recognize the signature, then the firmware did not execute properly. To correct this problem, download firmware and verify the controller hardware is working properly.
MEIControlMessageFIRMWARE_VERSION_NONE
 | The controller firmware version is zero. This message code is returned by control methods do not find a firmware version. This indicates the firmware did not execute at controller power-up or reset. To correct this problem, download firmware and verify the controller hardware is working properly.
MEIControlMessageFIRMWARE_VERSION
 | The controller firmware version does not match the software version. This message code is returned by control methods if the firmware version is not compatible with the MPI library. To correct this problem, either download compatible firmware or install a compatible MPI run-tim library.
MEIControlMessageFPGA_SOCKETS
 | The maximum number of FPGA socket types has been exceeded. This message code is returned by meiFlashMemoryFromFile(…) if the controller has more FPGA types than the controller has flash memory space to support them.
MEIControlMessageBAD_FPGA_SOCKET_DATA
 | Not supported.
MEIControlMessageNO_FPGA_SOCKET
 | The FPGA socket type does not exist. This message code is returned by meiFlashMemoryFromFile(…) if the controller does not support the FPGA type that was specified in the FPGA image file. To correct this problem, use a different FPGA image that is compatible with the controller.
MEIControlMessageINVALID_BLOCK_COUNT
 | Not supported.
MEIControlMessageSYNQNET_OBJECTS
 | Not supported.
MEIControlMessageSYNQNET_STATE
 | The controller's SynqNet state is not expected. This message code is returned by mpiControlInit(…), mpiControlReset(…) and mpiControlConfigSet(…) if the SynqNet network initialization fails to reach the SYNQ state. To correct this problem, check your node hardware and network connections.
MEIControlMessageIO_BIT_INVALID
 | The controller I/O bit is not valid. This message code is returned by meiControlIoBitGet(...) or meiControlIoBitSet(…) if the controller I/O bit is not a member of the MEIControlIoBit enumeration.
See Also


MEIControlOutput

MEIControlOutput

typedef enum {
    MEIControlOutputUSER_0  = MEIXmpControlIOMaskUSER0_OUT,
    MEIControlOutputUSER_1  = MEIXmpControlIOMaskUSER1_OUT,
    MEIControlOutputUSER_2  = MEIXmpControlIOMaskUSER2_OUT,
    MEIControlOutputUSER_3  = MEIXmpControlIOMaskUSER3_OUT,
    MEIControlOutputUSER_4  = MEIXmpControlIOMaskUSER4_OUT,
    MEIControlOutputUSER_5  = MEIXmpControlIOMaskUSER5_OUT,
} MEIControlOutput;
Description

ControlOutput is an enumeration of a controller's local digital output bit masks. Each mask represents a discrete output.

See Also | mpiControlIoGet | mpiControlIoSet | MEIControlInput


MEIControlTrace

MEIControlTrace

typedef enum {
    MEIControlTraceDYNA_ALLOC  = MEIControlTraceFIRST << 0,
} MEIControlTrace;
Description

ControlTrace is an enumeration of control object trace bits to enable debug tracing.

MEIControlTraceDYNA_ALLOC | This trace bit enables tracing for calls that dynamically allocate controller memory.
See Also


MPIControlType

MPIControlType

typedef enum {
    MPIControlTypeDEFAULT,
    MPIControlTypeMAPPED,
    MPIControlTypeIOPORT,
    MPIControlTypeDEVICE,
    MPIControlTypeCLIENT,
    MPIControlTypeFILE,
} MPIControlType;
Description

ControlType is an enumeration that specifies the type of controller that needs to be accessed when mpiControlCreate() is called. Please refer to the documentation for mpiControlCreate() to see how to use this enumeration.

See Also | MPIControl | mpiControlCreate | mpiControlType


MEIControlVersion

MEIControlVersion

typedef struct MEIControlVersion {
    struct {   /* control.c */
        char   *version;   /* MEIControlVersionMPI (YYYYMMDD) */

        struct {   /* xmp.h */
            long    version;    /* MEIXmpVERSION */
            long    option;     /* MEIXmpOPTION */
        } firmware;
    } mpi;

    struct {
        long    version; /* hardware version */

        struct {   /* MEIXmpData.SystemData{} */
            long    version;    /* MEIXmpVERSION_EXTRACT(SoftwareID) */
            char    revision;   /* ('A' - 1) + MEIXmpREVISION_EXTRACT(SoftwareID) */
            long    subRevision;    /* MEIXmpSUB_REV_EXTRACT(Option) */
            long    developmentId;  /* MEIXmpDEVELOPMENT_ID_EXTRACT(Option) */
            long    option;         /* MEIXmpOPTION_EXTRACT(Option) */
            long    userVersion;
            long    branchId;
     } firmware;

     struct {
        struct {
            long    version;
            long    option;
        } busInterface;
        struct {
             char number[10];
             char rev[5];
          } model;
       } board;
    } xmp;
} MEIControlVersion;
Description

ControlVersion is a structure that specifies the version information for the MPI and the controller's firmware, FPGAs, and the bus interface.

mpi | A structure that contains the version information of the MPI
mpi.version | A string representing the version of the MPI. The version of the MPI is broken down by date, branch, and revision (MPIVersion.branch.revision). For ex: 20021220.1.2 means MPI version 20021220, branch 1, revision 2.
mpi.firmware | The firmware version information that the current version of the MPI will work with. A new field has been added to the XMP's firmware to identify and differentiate between intermediate branch software revisions. The branch value is represented as a hex number between 0x00000000 and 0xFFFFFFFF. Each digit represents an instance of a branch (0x1 to 0xF). A single digit represents a single branch from a specific version, two digits represent a branch of a branch, three digits represent a branch of a branch of a branch, etc.
xmp | A structure that contains the version information of the XMP controller
xmp.firmware | The XMP's firmware version information.
xmp.motionBlock[] | An array of structures that contain version information about the motion blocks on the XMP.
xmp.board | An array of structures that contain version information about the XMP controller boards.
xmp.board.model.number | A string that contains the hardware model number for the controller.
xmp.board.model.rev | A string that contains the hardware revision for the controller.

See Also | MPIControl


mpiControlAddress

Declaration
long mpiControlAddress(MPIControl        control,
                       MPIControlAddress *address)
Required Header stdmpi.h
Description When a Control object (control) is created, an address is used. ControlAddress writes this address to the contents of address.
Return Values
MPIMessageOK if ControlAddress successfully writes the address (used when control was created) to the contents of address
See Also


mpiControlConfigGet

Declaration
long mpiControlConfigGet(MPIControl       control,
                         MPIControlConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

ControlConfigGet gets the configuration of a Control object (control) and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIControlConfig{} or is NULL.
Return Values
MPIMessageOK if ControlConfigGet successfully gets the control configuration and writes it in the structure(s)
See Also | mpiControlConfigSet | MEIControlConfig | Special Note on Dynamic Allocation of External Memory Buffers.


mpiControlConfigSet

Declaration
long mpiControlConfigSet(MPIControl       control,
                         MPIControlConfig *config,
                         void             *external)
Required Header stdmpi.h
Description

ControlConfigSet sets (writes) the Control object’s (control) configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEIControlConfig{} or is NULL.

Return Values
MPIMessageOK if ControlConfigSet successfully writes the Control object’s configuration using data from the structure(s)
See Also | mpiControlConfigGet | MEIControlConfig | Special Note on Dynamic Allocation of External Memory Buffers.


mpiControlCreate

Declaration
MPIControl mpiControlCreate(MPIControlType     type,
                            MPIControlAddress  *address)
Required Header stdmpi.h
Description

ControlCreate creates a Control object of the specified type and type-specific address. ControlCreate is the equivalent of a C++ constructor.
The type parameter determines the form of the address parameter:
If the "type" parameter is | Then the form of the "address" parameter is
MPIControlTypeDEFAULT | implementation-specific
MPIControlTypeMAPPED | MPIControlAddress.mapped
MPIControlTypeDEVICE | MPIControlAddress.device
MPIControlTypeCLIENT | MPIControlAddress.client
Note: This constructor does not reset or initialize the motion control device.
About MPIControlTypes:
If MPIControlType is | And MPIControlAddress is | Then the Board Number is | And the “address” parameter to be used is
DEFAULT | Null address | 0 address.number | default address parameter default address parameter
DEVICE | Null address | 0 address.number | default device driver address.type.device (if address.type.device is Null, then default device driver)
CLIENT | address | specified by server | address.type.client (NOTE: address.number should be set to zero)
  1. If the type is DEFAULT, then the address structure (if supplied) is referenced only for the board number. Note that even if the default type is DEVICE, the default device driver will be used and address.type.device will not be used.
  2. If the type is explicitly DEVICE, and the address is provided, then address.number will be used. If address.type.device is NULL, then the default device driver will be used. If address.type.device is not NULL, then the specified driver (DEVICE) will be used.

Sample Code

In general, if the caller specifies an explicit type (i.e., not DEFAULT), then the caller must
completely fill out the address.type structure.

A simple case that will work for almost anyone who wants to use board  #0:

mpiControlCreate(MPIControlTypeDEFAULT, NULL);

A simple case where board #1 is desired is:

    {
        MPIControlAddress address;
        address.number = 1;
        mpiControlCreate(MPIControlTypeDEFAULT, &address);
    }

Since the default MPIControlType = MPIControlTypeDEVICE, the address may be on the
stack with garbage for the device driver name. This isn’t a problem, however, because
the board number is the only field in address that will be used when the caller specifies
the DEFAULT MPIControlType.

Return Values
handle | to a Control object
MPIHandleVOID | if the object could not be created

See Also | MPIControl | MPIControlAddress | MPIControlType | mpiControlValidate mpiControlInit | mpiControlDelete


meiControlCycleWait

Declaration
long meiControlCycleWait(MPIControl control,
                         long       count)
Required Header stdmei.h
Description

ControlCycleWait waits for the XMP motion controller (control) to execute for count background cycles. The host will continuously verify that the XMP firmware is operational, and the host will give up its time slice as it waits (for the controller to execute the background cycles).
Return Values
MPIMessageOK after the motion controller successfully executes for count cycles
See Also


mpiControlDelete

Declaration
long mpiControlDelete(MPIControl control);
Required Header stdmpi.h
Description

ControlDelete deletes a control object and invalidates its handle. ControlDelete is the equivalent of a C++ destructor.

Return Values
MPIMessageOK if ControlDelete successfully deletes a Control object and invalidates its handle
See Also | mpiControlCreate | mpiControlValidate


meiControlExtMemAvail

Declaration
long meiControlExtMemAvail(MPIControl control,
                           long       *size)
Required Header stdmei.h
Description

ControlExtMemAvail gets the amount of external memory available on an XMP-Series controller. It puts the number of words (16 bit) in the location pointed to by size.

control | a handle to the Control object
*size | a pointer to the available memory words returned by the method
Return Values
MPIMessageOK if ControlExtMemAvail successfully gets and writes the available external memory words into *size
See Also | MPIControlConfig


mpiControlFlashConfigGet

Declaration
long mpiControlFlashConfigGet(MPIControl       control,
                              void             *flash,
                              MPIControlConfig *config,
                              void             *external)
Required Header stdmpi.h
Description

ControlFlashConfigGet gets the flash configuration of a Control object (control) and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Control’s flash configuration information in external is in addition to the Control’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIControlConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.

Return Values
MPIMessageOK if ControlFlashConfigGet successfully gets the Control’s flash configuration and writes it into the structure(s)
See Also | MEIFlash | mpiControlFlashConfigSet | | MEIControlConfig


mpiControlFlashConfigSet

Declaration
long mpiControlFlashConfigSet(MPIControl       control,
                              void             *flash,
                              MPIControlConfig *config,
                              void             *external)
Required Header stdmpi.h
Description

ControlFlashConfigSet sets (writes) the flash configuration of a Control object (control), using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Control’s flash configuration information in external is in addition to the Control’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEIControlConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
Return Values
MPIMessageOK if ControlFlashConfigSet successfully sets (writes) the Control’s flash configuration using data from the structure(s)
See Also | MEIFlash | mpiControlFlashConfigGet | | MEIControlConfig


meiControlGateGet

Declaration
long meiControlGateGet(MPIControl control,
                       long       gate,
                       long       *closed)
Required Header stdmei.h
Description

ControlGateGet gets the closed state (TRUE or FALSE) from the specified control gate (0 to 31).
Return Values
MPIMessageOK if ControlGateGet successfully gets (reads) the state from the control gate and puts it into closed.
See Also | meiControlGateSet


meiControlGateSet

Declaration
long meiControlGateSet(MPIControl control,
                       long       gate,
                       long       closed)
Required Header stdmei.h
Description

ControlGateSet sets the closed state (TRUE or FALSE) for the specified control gate (0 to 31).
Return Values
MPIMessageOK if ControlGateSet successfully sets (writes) the closed state into the control gate.
See Also | meiControlGateGet


mpiControlInit / meiControlInit

mpiControlInit
Declaration
long mpiControlInit(MPIControl   control)
Required Header stdmpi.h
Description

ControlInit initializes the motion control device control. ControlInit must be called at least once after a control object has been created and before any other mpiControl methods are called [with the exception of mpiControlDelete(...)].

Return Values
MPIMessageOK if ControlInit successfully initializes the motion control device control
See Also | mpiControlDelete

meiControlInit
Declaration
long meiControlInit(MPIControl   control,
                    char         *mpiVersion)
Required Header stdmei.h
Description

ControlInit

control | a handle to the Control object
*mpiVersion |
Return Values
MPIMessageOK if ControlInit successfully initializes the motion control device control
See Also


mpiControlInterruptEnable

Declaration
long mpiControlInterruptEnable(MPIControl control,
                               long       enable)
Required Header stdmpi.h
Description

If “enable” is TRUE, then ControlInterruptEnable enables interrupts from the motion controller.

If "enable" is FALSE, then ControlInterruptEnable disables interrupts from the motion controller.

Return Values
MPIMessageOK if ControlInterruptEnable successfully enables (or disables) interrupts from the motion controller
See Also | mpiControlInteruptWait | mpiControlInteruptWake


mpiControlInterruptWake

Declaration
long mpiControlInterruptWake(MPIControl control)
Required Header stdmpi.h
Description

ControlInterruptWake wakes all threads waiting for an interrupt from the motion controller control [as a result of a call to mpiControlInterruptWait(...)]. The waking thread(s) will return from the call with no interrupt indicated.
Return Values
MPIMessageOK if ControlInterruptWake successfully wakes all threads waiting for an interrupt from the motion controller
See Also | mpiControlInterruptWait | mpiControlInteruptEnable


mpiControlInterruptWait

Declaration
long mpiControlInterruptWait(MPIControl  control,
                             long        *interrupted,
                             MPIWait     timeout)
Required Header stdmpi.h
Description

ControlInterruptWait waits for an interrupt from the motion controller if interrupts are enabled.

After the ControlInterruptWait method returns, if the location pointed to by interrupted contains TRUE, then an interrupt has occurred.

After the ControlInterruptWait method returns, if the location pointed to by interrupted contains FALSE, then no interrupt has occurred, and the return of ControlInterruptWait was caused either by a call to mpiControlInterruptWake(...).

If timeout is MPIWaitPOLL (0), then ControlInterruptWait will return immediately.

If timeout is MPIWaitFOREVER (-1), then ControlInterruptWait will wait forever for an interrupt.

Otherwise, ControlInterruptWait will wait timeout milliseconds for an interrupt.

NOTE: For Windows operating systems, only MPIWaitPOLL and MPIWaitFOREVER are valid timeout values.

Return Values
MPIMessageOK | if ControlInterruptWait waits for an interrupt from the motion controller
MPIMessageTIMEOUT | if ControlInterruptWait did not receive an interrupt within timeout ms.

See Also | mpiControlInterruptWake | mpiControlInteruptEnable


meiControlIoBitGet

Declaration
meiControlIoBitGet(MPIControl          control,
                   MEIControlIoBit     bit,
                   long                *value);
Required Header stdmpi.h
Description

ControlIoBitGet reads the state of a controller digital input bit and writes it into a long pointed to by value. Some controller models have local digital I/O. Please see the controller hardware documentation for details

control | a handle to the Control object
bit | an enumerated bit number
*value | a pointer to a long. The value contains the state of the bit.
Return Values
MPIMessageOK if ControlIoBitGet successfully gets the Control configuration and writes it into the structure(s).
See Also | meiControlIoBitSet | MEIControlIoBit


meiControlIoBitSet

Declaration
meiControlIoBitSet(MPIControl          control,
                   MEIControlIoBit     bit,
                   long                *value);
Required Header stdmpi.h
Description

ControlIoBitSet writes the state of a controller digital output bit using data from a value pointed to by a long. Some controller models have local digital I/O. Please see the controller hardware documentation for details

control | a handle to the Control object
bit | an enumerated bit number
*value | a pointer to a long. The value contains the state of the bit.
Return Values
MPIMessageOK if ControlIoBitSet successfully sets the Control configuration and writes it into the structure(s).
See Also | meiControlIoBitGet | MEIControlIoBit


mpiControlIoGet

Declaration
long mpiControlIoGet(MPIControl       control,
                     MPIControlIo     *io);
Required Header stdmpi.h
Description

ControlIoGet reads the states of a controller's digital inputs and writes them into a structure pointed to by io. Some controller models have local digital I/O. Please see the controller hardware documentation for details.

control | a handle to a Control object
*io | a pointer to a structure containing the digital input and output values.

Return Values
MPIMessageOK | if ControlIoGet successfully gets the I/O bits from controller and puts (writes) them in the structure.
MPIMessageARG_INVALID | if the io pointer points to NULL.

See Also | mpiControlIoSet | MPIControlInput | MPIControlOutput


mpiControlIoSet

Declaration
long mpiControlIoGet(MPIControl       control,
                     MPIControlIo     *io);
Required Header stdmpi.h
Description

ControlIoSet writes the states of a controller's digital I/O using data from a structure pointed to by io. Some controller models have local digital I/O. Please see the controller hardware documentation for details.

control | a handle to a Control object
*io | a pointer to a structure containing the digital input and output values.
Return Values
MPIMessageOK if ControlIoSet successfully gets the I/O bits from controller and puts (writes) them in the structure
See Also | mpiControlIoGet | MPIControlInput | MPIControlOutput


mpiControlMemory

Declaration
long mpiControlMemory(MPIControl control,
                      void       **memory,
                      void       **external)
Required Header stdmpi.h
Description

ControlMemory sets (writes) an address (used to access a Control object’s memory) to the contents of memory.

If external is not NULL, the contents of external are set to an implementation-specific address that typically points to a different section or type of Control memory other than memory (e.g., to external or off-chip memory). These addresses (or addresses calculated from them) are passed as the src argument to mpiControlMemoryGet(...) and the dst argument to mpiControlMemorySet(...).
Return Values
MPIMessageOK if ControlMemory successfully writes the address(es) (used to access Control memory, and optionally to access another section of Control memory) to the contents of memory (and to external, if external is not Null)
See Also | mpiControlMemoryGet | mpiControlMemorySet | mpiControlMemoryAlloc | mpiControlMemoryCount | mpiControlMemoryFree


mpiControlMemoryAlloc

Declaration
long mpiControlMemoryAlloc(MPIControl           control,
                           MPIControlMemoryType type,
                           long                 count,
                           void                 **memory)
Required Header stdmpi.h
Description

ControlMemoryAlloc allocates count bytes of firmware memory [of type type on a Control object (control)] and writes the host address (of the allocated firmware memory) to the location pointed to by memory.

Return Values
MPIMessageOK if ControlMemoryAlloc successfully allocates firmware memory and writes the host address of that firmware memory to memory
See Also | mpiControlMemoryGet | mpiControlMemorySet | mpiControlMemory | mpiControlMemoryCount | mpiControlMemoryFree


mpiControlMemoryCount

Declaration
long mpiControlMemoryCount(MPIControl            control,
                           MPIControlMemoryType  type,
                           long                  *count)
Required Header control.h
Description

ControlMemoryCount writes the number of bytes of firmware memory [on a Control object (control, of type type) that are available to be allocated] to the location pointed to by count.
Return Values
MPIMessageOK if ControlMemoryCount successfully writes the number of bytes of firmware memory (that are available to be allocated) to count.
See Also


mpiControlMemoryFree

Declaration
long mpiControlMemoryFree(MPIControl           control,
                          MPIControlMemoryType type,
                          long                 count,
                          void                 *memory)
Required Header stdmpi.h
Description

ControlMemoryFree frees count bytes of firmware memory on a Control object (control, of type type) starting at host address memory.
Return Values
MPIMessageOK if ControlMemoryAlloc successfully frees count bytes of firmware memory on a Control object
See Also | mpiControlMemoryGet | mpiControlMemorySet | mpiControlMemoryAlloc | mpiControlMemoryCount | mpiControlMemory


mpiControlMemoryGet

Declaration
long mpiControlMemoryGet(MPIControl control,
                         void       *dst,
                         void       *src,
                         long       count)
Required Header stdmpi.h
Description

ControlMemoryGet gets count bytes of control memory (starting at address src) and puts (writes) them in application memory (starting at address dst).

Return Values
MPIMessageOK if ControlMemoryGet successfully gets count bytes of control memory and puts (writes) them in application memory
See Also | mpiControlMemorySet | mpiControlMemory | mpiControlMemoryAlloc | mpiControlMemoryCount | mpiControlMemoryFree


mpiControlMemorySet

Declaration
long mpiControlMemorySet(MPIControl control,
                         void       *dst,
                         void       *src,
                         long       count)
Required Header stdmpi.h
Description

ControlMemorySet sets (writes) count bytes of application memory (starting at address src) to control memory (starting at address dst).

Return Values
MPIMessageOK if ControlMemorySet successfully sets (writes) count bytes of application memory to control memory
See Also | mpiControlMemoryGet | mpiControlMemory | mpiControlMemoryAlloc | mpiControlMemoryCount | mpiControlMemoryFree


meiControlPlatform

Declaration
MEIPlatform  meiControlPlatform(MPIControl    control)
Required Header stdmei.h
Description

ControlPlatform returns a handle to the Platform object with which the control is associated.

control | a handle to the Control object

Return Values
MPIPlatform | handle to a Platform object
MPIHandleVOID | if control is invalid

See Also | mpiControlCreate


mpiControlReset

Declaration

long mpiControlReset(MPIControl control)
Required Header stdmpi.h
Description

ControlReset resets the motion controller (control) board.

Return Values
MPIMessageOK if ControlReset successfully resets the motion controller board
See Also


meiControlSampleCounter

Declaration
long meiControlSampleCounter(MPIControl   control,
                             long         *sampleCounter)
Required Header stdmei.h
Description

ControlSampleCounter writes the number of servo cycles (samples) that have occured since the last sample counter reset/rollover, to the sampleCounter . When the user resets the controller, the sample counter will also be reset. Since the sample counter is a long, if the sample counter is 2147483647 it will roll over on the next servo cycle to -2147483648.

Return Values
MPIMessageOK if the sample counter could be read
See Also | meiControlSecondstoSamples | meiControlSamplestoSeconds | meiControlSampleWait


meiControlSamplesToSeconds

Declaration
long meiControlSamplesToSeconds(MPIControl control,
                                long       samples,
                                float      *seconds)
Required Header stdmei.h
Description

ControlSamplesToSeconds writes to seconds the number of seconds it takes to process samples number of samples (at the current sample rate). Use this function to convert samples to seconds.
Return Values
MPIMessageOK if ControlSampleToSeconds successfully converts the samples to seconds.
See Also | meiControlSecondstoSamples | meiControlSampleCounter


meiControlSampleWait

Declaration
long meiControlSampleWait(MPIControl control,
                          long       count)
Required Header stdmpi.h
Description

ControlSampleWait waits for count samples while the XMP motion controller (associated with control) executes. While the host waits, the host gives up its time slice and continuously verifies that the XMP firmware is operational.

Return Values
MPIMessageOK if ControlSampleWait successfully waits for count samples while the XMP motion controller executes
See Also | meiControlSamplestoSeconds | meiControlSecondstoSamples | meiControlSampleCounter |


meiControlSecondstoSamples

Declaration
long meiControlSecondsToSamples(MPIControl control,
                                float      seconds,
                                long       *samples)
Required Header stdmei.h
Description

ControlSecondsToSamples writes to samples the number of servo cycles that will take place in seconds number of seconds (at the current sample rate). Use this function to convert seconds to samples.

Return Values
MPIMessageOK if ControlSecondsToSamples successfully converts the seconds to samples.
See Also | meiControlSamplestoSeconds | meiControlSampleCounter | meiControlSampleWait


mpiControlType

Declaration
long mpiControlType(MPIControl     control,
                    MPIControlType *type)
Required Header stdmpi.h
Description

When a Control object (control) is created, a type is used. ControlType writes this type to the contents of type.
Return Values
MPIMessageOK if ControlType successfully gets the type (used when control was created) to the contents of type
See Also


mpiControlValidate

Declaration
long mpiControlValidate(MPIControl control);
Required Header stdmpi.h
Description

ControlValidate validates the control object and its handle.
Return Values
MPIMessageOK if Control is a handle to a valid object.
See Also | mpiControlCreate | mpiControlDelete


meiControlVersionGet

Declaration
long meiControlVersionGet(MPIControl        control,
                          MEIControlVersion *version)
Required Header stdmei.h
Description

ControlVersionGet writes the the version numbers of the XMP firmware, hardware, and the MPI library to the structure pointed to by version.

Return Values
MPIMessageOK if ControlVersionGet successfully writes the the version numbers of the XMP firmware, hardware, and the MPI library to the location
See Also | meiControlVersionSet


meiControlVersionSet

Declaration
long meiControlVersionSet(MPIControl        control,
                          MPIControlVersion *version)
Required Header stdmei.h
Description

ControlVersionSet sets the version numbers of the XMP firmware, hardware, and the MPI library using data from the structure pointed to by version.

Normally, the MPI library is compatible only with the XMP firmware for which the library is specifically built; i.e., only when

version -> mpi.firmware.version == version -> xmp.firmware.version

However, there are times when it is desirable to have the MPI library ignore incompatible firmware and continue to operate. As an example, the flash utility instructs the MPI library to ignore firmware incompatibility when new firmware is being loaded. Of course, this new firmware should also be compatible with the MPI library. In such cases, the version -> xmp.firmware structure will be copied into control.
Return Values
MPIMessageOK if ControlVersionSet successfully sets the version numbers of the XMP firmware, hardware, and the MPI library using data from the structure
See Also | meiControlVersionGet


Dynamic Allocation of External Memory Buffers

.

Dynamic Allocation of External Memory Buffers

In previous versions, the XMP external memory was statically allocated at firmware compile time.

In version 20010119 and later, specific buffers of the XMP external memory are dynamically allocated. The dynamic allocation feature allows an application to efficiently use the XMP controller's on-board memory and allows for future expansion. The dynamically allocated buffers currently include the Frame Buffer and Record Buffer. Each of these buffers sizes are recalculated during a call to mpiControlConfigSet(...) if there is a change in any of the associated ControlConfig values.

The Frame Buffer is used for motion on each axis. The Frame Buffer is directly associated with the number of EnabledAxes in the MPIControlConfig structure. The Frame Buffer will be allocated to the minimum size required to support the number of enabled axes. The default number of EnabledAxes is eight (8).

The Record Buffer is used for the on-board data recorder. The Record Buffer is directly associated with the number of EnabledRecord in the MPIControlConfig structure. The Record Buffer will be allocated to the minimum size required to support the number of enabled records. The default number of EnabledRecords is 3064. Each record is the size of one memory word.

The meiControlExtMemAvail(...) method has been added to discover how much memory is available on your controller.

MPI_DEF1 long MPI_DEF2
     meiControlExtMemAvail(MPIControl  control,
                           long        *size)

The meiControlExtMemAvail(...) method will return the number of memory words available. Since each record size is one memory word, the size returned from the above function can be used to increase the Record Buffer to maximum size possible. This greatly improves client/server operation of Motion Scope and any application used for data collection.

WARNING! Due to the nature of dynamic allocation and the clearing of external memory buffers mpiControlConfigSet(...) should ONLY be called at motion application initialization time and NOT during motion.

Return to Control Objects page


TCP/IP and Sockets for Control Objects

.

TCP/IP and Sockets for Control Objects

The MPI implements network functionality as client/server. The xmp\util\server.c program implements a basic server. You just create a Control object of type MPIControlTypeCLIENT and specify the server's host in the MPIControlAddress{}.client{} structure.

You can try “MPI networking” on a single machine by starting up the server program in a DOS window, and then running a sample application in another DOS window. Note that you can specify the host name and port of the server as command line arguments to all sample applications and utilities.

The way the MPI client/server works internally is that low-level mpiControlMemory and mpiControlInterrupt methods are intercepted just before they read/write XMP memory. The methods are packaged up as remote procedure calls and sent to the server for execution. The server sends the results back to the client.

There are 2 channels of communication - one channel to wait for interrupts, and another channel to do everything else. All MPI methods that communicate with the XMP do so by calling (eventually) the low level mpiControlMemory methods, so no application code needs to be changed other than the initial call to mpiControlCreate(...). This is all implemented on WinNT using WinSock.

Note that it would be possible to implement the client/server scenario above using an RS-232 line rather than TCP/IP WinSock. The MPI’s client/server protocol only requires a reliable transport mechanism (WinSock, RS-232) between a client and server.

Return to Control Objects page


DriveMap Objects

.

DriveMap Objects

Introduction

A DriveMap object is used to access information in a drive map file.

Methods

Create, Delete, Validate Methods
 | meiDriveMapCreate
 | meiDriveMapDelete
 | meiDriveMapValidate

Configuration and Information Methods
 | meiDriveMapParamCount
 | meiDriveMapParamList
 | meiDriveMapConfigCount
 | meiDriveMapConfigList

Data Types

MEIDriveMapMessage
MEIDriveMapParamAccess
MEIDriveMapParamInfo
MEIDriveMapParamType
MEIDriveMapParamValue

Constants

MEIDriveMapParamMAX_STRING_LENGTH


MEIDriveMapMessage

MEIDriveMapMessage

typedef enum {
   MEIDriveMapMessageMAP_FILE_OPEN_ERROR,
   MEIDriveMapMessageMAP_FILE_FORMAT_INVALID,
   MEIDriveMapMessageNODE_NOT_FOUND_IN_MAP,
   MEIDriveMapMessageVERSION_NOT_FOUND_IN_MAP,
   MEIDriveMapMessageDRIVE_PARAM_READ_ONLY,
} MEIDriveMapMessage;

Description
MEIDriveMapMessageMAP_FILE_OPEN_ERROR
 | There was an error when opening the drive map file. The file may not exist, or access to the directory may not be allowed.
MEIDriveMapMessageMAP_FILE_FORMAT_INVALID
 | The format of the drive map file is invalid.
MEIDriveMapMessageNODE_NOT_FOUND_IN_MAP
 | The node type specified by the nodeName parameter was not found in the driveMap file.
MEIDriveMapMessageVERSION_NOT_FOUND_IN_MAP
 | The drive firmware version specified by the firmwareVersion parameter was not found in the driveMap file.
MEIDriveMapMessageDRIVE_PARAM_READ_ONLY
 | A read-only parameter is included in the configuration list for the specified drive in the driveMap file.
See Also


MEIDriveMapParamAccess

MEIDriveMapParamAccess

typedef enum MEISqNodeDriveParamAccess {
    MEIDriveMapParamAccessREAD_WRITE,
    MEIDriveMapParamAccessREAD_ONLY,
} MEIDriveMapParamAccess;
Description

The DriveMapParamAccess structure indicates what type of access is possible with the drive parameter.

This field of the MEIDriveMapParamInfo structure indicates what type of access is possible with this drive parameter.

See Also | MEIDriveMapParamInfo


MEIDriveMapParamInfo

MEIDriveMapParamInfo

typedef struct MEISqNodeDriveParamInfo {
    unsigned long             parameter;
    char                      name[MEISqNodeDriveParamMAX_STRING_LENGTH];
    MEIDriveMapParamAccess    access;  /* 0=>rw, 1=>ro */
    MEIDriveMapParamType      type;
    char                      validValues[MEISqNodeDriveParamMAX_STRING_LENGTH];
    long                      defaultValue;
    char                      help[MEISqNodeDriveParamMAX_STRING_LENGTH];
} MEIDriveMapParamInfo;
Description

The DriveMapParamInfo structure holds a set of information describing a drive parameter. This structure is read from the drives map file "drives.dm."

parameter | the number used to address this drive parameter.
name | a null terminated string giving a name for this drive parameter.
access | defines if this drive parameter is read-only or read-write.
type | the data type for this drive parameter. (ex: signed32, unsigned32, float, etc.)
validValues | a string describing the possible valid values for this drive parameter.
defaultValue | The factory default value this drive parameter.
help | A string describing this drive parameter.

See Also | MEIDriveMapParamType


MEIDriveMapParamMAX_STRING_LENGTH

MEIDriveMapParamMAX_STRING_LENGTH

#define  MEIDriveMapParamMAX_STRING_LENGTH  (256)

Description
 | The DriveMapParamMAX_STRING_LENGTH macro defines the maximum length of a string that can be read from or written to a drive parameter.
See Also


MEIDriveMapParamType

MEIDriveMapParamType

typedef enum MEIDriveParamType {
    MEISqNodeDriveParamTypeSIGNED32,
    MEISqNodeDriveParamTypeSIGNED16,
    MEISqNodeDriveParamTypeSIGNED8,
    MEISqNodeDriveParamTypeUNSIGNED32,
    MEISqNodeDriveParamTypeUNSIGNED16,
    MEISqNodeDriveParamTypeUNSIGNED8,
    MEISqNodeDriveParamTypeHEX,
    MEISqNodeDriveParamTypeENUMERATED,
    MEISqNodeDriveParamTypeMASK,
    MEISqNodeDriveParamTypeCHARACTER,
    MEISqNodeDriveParamTypeSTRING,
    MEISqNodeDriveParamTypeSINGLE,
    MEISqNodeDriveParamTypeACTION,
} MEIDriveMapParamType;
Description

DriveMapParamType is an enumeration that indicates which data format should be used with the drive parameter.

MEISqNodeDriveParamTypeSIGNED32 | A signed 32bit integer.
MEISqNodeDriveParamTypeSIGNED16 | A signed 16bit integer.
MEISqNodeDriveParamTypeSIGNED8 | A signed 8bit integer.
MEISqNodeDriveParamTypeUNSIGNED32 | An unsigned 32bit integer.
MEISqNodeDriveParamTypeUNSIGNED16 | An unsigned 16bit integer.
MEISqNodeDriveParamTypeUNSIGNED8 | An unsigned 8bit integer.
MEISqNodeDriveParamTypeHEX | An integer representred in hexadecimal notation.
MEISqNodeDriveParamTypeENUMERATED | An integer where each value can be represented by a different name.
MEISqNodeDriveParamTypeMASK | An integer where each bit has a unique name.
MEISqNodeDriveParamTypeCHARACTER | An single ASCII character.
MEISqNodeDriveParamTypeSTRING | A null terminated string of characters.
MEISqNodeDriveParamTypeSINGLE | A single precision floating point number.
MEISqNodeDriveParamTypeACTION | Writing to this parameter will perform an action on the drive. No data is assiated with this type.
See Also


MEIDriveMapParamValue

MEIDriveMapParamValue

typedef union {
    long           signed32;
    short          signed16;
    char           signed8;
    unsigned long  unsigned32;
    unsigned short unsigned16;
    unsigned char  unsigned8;
    unsigned long  enumerated;
    unsigned long  hex;
    unsigned long  mask;
    char           character;
    char           * string;
    float          single;
} MEIDriveMapParamValue;
Description

The MEIDriveMapParamValue union holds the value of a drive parameter. The different fields allow this data type to hold all the different types of drive parameters. The MEISqNodeDriveParamType enumeration is used to identify which of the fields within the MEISqNodeDriveParamValue union to use.

See Also | MEIDriveMapParamType


meiDriveMapConfigCount

Declaration
long meiDriveMapConfigCount (MEIDriveMap  driveMap,
                             char         *nodeName,
                             char         *firmwareVersion,
                             long         *configCount);
Required Header stdmei.h
Description

DriveMapConfigCount scans the drive map file for a drive entry that matches a particular drive. If an entry is found, this function returns the number of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiDriveMapConfigList function. This function is called first in order to get the size of the drive configuration list. Then the user can use this size to allocate enough memory to hold the complete configuration list before calling meiDriveMapConfigList to fill in the list.

driveMap | a handle to a DriveMap object.
nodeName | the product/manufacturing text string of the node to search for. The nodeName of an SqNode object can be retreived by calling meiSqNodeInfo. See MEISqNodeInfo.
firmwareVersion | The firmware version of the drive to search for. This information can be retrieved from an SqNode object by calling meiSqNodeDriveInfo. See MEISqNodeDriveInfo.
*configCount | pointer to the variable that will be set by this function.
Return Values
MPIMessageOK if meiDriveMapConfigCount successfully scans the drive map file for a drive entry that matches this node on the network and returns the number of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiDriveMapConfigList


meiDriveMapConfigList

Declaration
long meiDriveMapConfigList (MEIDriveMap   driveMap,
                            char          *nodeName,
                            char          *firmwareVersion,
                            long          configCount,
                            long          *configList);
Required Header stdmei.h
Description

DriveMapConfigList scans the drive map file for a drive entry that matches a particular drive. If an entry is found, this function returns the list of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiDriveMapConfigCount function. The meiDriveMapConfigCount function is called first in order to get the size of the drive configuration list. Then the user can use this size as a guide to allocate enough memory to hold the complete configuration list before calling this function to fill in the list.

driveMap | a handle to a DriveMap object.
*nodeName | the product/manufacturing text string of the node to search for. The nodeName of an SqNode object can be retreived by calling meiSqNodeInfo. See MEISqNodeInfo.
*firmwareVersion | The firmware version of the drive to search for. This information can be retrieved from an SqNode object by calling meiSqNodeDriveInfo. See MEISqNodeDriveInfo.
configCount | the number of drive parameter information records that can be written to the configList list.
*configList | pointer to the list of drive parameters that make up the drive configuration that will be filled in by this function.
Return Values
MPIMessageOK if meiDriveMapConfigList successfully scans the drive map file for a drive entry that matches this node on the network and returns the list of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiDriveMapConfigCount


meiDriveMapCreate

Declaration
meiDriveMapCreate(char  *fileName)
Required Header stdmei.h
Description

DriveMapCreate creates a DriveMap object associated with the file specified by fileName.

DriveMapCreate is the equivalent of a C++ constructor.

*filename | the drive map file.

Return Values
handle | to a DriveMap object. After creating a DriveMap object, it must be validated using meiDriveMapValidate().
MPIHandleVOID | if the object could not be created.

See Also | meiDriveMapDelete | meiDriveMapValidate


meiDriveMapDelete

Declaration
meiDriveMapDelete(MEIDriveMap  driveMap);
Required Header stdmei.h
Description

DriveMapDelete deletes a DriveMap object and invalidates its handle.

DriveMapDelete is the equivalent of a C++ destructor.

driveMap | a handle of the DriveMap object to delete in the reverse order to avoid memory leaks.
Return Values
MPIMessageOK if DriveMapDelete successfully deleted the object.
See Also | meiDriveMapCreate | meiDriveMapValidate


meiDriveMapParamCount

Declaration
long meiDriveMapParamCount (MEIDriveMap   driveMap,
                            char          *nodeName,
                            char          *firmwareVersion,
                            long          *paramsCount);
Required Header stdmei.h
Description

DriveMapParamCount scans the drive map file for a drive entry that matches a particular drive. If an entry is found, then this function returns the number of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiDriveMapParamList function. First, this function is called in order to get the size of the drive parameter list. Then the user can use this size to allocate enough memory to hold the complete parameter list before calling meiDriveMapParamList to fill in the list.

driveMap | a handle to a DriveMap object.
nodeName | the product/manufacturing text string of the node to search for. The nodeName of an SqNode object can be retreived by calling meiSqNodeInfo. See MEISqNodeInfo.
firmwareVersion | The firmware version of the drive to search for. This information can be retrieved from an SqNode object by calling meiSqNodeDriveInfo. See MEISqNodeDriveInfo.
*paramsCount | pointer to the variable that will be set by this function.
Return Values
MPIMessageOK if meiDriveMapParamCount successfully scans the drive map file for a drive entry that matches this node on the network and returns the number of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiDriveMapParamList


meiDriveMapParamList

Declaration

long meiDriveMapParamList (MEIDriveMap           driveMap,
                           char                  *nodeName,
                           char                  *firmwareVersion,
                           long                  paramCount,
                           MEIDriveParamInfo     *driveParamInfo);
Required Header stdmei.h
Description

SqNodeDriveMapScanParamsList scans the drive map file for an entry that matches a particular drive. If a drive entry is found, this function writes the drive parameter information about each of the drive parameters to the driveParamInfo list.

This function is normally used with the meiDriveMapParamCount function. The meiDriveMapParamCount function is called first to get the size of the parameter list, the user can then use this size to allocate enough memory to hold the complete parameter list before calling this function to fill in the parameter list.

driveMap | a handle to a DriveMap object.
*nodeName | the product/manufacturing text string of the node to search for. The nodeName of an SqNode object can be retreived by calling meiSqNodeInfo. See MEISqNodeInfo.
*firmwareVersion | The firmware version of the drive to search for. This information can be retrieved from an SqNode object by calling meiSqNodeDriveInfo. See MEISqNodeDriveInfo.
paramCount | the number of drive parameter information records that can be written to the driveParamInfo list.
*driveParamInfo | pointer to the list of drive parameter information records that will be filled in by this function.
Return Values
MPIMessageOK if meiDriveMapParamList successfully scans the drive map file for an entry that matches the node on the network and writes the information about each of the drive parameters to the driveParamInfo list.
See Also | meiDriveMapParamCount


meiDriveMapValidate

Declaration
long meiDriveMapValidate(MEIDriveMap  driveMap);
Required Header stdmei.h
Description

DriveMapValidate validates a DriveMap object and its handle.

DriveMapValidate is the equivalent of a C++ constructor.

driveMap | a handle to SqNode object.
Return Values
MPIMessageOK if driveMap is a handle to a valid object.
See Also | meiDriveMapCreate | meiDriveMapDelete


Event Objects

.

Event Objects

Introduction

An Event object contains information about an asynchronous event. Typically, events are generated by the controller, but in some special cases it is possible to generate events from the host computer.

The Event object is retrieved through the EventMgr, via the Notify object. The Event object contains data about the type of event, its source, and other information. The user Event fields can be configured to collect data at the time when the event occurs in the controller.

Methods

Configuration and Information Methods
 | mpiEventStatusGet | Get Event status
 | mpiEventStatusSet | Set Event status

Data Types

MPIEventMessage
MEIEventNotifyData
MPIEventStatus
MEIEventStatusInfo
MPIEventType / MEIEventType

Constants

MPIEventStatusINFO_COUNT_MAX defines the size of the MPIEventStatus.info[] array.


MPIEventMessage

MPIEventMessage

typedef enum {
    MPIEventMessageEVENT_INVALID,
} MPIEventMessage;
Description
MPIEventMessageEVENT_INVALID
The event type is not valid. This message code is returned by mpiEventStatusSet(…) if the event type is not a member of the MPIEventType or MEIEventType enumerations.
See Also


MEIEventNotifyData

MPIEventNotifyData

typedef struct MEIEventNotifyData {
    void	*address[MEIXmpSignalUserData];
} MEIEventNotifyData;

Description | The address of an EventNotifyData structure is passed as the third (void *external) argument to mpi'Object'EventNotify[GS]et(). The address array contains host-based XMP addresses, the contents of which are returned in MEIEventStatusInfo{}.data.

See Also | MEIEventStatusInfo


MPIEventStatus

MPIEventStatus

typedef struct MPIEventStatus {
    MPIEventType	type;
    void		*source;

    long		info[MPIEventStatusINFO_COUNT_MAX];
} MPIEventStatus;
Description

EventStatus holds information about a particular event that was generated by the XMP.

type | identifies the type of event that was generated.
*source | identifies what the source of the event was. source will either be a handle to an MPI object or a host pointer. Use mpiObjectModuleId() to identify what source points to.

See Also | mpiObjectModuleId | MPIEventType | MPIEventMgr | MPINotify | MEIEventStatusInfo | MPIEventStatusINFO_COUNT_MAX


MEIEventStatusInfo

MEIEventStatusInfo

typedef struct MEIEventStatusInfo {
    union {
        MPIHandle  handle;  /* generic */
        MPIAxis    axis;    /* MEIEventTypeAXIS_FIRST ... MEIEventTypeAXIS_LAST - 1 */
        long       node;    /* MEIEventTypeCAN_FIRST... MEIEventTypeCAN_LAST - 1  */
        long       number;  /* MPIEventTypeMOTION MPIEventTypeMOTOR_FIRST
                              ... MPIEventTypeMOTOR_LAST - 1
                                 MEIEventTypeMOTOR_FIRST ... MEIEventTypeMOTOR_LAST - 1 */
        long       value;   /* MPIEventTypeEXTERNAL */
        } type;

        MEIXmpSignalID signalID;

        /* Contents of addresses specified by MEIEventNotifyData{} */
        union {
         long sampleCounter;
         struct {
              long sampleCounter;
         } motion;
         struct {
              long sampleCounter;
              long actualPosition;
         } axis;
         struct {
            /* Data associated with the CAN event. */
            long data[4];
        } can;
         struct {
              long sampleCounter;
              long encoderPosition;
         } motor;
         long word[MEIXmpSignalUserData];
     } data;
} MEIEventStatusInfo;
Description

EventStatusInfo is an information structure that tells the XMP what the data in MPIEventStatus.info holds.

type | A union that specifies the object handle, motion number, or external ID value that generated the event
type.handle | A generic object handle. Used by MPIRecorder and MPIMotor events
type.axis | An axis object handle. Used by MPIAxis events
type.node | The CAN Node number of the MEICan object that generated the event.
type.number | The motion number of the MPIMotion object that generated the event
type.value | An ID value used to identify what external source or MPISequence event was generated
signalID | Specifies what type of object actually generated the event
data | A union that contains extra data about the event that was generated
data.sampleCounter | The value of the sampleCounter when the event was generated
data.motion | A union that contains extra data about the motion event that was generated
data.motion.sampleCounter | The value of the sampleCounter when the motion event was generated
data.axis | A union that contains extra data about the axis event that was generated
data.axis.sampleCounter | The value of the sampleCounter when the axis.event was generated
data.axis.actualPosition | The value of the axis' actual position when the event was generated
data.can.data | A union that contains extra data about the CAN event that was generated.
data.motor | A union that contains extra data about the motor event that was generated
data.motor.sampleCounter | The value of the sampleCounter when the motor event was generated
data.motor.encoderPosition | The value of the motor's ecoder position when the event was generated
data.word[] | The extra data about the event that was generated formatted as an array of long values
Sample Code

        MPINotify      notify
        MPIEventStatus eventStatus;

        . . .

        /* Wait for event */
        returnValue =
            mpiNotifyEventWait(notify,
                                         &eventStatus,
                                          MPIWaitFOREVER);
        msgCHECK(returnValue);

        if (eventStatus.type == MPIEventTypeMOTION_DONE) {
            MEIEventStatusInfo *info;

            info = (MEIEventStatusInfo *)eventStatus.info;

            . . .
        }

See Also | MPIEventStatus | MPIAxis


MPIEventStatusINFO_COUNT_MAX

MPIEventStatusINFO_COUNT_MAX

#define MPIEventStatusINFO_COUNT_MAX	(16)
Description

EventStatusINFO_COUNT_MAX defines the size of the MPIEventStatus.info[] array.

See Also | MPIEventStatus | MPIEventMgr | MPINotify


MPIEventType / MEIEventType

MPIEventType
typedef enum {
    MPIEventTypeINVALID,

    MPIEventTypeNONE,                /*  0 */

    /* Motor events */
    MPIEventTypeAMP_FAULT,           /*  1 */
    MPIEventTypeHOME,                /*  2 */
    MPIEventTypeLIMIT_ERROR,         /*  3 */
    MPIEventTypeLIMIT_HW_NEG,        /*  4 */
    MPIEventTypeLIMIT_HW_POS,        /*  5 */
    MPIEventTypeLIMIT_SW_NEG,        /*  6 */
    MPIEventTypeLIMIT_SW_POS,        /*  7 */
    MPIEventTypeENCODER_FAULT,       /*  8 */

    /* Motion events */
    MPIEventTypeMOTION_DONE,         /*  9 */
    MPIEventTypeMOTION_AT_VELOCITY,  /* 10 */

    /* Recorder events */
    MPIEventTypeRECORDER_FULL,       /* 11 */
    MPIEventTypeRECORDER_DONE,       /* 12 */

    /* External events */
    MPIEventTypeEXTERNAL,            /* 13 */
} MPIEventType;
Description

EventType is used by the MPIEventMask macros to help generate event masks.

MPIEventTypeNONE | This event type indicates no event was generated.
MPIEventTypeAMP_FAULT | This event type indicates an Amp Fault event was generated from a Motor object.
MPIEventTypeHOME | This event type indicates a Home event was generated from a Motor object.
MPIEventTypeLIMIT_ERROR | This event type indicates a position Error Limit was generated from a Motor object.
MPIEventTypeLIMIT_HW_NEG | This event type indicates a Negative Hardware Limit event was generated from a Motor object.
MPIEventTypeLIMIT_HW_POS | This event type indicates a Positive Hardware Limit event was generated from a Motor object.
MPIEventTypeLIMIT_SW_NEG | This event type indicates a Negative Software Limit event was generated from a Motor object.
MPIEventTypeLIMIT_SW_POS | This event type indicates a Positive Software Limit event was generated from a Motor object.
MPIEventTypeENCODER_FAULT | This event type indicates an Encoder Fault event was generated from a Motor object.
MPIEventTypeMOTION_DONE | This event type indicates a Motion Done event was generated from a Motion Supervisor object.
MPIEventTypeMOTION_AT_VELOCITY | This event type indicates an At Velocity event was generated from a Motion Supervisor object.
MPIEventTypeRECORDER_FULL | This event type indicates a Recorder Full event was generated from a Recorder object.
MPIEventTypeRECORDER_DONE | This event type indicates a Recorder Done event was generated from a Recorder object.
MPIEventTypeEXTERNAL | This event type indicates an External event was generated from an external source.

MEIEventType
typedef enum {
    /* Motor events */
    MEIEventTypeLIMIT_USER0,
    MEIEventTypeLIMIT_USER1,
    MEIEventTypeLIMIT_USER2,
    MEIEventTypeLIMIT_USER3,
    MEIEventTypeLIMIT_USER4,
    MEIEventTypeLIMIT_USER5,
    MEIEventTypeLIMIT_USER6,
    MEIEventTypeLIMIT_USER7,
    MEIEventTypeLIMIT_USER8,
    MEIEventTypeLIMIT_USER9,
    MEIEventTypeLIMIT_USER10,
    MEIEventTypeLIMIT_USER11,
    MEIEventTypeLIMIT_USER12,
    MEIEventTypeLIMIT_USER13,
    MEIEventTypeLIMIT_USER14,
    MEIEventTypeLIMIT_USER15,

    /* Motion events */
    MEIEventTypeMOTION_OUT_OF_FRAMES,
    MEIEventTypeMOTION_RESERVED0,

    /* Axis events */
    MEIEventTypeIN_POSITION_COARSE,
    MEIEventTypeIN_POSITION_FINE,
    MEIEventTypeSETTLED
    MEIEventTypeAT_TARGET,
    MEIEventTypeFRAME,
    MEIEventTypeAXIS_RESERVED0,
    MEIEventTypeAXIS_RESERVED1,

    /* SynqNet events */
    MEIEventTypeSYNQNET_DEAD,
    MEIEventTypeSYNQNET_RX_FAILURE,
    MEIEventTypeSYNQNET_TX_FAILURE,
    MEIEventTypeSYNQNET_NODE_FAILURE,
    MEIEventTypeSYNQNET_RECOVERY,

    /* SqNode events */
    MEIEventTypeSQNODE_IO_ABORT,
    MEIEventTypeSQNODE_NODE_DISABLE,
    MEIEventTypeSQNODE_NODE_ALARM,
    MEIEventTypeSQNODE_ANALOG_POWER_FAULT,
    MEIEventTypeSQNODE_USER_FAULT,
    MEIEventTypeSQNODE_NODE_FAILURE,

    /* CAN events */
    MEIEventTypeCAN_BUS_STATE,
    MEIEventTypeCAN_RECEIVE_OVERRUN,
    MEIEventTypeCAN_EMERGENGY,
    MEIEventTypeCAN_NODE_BOOT,
    MEIEventTypeCAN_HEALTH,
    MEIEventTypeCAN_DIGITAL_INPUT,
    MEIEventTypeCAN_ANALOG_INPUT,

} MEIEventType;
Description

EventType is used by the MPIEventMask macros to help generate event masks.

MEIEventTypeLIMIT_USER0
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 0.
MEIEventTypeLIMIT_USER1
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 1.
MEIEventTypeLIMIT_USER2
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 2.
MEIEventTypeLIMIT_USER3
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 3.
MEIEventTypeLIMIT_USER4
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 4.
MEIEventTypeLIMIT_USER5
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 5.
MEIEventTypeLIMIT_USER6
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 6.
MEIEventTypeLIMIT_USER7
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 7.
MEIEventTypeLIMIT_USER8
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 8.
MEIEventTypeLIMIT_USER9
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 9.
MEIEventTypeLIMIT_USER10
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 10.
MEIEventTypeLIMIT_USER11
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 11.
MEIEventTypeLIMIT_USER12
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 12.
MEIEventTypeLIMIT_USER13
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 13.
MEIEventTypeLIMIT_USER14
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 14.
MEIEventTypeLIMIT_USER15
 | This event type indicates a User Limit event was generated from a Motor object. User Limit number 15.
MEIEventTypeMOTION_OUT_OF_FRAMES
 | This event type indicates a Motion Done event was generated from a Motion Supervisor object.
MEIEventTypeMOTION_RESERVED0
 | This event type indicates a Reserved Motion event was generated from a Motion Supervisor object. This event type is reserved for future use or custom motion events.
MEIEventTypeIN_POSITION_COARSE
 | This event type indicates an In Coarse Position event was generated from an Axis object.
MEIEventTypeIN_POSITION_FINE
 | This event type indicates that an In Fine Position event was generated from an Axis object.
MEISynqNetMessageREADY_TIMEOUT
 | The node failed to be ready for a service command within the timeout. This message code is returned by MPI methods that fail a service command transaction because the node is not ready to accept service commands. To correct this problem, check your node hardware. There are 32 possible message codes for this error. Each message code specifies a different node, from node number 0 to 31.
MEIEventTypeSETTLED
 | Equivalent to MEIEventTypeIN_POSITION_FINE.
MEIEventTypeAT_TARGET
 | Reserved Frame Event.
MEIEventTypeFRAME
 | This event type is currently not supported and is reserved for future use.
MEIEventTypeAXIS_RESERVED0
 | This event type indicates a Reserved Axis event was generated from an Axis object. This event type is currently not supported and is reserved for future use or custom axis events.
MEIEventTypeAXIS_RESERVED1
 | This event type indicates that a Reserved Axis event was generated from an Axis object. This event type is currently not supported and is reserved for future use or custom axis events.
MEIEventTypeSYNQNET_DEAD
 | The SynqNet network was shutdown due to a communication failure. This status/event occurs when the controller fails to read/write data to the SynqNet network interface from an RX_FAILURE or a TX_FAILURE. To recover from a DEAD event, the network must be shutdown and reinitialized. SYNQNET_DEAD is latched by the controller, use meiSynqNetEventReset(…) to clear the status/event bit.
MEIEventTypeSYNQNET_RX_FAILURE
 | SynqNet network data receive failure. Generated when the controller fails to receive the packet data buffer (Rincon DMA to internal memory) in two successive controller samples. A SYNQNET_RX_FAILURE is most likely caused by an incorrect RX_COPY_TIMER value (internal) or a timing problem. To recover from an RX_FAILURE event, the network must be shutdown and reinitialized. SYNQNET_RX_FAILURE is latched by the controller, use meiSynqNetEventReset(…) to clear the status/event bit.
MEIEventTypeSYNQNET_TX_FAILURE
 | SynqNet network data transmission failure. Generated when the controller fails to transmit the packet data buffer in two successive controller samples. This occurs when the maximum foreground time exceeds the Tx time percentage of the controller's sample period. The default Tx time value is 75% of the controller's sample period. To correct Tx failures, either increase the Tx time or decrease the controller's sample rate. To recover from a TX_FAILURE event, the network must be shutdown and reinitialized. SYNQNET_TX_FAILURE is latched by the controller, use meiSynqNetEventReset(…) to clear the status/event bit.
MEIEventTypeSYNQNET_NODE_FAILURE
 | SynqNet node failure. Generated when any node's upstream or downstream packet error rate counters exceed the failure limit. The failure limits are configured with meiSqNodeConfigSet(…). Use meiSynqNetStatus(…) to read the nodeFailedMask to identify the failed nodes. Also, a SQNODE_NODE_FAILURE will be generated for each node that fails. SYNQNET_NODE_FAILURE is latched by the controller, use meiSynqNetEventReset(…) to clear the status/event bit. To recover from a node failure, the network must be shutdown and reinitialized.
MEIEventTypeSYNQNET_RECOVERY
 | SynqNet fault recovery. Generated when any node's upstream or downstream packet error rate counters exceed the fault limit and the data traffic is redirected around the fault. The fault limits are configurable via meiSqNodeConfigSet(…). SYNQNET_RECOVERY is latched by the controller. Use meiSynqNetEventReset(…) to clear the status/event bit.
MEIEventTypeSQNODE_IO_ABORT
 | SynqNet node I/O abort. Generated when the node I/O Abort is activated. When the I/O Abort is triggered, the node's outputs are disabled (set to the power-on condition). The node I/O Abort can be configured to trigger when either a Synq Lost occurs, Node Disable is active, a Power Fault occurs, or a User Fault is triggered. See MEISqNodeConfigIoAbort{…} for more details.
MEIEventTypeSQNODE_NODE_DISABLE
 | SynqNet node's Node Disable input is activated. Generated when the Node Disable input signal transitions from inactive to active. This signal is latched in hardware. Use meiSqNodeEventReset(…) to clear the status/event and the hardware latch.
MEIEventTypeSQNODE_NODE_ALARM
 | SynqNet node alarm digital output. Generated when the node alarm output signal transitions from inactive to active. This signal is not latched.
MEIEventTypeSQNODE_ANALOG_POWER_FAULT
 | SynqNet node analog power failure. Generated when the node's power failure input bit transitions from inactive to active. The power fault circuit is node specific, but is typically connected to an analog power monitor. This signal is latched in hardware. Use meiSqNodeEventReset(…) to clear the status/event and the hardware latch.
MEIEventTypeSQNODE_USER_FAULT
 | SynqNet node user fault. Generated when the node's user configurable fault is triggered. The user fault can be configured to monitor any controller memory address and compare the masked value to a specified pattern. This signal is latched by the controller, use meiSqNodeEventReset(…) to clear the status/event bit.
MEIEventTypeSQNODE_NODE_FAILURE
 | SynqNet node failure. Generated when a node's upstream or downstream packet error rate counters exceed the failure limit. The failure limits are configured with meiSqNodeConfigSet(…). SQNODE_NODE_FAILURE is latched by the controller, use meiSqNodeEventReset(…) to clear the status/event bit. To recover from a node failure, the network must be shutdown and reinitialized.
MEIEventTypeCAN_BUS_STATE
 | The BusState has changed. Data[0] contains the new bus state.
MEIEventTypeCAN_RECEIVE_OVERRUN
 | The CAN hardware detected a receive overrun.
MEIEventTypeCAN_EMERGENGY
 | An emergency message was received from a node. Data[0] contains the node number. Data[1 to 4] contains the contents of the emergency message.
MEIEventTypeCAN_NODE_BOOT
 | A node boot message was received from a node. Data[0] contains the node number.
MEIEventTypeCAN_HEALTH
 | The health of a node has changed. Data[0] contains the node number. Data[1] contains the new node health.
MEIEventTypeCAN_DIGITAL_INPUT
 | A digital input event was received from a node. Data[0] contains the node number. Data[1 to 4] contains the new input state.
MEIEventTypeCAN_ANALOG_INPUT
 | An analog input event was received from a node. Data[0] contains the node number. Data[1 to 4] contains the new input state.

See Also | MPIEventMask | MPIEventMgr | MPINotify | MPIEventStatus | meiSynqNetEventReset | Special Note on the use of MPIEventTypeENCODER_FAULT


mpiEventStatusGet

Declaration
long mpiEventStatusGet(MPIEvent       event,
                       MPIEventStatus *status)
Required Header event.h
Description

EventStatusGet gets the status of an Event object (event) and writes it into the structure pointed to by status. Event status includes the event type, type-specific codes and the event source.

Return Values
MPIMessageOK if EventStatusGet successfully gets the status of an Event object and writes it into the structure
See Also | mpiEventStatusSet | meiEventStatusInfo


mpiEventStatusSet

Declaration
long mpiEventStatusSet(MPIEvent       event,
                       MPIEventStatus *status)
Required Header event.h
Description

EventStatusSet sets (writes) the status of event using data from the structure pointed to by status. Event status includes the event type, type-specific codes and the event source.

Return Values
MPIMessageOK if EventStatusSet successfully sets (writes) the status of event using data from the structure
See Also | mpiEventStatusGet | meiEventStatusInfo


Special Note: Use of MPIEventTypeENCODER_FAULT

This event type is used to detect three types of encoder faults:

  • Broken wire errors
  • Illegal state errors
  • Absolute encoder initialization errors
    • Timeout errors
    • Protocol errors

Broken wire errors are detected for either incremental or absolute encoders whenever both differential inputs of any encoder receiver (A, B, or Index) are at the same voltage level (i. e., whenever one or both inputs is disconnected from the encoders differential transmitter). The EncoderTermination configuration of the encoder input must be TRUE for correct detection of broken wires.

Illegal state errors occur whenever transitions are seen on both A and B phases of an encoder input at the same time (e.g. noise spikes).

There are two types of absolute encoder initialization errors: Timeout errors and Protocol errors. Timeout errors occur when an absolute encoder does not transmit absolute encoder data within the timeout period starting at the transition of the interrogation line (SEN line). Protocol errors are detected when serial absolute data is sent during the timeout, but the data cannot be interpreted by the XMP. Both error types result in an ENCODER_FAULT event.

Return to MPIEventType


EventMask Objects

.

EventMask Objects

Introduction

The EventMask determines which event types will be sent from the controller to the Notify object. By setting bits in the EventMask, specific events can be sent to the Notify object when they occur or by clearing specific bits, the events can be ignored. By default, no Events will occur until the EventMask is set.

The Event, EventMgr, and Notify objects are used with the EventMask to handle controller events.

Data Types

MPIEventMask An array of unsigned longs

Macros

mpiEventMaskALL / meiEventMaskALL | Set all events within the event mask.
mpiEventMaskAND_ASSIGN | Assign dst all events masked by both src and dst.
mpiEventMaskASSIGN | Assign the value of event mask src to the event mask dst.
mpiEventMaskAXIS / meiEventMaskAXIS | Set all MPIAxis events within the event mask.
mpiEventMaskBIT | Set mask to only handle events of type type.
mpiEventMaskBitGET | Reports if a mask is set to handle events of type type.
mpiEventMaskBitSET | Sets mask to handle events of type type.
mpiEventMaskBIT_POSITION_MASK | Returns an element's bit-mask for the specified event type.
mpiEventMaskCLEAR | Set mask to handle no events.
mpiEventMaskCOMPLEMENT | Change the value of every bit within the event mask.
mpiEventMaskEXTERNAL | Set external events within the event mask.
mpiEventMaskGET | Reports if a mask is set to handle events of type type.
mpiEventMaskIS_EQUAL | Tests the equality of two event masks.
mpiEventMaskMOTION / meiEventMaskMOTION | Set all MPIMotion events within the event mask.
mpiEventMaskMOTOR / meiEventMaskMOTOR | Set all MPIMotor events within the event mask.
mpiEventMaskOR_ASSIGN | Add all events masked by src to the event mask dst.
mpiEventMaskRECORDER | Sets all MPIRecorder events within the event mask.
mpiEventMaskSET | Set mask to handle events of type type.
mpiEventMaskSET_ALL | Set mask to handle all events whose type is enumerated less than type.
meiEventMaskSYNQNET | Set all MEISynqNet events within the event mask.
meiEventMaskSQNODE | Set all MEISqNode events within the event mask.

Constants

MEIEventMaskBITS_IN_ELEMENT | Define the number of bits in each data element of MPIEventMask.
MPIEventMaskELEMENTS | Define the number of data elements in a MPIEventMask.
MPIEventMaskELEMENT_TYPE | Define what the data type MPIEventMask is comprised of.


MEIEventMaskBITS_IN_ELEMENT

MEIEventMaskBITS_IN_ELEMENT

#define MEIEventMaskBITS_IN_ELEMENT ((unsigned long)
                                     (sizeof(MPIEventMaskELEMENT_TYPE) * 8))
Description

EventMaskBITS_IN_ELEMENT defines the number of bits in each data element of MPIEventMask.

NOTE: MEIEventMaskBITS_IN_ELEMENT replaced mpiEventMaskBITS_IN_ELEMENT.

See Also | MPIEventMask | mpiEventMaskBIT | mpiEventMaskBitGET | mpiEventMaskBitSET | mpiEventMaskBIT_POSITION_MASK


MPIEventMaskELEMENTS

MPIEventMaskELEMENTS

#define MPIEventMaskELEMENTS	(2)

Description
 | EventMaskELEMENTS defines the number of data elements in a MPIEventMask.

See Also | MPIEventMask


MPIEventMaskELEMENT_TYPE

MPIEventMaskELEMENT_TYPE

typedef unsigned long MPIEventMaskELEMENT_TYPE

Description
 | EventMaskELEMENT_TYPE defines what the data type MPIEventMask is comprised of.

See Also | MPIEventMask


MPIEventMask

MPIEventMask

#define MPIEventMaskELEMENTS	(2)
typedef unsigned long MPIEventMaskELEMENT_TYPE;
typedef MPIEventMaskELEMENT_TYPE MPIEventMask[MPIEventMaskELEMENTS];

Description
 | EventMask is an array of unsigned longs, with a length defined by MPIEventMaskELEMENTS. Each bit in the array represents a mask for a particular event. Be sure to always use the mpiEventMask…(…) macros to set or clear the event masks.

See Also | MPIEventType | mpiEventMaskBIT


mpiEventMaskALL / meiEventMaskALL

mpiEventMaskALL
Declaration

#define mpiEventMaskALL(mask)
          mpiEventMaskSET_ALL((mask), MPIEventTypeLAST)
Required Header stdmpi.h
Description

EventMaskALL sets all events within the event mask.

meiEventMaskALL
Declaration

#define	meiEventMaskALL(mask)
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER0, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER1, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER2, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER3, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER4, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER5, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER6, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER7, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER8, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER9, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER10,1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER11,1),
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER12,1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER13,1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER14,1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER15,1), \\
    mpiEventMaskBitSET((mask), MEIEventTypeMOTION_OUT_OF_FRAMES, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeMOTION_RESERVED0, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeIN_POSITION_COARSE, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeIN_POSITION_FINE, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAT_TARGET, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeFRAME, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAXIS_RESERVED0, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAXIS_RESERVED1, 1), \
Required Header stdmei.h
Description

EventMaskALL sets all MEI events within the event mask.

See Also | MPIEventType


mpiEventMaskAND_ASSIGN

Declaration

#define mpiEventMaskAND_ASSIGN(dst,src)((dst)[0] = ((dst)[0] & (src)[0])), \
                                       ((dst)[1] = ((dst)[1] & (src)[1]))
Required Header stdmpi.h
Description

EventMaskOR_ASSIGN assigns dst all events masked by both src and dst.

See Also | MPIEventMask


mpiEventMaskASSIGN

Declaration
#define mpiEventMaskASSIGN(dst,src)((dst)[0] = (src)[0]), \
                                   ((dst)[1] = (src)[1])
Required Header stdmpi.h
Description

EventMaskASSIGN assigns the value of event mask src to the event mask dst.

See Also | MPIEventMask


mpiEventMaskAXIS / meiEventMaskAXIS

mpiEventMaskAXIS
Declaration
#define mpiEventMaskAXIS(mask)(mask)
Required Header stdmpi.h
Description

EventMaskAXIS sets all MPIAxis events within the event mask.

meiEventMaskAXIS
Declaration

#define	meiEventMaskAXIS(mask)
    mpiEventMaskBitSET((mask), MEIEventTypeIN_POSITION_COARSE, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeIN_POSITION_FINE, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAT_TARGET, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeFRAME, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAXIS_RESERVED0, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeAXIS_RESERVED1, 1)
Required Header stdmei.h
Description

EventMaskAXIS sets all MEIAxis events within the event mask.

See Also | MPIEventMask


mpiEventMaskBIT

Declaration

#define mpiEventMaskBIT(mask,type)
(((mask)[0] = 0);
 ((mask)[1] = 0); \
((mask)[mpiEventMaskWORD(type)]= mpiEventMaskBIT_POSITION_MASK(type)))
Required Header stdmpi.h
Description

EventMaskBIT sets mask to only handle events of type type.

See Also | MPIEventMask | mpiEventMaskBIT | mpiEventMaskBitGET | mpiEventMaskBitSET | MEIEventMaskBITS_IN_ELEMENT | mpiEventMaskBIT_POSITION_MASK


mpiEventMaskBitGET

Declaration

#define	mpiEventMaskBitGET(mask,bit)(((mask)[mpiEventMaskWORD(bit)] &
    mpiEventMaskBIT_POSITION_MASK(bit)) ? 1 : 0)
Required Header stdmpi.h
Description

EventMaskAXIS sets all MPIAxis events within the event mask.

Returns

 TRUE if mask is set to handle events of type type. Otherwise, it returns FALSE.
See Also | MPIEventMask | mpiEventMaskBIT | mpiEventMaskBitSET | mpiEventMaskBIT_POSITION_MASK | MEIEventMaskBITS_IN_ELEMENT


mpiEventMaskBIT_POSITION_MASK

Declaration
#define mpiEventMaskBIT_POSITION_MASK (type)
               ((MPIEventMaskELEMENT_TYPE)(0x1 <<
                 mpiEventMaskBIT_POSITION(type)))
Required Header stdmpi.h
Description

type | the event type (MPIEventType / MEIEventType)

Returns

 an element's bit-mask for the specified event type.
See Also | MPIEventMask | mpiEventMaskBIT | mpiEventMaskBitGET | mpiEventMaskBitSET | MEIEventMaskBITS_IN_ELEMENT


mpiEventMaskBitSET

Declaration

#define	mpiEventMaskBitSET(mask,bit,value)	(((value) == 0) ? \
    ((mask)[mpiEventMaskWORD(bit)] &= ~mpiEventMaskBIT_POSITION_MASK(bit))
              : \
    ((mask)[mpiEventMaskWORD(bit)] |= mpiEventMaskBIT_POSITION_MASK(bit)))
Required Header stdmpi.h
Description

EventMaskBitSET sets mask to handle events of type type.

See Also | MPIEventMask | mpiEventMaskBitGET | mpiEventMaskBIT | mpiEventMaskBIT_POSITION_MASK | MEIEventMaskBITS_IN_ELEMENT


mpiEventMaskCLEAR

Declaration

#define mpiEventMaskCLEAR(mask) (((mask)[0] == 0) && ((mask)[1] ==0))
Required Header stdmpi.h
Description EventMaskCLEAR sets mask to handle no events.
See Also | MPIEventMask


mpiEventMaskCOMPLEMENT

Declaration

#define mpiEventMaskCOMPLEMENT(mask)((mask)[0] = ~(mask)[0]), \
                                    ((mask)[1] = ~(mask)[1])
Required Header stdmpi.h
Description

EventMaskCOMPLEMENT() changes the value of every bit within the event mask. If the mask is origininally set to handle an event, then mask will be set to not handle the event after the call to mpiEventMaskCOMPLEMENT(). Likewise, If the mask is origininally set to not handle an event, then mask will be set to handle the event after the call to mpiEventMaskCOMPLEMENT().

See Also | MPIEventMask


mpiEventMaskEXTERNAL

Declaration
#define mpiEventMaskEXTERNAL(mask)mpiEventMaskBitSET((mask),
                             MPIEventTypeEXTERNAL, 1)
Required Header stdmpi.h
Description

EventMaskEXTERNAL sets external events within the event mask.

See Also | MPIEventMask


mpiEventMaskGET

Declaration

#define mpiEventMaskGET(mask,type) mpiEventMaskBitGET(mask,type)
Required Header stdmpi.h
Description

Returns

 TRUE if mask is set to handle events of type type. Otherwise, it returns FALSE.
See Also | MPIEventMask | mpiEventMaskSET


mpiEventMaskIS_EQUAL

Declaration
#define	mpiEventMaskIS_EQUAL(mask1,mask2)
    (((mask1)[0] == (mask2)[0]) &&
     ((mask1)[1] == (mask2)[1]))
Required Header stdmpi.h
Description

EventMaskIS_EQUAL tests the equality of two event masks.

Returns

 TRUE if mask1 is the same as mask2. Otherwise it returns FALSE.
See Also | MPIEventMask


mpiEventMaskMOTION / meiEventMaskMOTION

mpiEventMaskMOTION
Declaration

#define	mpiEventMaskMOTION(mask)
    mpiEventMaskBitSET((mask), MPIEventTypeMOTION_DONE, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeMOTION_AT_VELOCITY, 1)
Required Header stdmpi.h
Description

EventMaskMOTION sets all MPIMotion events within the event mask.

meiEventMaskMOTION
Declaration

#define	meiEventMaskMOTION(mask)
   mpiEventMaskBitSET((mask), MEIEventTypeMOTION_OUT_OF_FRAMES, 1), \
   mpiEventMaskBitSET((mask), MEIEventTypeMOTION_RESERVED0, 1)
Required Header stdmei.h
Description

EventMaskMOTION sets all MEIMotion events within the event mask.

See Also | MPIEventMask


mpiEventMaskMOTOR / meiEventMaskMOTOR

mpiEventMaskMOTOR
Declaration
#define	mpiEventMaskMOTOR(mask)
    mpiEventMaskBitSET((mask), MPIEventTypeAMP_FAULT, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeHOME, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeLIMIT_ERROR, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeLIMIT_HW_NEG, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeLIMIT_HW_POS, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeLIMIT_SW_NEG, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeLIMIT_SW_POS, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeENCODER_FAULT, 1)
Required Header stdmpi.h
Description

EventMaskMOTOR sets all MPIMotor events within the event mask.

meiEventMaskMOTOR
Declaration
#define	meiEventMaskMOTOR(mask)
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER0, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER1, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER2, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER3, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER4, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER5, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER6, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER7, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER8, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER9, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER10, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER11, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER12, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER13, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER14, 1), \
    mpiEventMaskBitSET((mask), MEIEventTypeLIMIT_USER15, 1), \
Required Header stdmei.h
Description

EventMaskMOTOR sets all MEIMotor events within the event mask.

See Also | MPIEventMask


mpiEventMaskOR_ASSIGN

Declaration

#define	mpiEventMaskOR_ASSIGN(dst,src)	((dst)[0] = ((dst)[0] | (src)[0])), \
                                        ((dst)[1] = ((dst)[1] | (src)[1]))
Required Header stdmpi.h
Description

EventMaskOR_ASSIGN adds all events masked by src to the event mask dst.

See Also | MPIEventMask


mpiEventMaskRECORDER

Declaration

#define	mpiEventMaskRECORDER(mask)	mpiEventMaskBitSET((mask),
    MPIEventTypeRECORDER_FULL, 1), \
    mpiEventMaskBitSET((mask), MPIEventTypeRECORDER_DONE, 1)
Required Header stdmpi.h
Description

EventMaskRECORDER sets all MPIRecorder events within the event mask.

See Also | MPIEventMask


mpiEventMaskSET

Declaration
#define mpiEventMaskSET(mask,type)
        mpiEventMaskBitSET(mask,type,1)
Required Header stdmpi.h
Description

mpiEventMaskSET sets mask to handle events of type type.

See Also | MPIEventMask | mpiEventMaskGET


mpiEventMaskSET_ALL

Declaration

#define	mpiEventMaskSET_ALL(mask,type)
     ((mpiEventMaskWORD(type) == 0) ? \
            ((mask)[0] |= mpiEventMaskBIT_POSITION_MASK(type) - 1) : \
            ((mask)[0] |= 0xFFFFFFFF)), \
     ((mpiEventMaskWORD(type) == 0) ? \
            ((mask)[1] |= 0x0) : \
            ((mask)[1] |= mpiEventMaskBIT_POSITION_MASK(type) - 1))
Required Header stdmpi.h
Description

EventMaskSET_ALL sets mask to handle all events whose type is enumerated less than type.

See Also | MPIEventMask


meiEventMaskSQNODE

Declaration

#define meiEventMaskSQNODE(mask)
          mpiEventMaskBitSET((mask), MEIEventTypeSQNODE_IO_ABORT, 1), \
          mpiEventMaskBitSET((mask), MEIEventTypeSQNODE_NODE_DISABLE, 1), \
          mpiEventMaskBitSET((mask), MEIEventTypeSQNODE_NODE_ALARM, 1), \
          mpiEventMaskBitSET((mask), MEIEventTypeSQNODE_ANALOG_POWER_FAULT, 1)
          mpiEventMaskBitSET((mask), MEIEventTypeSQNODE_NODE_FAILURE, 1)
Required Header stdmei.h
Description

EventMaskSQNODE is a macro that sets all MEISynqNet event bits in the event mask.
See Also


meiEventMaskSYNQNET

Declaration

#define meiEventMaskSYNQNET(mask)
             mpiEventMaskBitSET((mask), MEIEventTypeSYNQNET_DEAD, 1), \
             mpiEventMaskBitSET((mask), MEIEventTypeSYNQNET_RX_FAILURE,1), \
             mpiEventMaskBitSET((mask), MEIEventTypeSYNQNET_TX_FAILURE,1)
             mpiEventMaskBitSET((mask), MEIEventTypeSYNQNET_NODE_FAILURE,1), \
             mpiEventMaskBitSET((mask), MEIEventTypeSYNQNET_RECOVERY,1)
Required Header stdmei.h
Description

EventMaskSYNQNET is a macro that sets all MEISynqNet event bits in the event mask.
See Also


EventMgr Objects

.

EventMgr Objects

Introduction

An EventMgr

  • Obtains asynchronous events from the Control object(s) that the EventMgr is associated with.
  • Generates Event objects for enabled event sources.
  • Awakens any threads that are waiting for events.

Methods

Create, Delete, Validate Methods
 | mpiEventMgrCreate | Create EventMgr object
 | mpiEventMgrDelete | Delete EventMgr object
 | mpiEventMgrValidate | Validate EventMgr object

Configuration and Information Methods
 | mpiEventMgrConfigGet | Get EventMgr config
 | mpiEventMgrConfigSet | Set EventMgr config
 | mpiEventMgrEvent | Request event notification for all Notify objects on EventMgr’s list
 | meiEventMgrServiceConfigGet | Get processes that EventMgr will service
 | meiEventMgrServiceConfigSet | Set processes that EventMgr will service

Action Methods
 | mpiEventMgrFlush | Flush pending EventMgr events
 | mpiEventMgrService | Get list of all pending asynchronous events

Relational Methods
 | List Methods- for Control Objects
 | mpiEventMgrControl | Return handle of indexth Control object in list
 | mpiEventMgrControlAppend | Append Control’s handle to list
 | mpiEventMgrControlCount | Count the number of Control objects associated with EventMgr (in list)
 | mpiEventMgrControlFirst | Return handle to first Control object in list
 | mpiEventMgrControlIndex | Return the index of a Control object in list
 | mpiEventMgrControlInsert | Insert Control handle into list
 | mpiEventMgrControlLast | Get handle to last Control object in list
 | mpiEventMgrControlListGet | Get list of Control objects associated with EventMgr
 | mpiEventMgrControlListSet | Create a list of Control objects associated with EventMgr
 | mpiEventMgrControlNext | Get handle to next Control object in list
 | mpiEventMgrControlPrevious | Get handle to previous Control object in list
 | mpiEventMgrControlRemove | Remove a Control object’s handle from list
 | List Methods- for Notify Objects
 | mpiEventMgrNotify | Return handle to a Notify object associated with EventMgr
 | mpiEventMgrNotifyAppend | Append Notify object to list
 | mpiEventMgrNotifyCount | Return number of Notify objects in list
 | mpiEventMgrNotifyFirst | Get first Notify object in list
 | mpiEventMgrNotifyIndex | Get index value for a Notify object in list
 | mpiEventMgrNotifyInsert | Place a Notify object after another Notify object in list
 | mpiEventMgrNotifyLast | Get handle to the Notify object that is last on the list
 | mpiEventMgrNotifyListGet | Get a list of Notify objects
 | mpiEventMgrNotifyListSet | Create a list of Notify objects
 | mpiEventMgrNotifyNext | Get the Notify object just after notify in list
 | mpiEventMgrNotifyPrevious | Get the Notify object just before notify in list
 | mpiEventMgrNotifyRemove | Remove a Notify object from list

Data Types

MPIEventMgrMessage
MEIEventMgrServiceConfig


MPIEventMgrMessage

MPIEventMgrMessage

typedef enum {

    MPIEventMgrMessageEVENTMGR_INVALID,
} MPIEventMgrMessage;
Description
MPIEventMgrMessageEVENTMGR_INVALID
Not supported.
Sample Code
MPIControl        control;
MPIEventMgr     eventMgr;
long                  returnValue;
…

eventMgr =
    mpiEventMgrCreate(control);
returnValue =
    mpiEventMgrValidate(eventMgr);

See Also | MPIEventMgr | mpiEventMgrCreate | mpiEventMgrValidate


MEIEventMgrServiceConfig

MEIEventMgrServiceConfig
typedef struct MEIEventMgrServiceConfig
            { long allProcesses; /* TRUE => collect events from all processes,
            else EventMgr process only */
} MEIEventMgrServiceConfig;

Description
 | allProcesses | is a boolean value. If allProcesses=TRUE, then the event manager will handle events originating from all processes. If allProcesses=FALSE, then the event manager will only handle events originating from the same process in which the event manager was created.
See Also


mpiEventMgrConfigGet

Declaration
long mpiEventMgrConfigGet(MPIEventMgr       eventMgr,
                          MPIEventMgrConfig *config,
                          void              *external)
Required Header stdmpi.h
Description

EventMgrConfigGet gets the configuration of an EventMgr object (eventMgr) and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIEventMgrConfig{} or is NULL.

Return Values
MPIMessageOK if EventMgrConfigGet successfully gets the EventMgr’s configuration and writes it into the structure(s)
See Also | mpiEventMgrConfigSet


mpiEventMgrConfigSet

Declaration
long mpiEventMgrConfigSet(MPIEventMgr       eventMgr,
                          MPIEventMgrConfig *config,
                          void              *external)
Required Header stdmpi.h
Description

EventMgrConfigSet sets (writes) the eventMgr configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIEventMgrConfig{} or is NULL.

Return Values
MPIMessageOK if EventMgrConfigSet successfully sets (writes) the EventMgr’s configuration using data from the structure(s)
See Also | mpiEventMgrConfigGet


mpiEventMgrControl

Declaration
MPIControl mpiEventMgrControl(MPIEventMgr eventMgr,
                              long        index)
Required Header stdmpi.h
Description

Returns the element at the position on the list indicated by index.

eventMgr | a handle to the EventMgr object.
index | a position in the list.

Return Values
handle | to the indexth motion controller (Control) associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if index is less than 0 if index is greater than or equal to mpiEventMgrCount(eventMgr)
MPIMessageARG_INVALID | index is a negative number.
MEIListMessageELEMENT_NOT_FOUND | index is greater than or equal to the number of elements in the list.
MPIMessageHANDLE_INVALID | eventMgr is an invalid handle.
See Also


mpiEventMgrControlAppend

Declaration
long mpiEventMgrControlAppend(MPIEventMgr eventMgr,
                              MPIControl  control)
Required Header stdmpi.h
Description

EventMgrControlAppend appends control to the list of motion controllers associated with an EventMgr (eventMgr). Add "control" to the end of the list.

eventMgr | a handle to the EventMgr object.
control | a handle to a Control object.

Return Values
MPIMessageOK | if EventMgrControlAppend successfully appends control to the list of motion controllers associated with an EventMgr
MPIMessageHANDLE_INVALID | Either eventMgr or control is an invalid handle.
MPIMessageOBJECT_ON_LIST | control is already on the list.
MPIMessageNO_MEMORY | Not enough memory was available.
See Also


mpiEventMgrControlCount

Declaration
long mpiEventMgrControlCount(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

Returns the number of elements on the list.

eventMgr | a handle to the EventMgr object.

Return Values
number | of motion controllers associated with an EventMgr (eventMgr)
-1 | if eventMgr is an invalid handle
0 | if eventMgr has no associated motion controllers
See Also


mpiEventMgrControlFirst

Declaration
MPIControl mpiEventMgrControlFirst(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrControlFirst returns the first element in the list. This function can be used in conjuntion with mpiEventMgrControlNext() in order to iterate through the list. MPIHandleVOID is returned if the list is empty.

eventMgr | a handle to the EventMgr object.

Return Values
handle | to the first motion controller (Control) associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if eventMgr has no associated motion controllers
MPIMessageHANDLE_INVALID | if eventMgr is an invalid handle.

See Also | mpiEventMgrControlLast


mpiEventMgrControlInsert

Declaration
long mpiEventMgrControlInsert(MPIEventMgr eventMgr,
                              MPIControl  control,
                              MPIControl  insert)
Required Header stdmpi.h
Description

EventMgrControlInsert inserts a Control object (insert) after the Control object (control) in the list of motion controllers associated with eventMgr.
Return Values
MPIMessageOK if EventMgrControlInsert successfully inserts the Control object (insert) after another Control object (control) in the list of motion controllers
See Also


mpiEventMgrControlIndex

Declaration
long mpiEventMgrControlIndex(MPIEventMgr eventMgr,
                             MPIControl  control)
Required Header stdmpi.h
Description

EventMgrControlIndex returns the position of "control" on the list.

eventMgr | a handle to the EventMgr object.
control | a handle to a Control object.

Return Values
index | of control in the list of motion controllers associated with an EventMgr (eventMgr)
-1 | if eventMgr is invalid if control was not found in the list of motion controllers
See Also


mpiEventMgrControlLast

Declaration
MPIControl mpiEventMgrControlLast(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrControlLast returns the last element in the list.
This function can be used in conjuntion with mpiEventMgrControlPrevious() in order to iterate through the list backwards.

eventMgr | a handle to the EventMgr object.

Return Values
handle | to the last motion controller (Control) associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if eventMgr has no associated motion controllers
MPIMessageHANDLE_INVALID | if eventMgr is an invalid handle.

See Also | mpiEventMgrControlFirst


mpiEventMgrControlListGet

Declaration
long mpiEventMgrControlListGet(MPIEventMgr eventMgr,
                               long        *controlCount,
                               MPIControl  *controlList)
Required Header stdmpi.h
Description

EventMgrControlListGet returns the list of Control objects associated with an EventMgr object (eventMgr).

EventMgrControlListGet also writes the number of Control handles (in the list) to the location pointed to by controlCount, and writes an array (of controlCount Control handles) to the location pointed to by controlList.
Return Values
MPIMessageOK if EventMgrControlListGet successfully returns the list of Control objects associated with an EventMgr object
See Also | mpiEventMgrControlListSet


mpiEventMgrControlListSet

Declaration
long mpiEventMgrControlListSet(MPIEventMgr eventMgr,
                               long        controlCount,
                               MPIControl  *controlList)
Required Header stdmpi.h
Description

EventMgrControlListSet creates a list of controlCount Control objects using the Control handles specified by controlList. Any existing motion controller list is completely replaced.

The controlList parameter is the address of an array of controlCount Control handles, or is NULL (if controlCount is equal to zero).

A motion controller list can also be created incrementally (i.e., one Control at a time) by using the append and/or insert methods described in this section. The initial Control of a control list may be specified using the control parameter of mpiEventMgrCreate(...). The list methods in this section can be used to examine and manipulate a motion controller list regardless of how the list was created.
Return Values
MPIMessageOK if EventMgrControlListSet successfully creates a list of Control objects using the Control handles
See Also | mpiEventMgrControlListGet


mpiEventMgrControlNext

Declaration
MPIControl mpiEventMgrControlNext(MPIEventMgr  eventMgr,
                                  MPIControl   control)
Required Header stdmpi.h
Description

EventMgrControlNext returns the next element following "control" on the list. MPIHandleVOID is returned if "control" is the last element on the list, or if "control" is not in the list at all. This function can be used in conjuntion with mpiEventMgrControlFirst() in order to iterate through the list.

eventMgr | a handle to the EventMgr object.
control | a handle to a Control object.

Return Values
handle | to the motion controller following control in the list of motion controllers associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if control is the last motion controller
MPIMessageHANDLE_INVALID | Either eventMgr or control is an invalid handle.

See Also | mpiEventMgrControlPrevious


mpiEventMgrControlPrevious

Declaration
MPIControl  mpiEventMgrControlPrevious(MPIEventMgr eventMgr,
                                       MPIControl  control)
Required Header stdmpi.h
Description

EventMgrControlPrevious returns the previous element prior to "control" on the list. MPIHandleVOID is returned if "control" is the first element on the list, or if "control" is not in the list at all. This function can be used in conjuntion with mpiEventMgrControlLast() in order to iterate through the list backwards.

eventMgr | a handle to the EventMgr object.
control | a handle to a Control object.

Return Values
handle | to the motion controller preceding control in the list of motion controllers associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if control is the first motion controller
MPIMessageHANDLE_INVALID | Either eventMgr or control is an invalid handle.

See Also | mpiEventMgrControlNext


mpiEventMgrControlRemove

Declaration
long mpiEventMgrControlRemove(MPIEventMgr eventMgr,
                              MPIControl  control)
Required Header stdmpi.h
Description

EventMgrControlRemove removes a Control object (control) from the list of Control objects associated with eventMgr.
Return Values
MPIMessageOK if EventMgrControlRemove successfully removes a Control object from the list of Control objects associated with an EventMgr (eventMgr)
See Also | mpiEventMgrControl


mpiEventMgrCreate

Declaration
MPIEventMgr mpiEventMgrCreate(MPIControl control)
Required Header stdmpi.h
Description

EventMgrCreate creates an EventMgr object, with control as the initial element in the list of Control objects from which the EventMgr obtains asynchronous events (control may be MPIHandleVOID).

EventMgrCreate is the equivalent of a C++ constructor.

Return Values
handle | to an EventMgr object
MPIHandleVOID | if the object could not be created

See Also | mpiEventMgrDelete | mpiEventMgrValidate


mpiEventMgrDelete

Declaration
long mpiEventMgrDelete(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrDelete deletes an EventMgr object and invalidates its handle (eventMgr). EventMgrDelete is the equivalent of a C++ destructor.

Deleting an EventMgr object does not delete any of the Control objects that supply the EventMgr with asynchronous events. However, deleting an EventMgr object will delete any unreceived events for that EventMgr.

Return Values
MPIMessageOK if EventMgrDelete successfully deletes an EventMgr object and invalidates its handle
See Also | mpiEventMgrCreate | mpiEventMgrValidate


mpiEventMgrEvent

Declaration
long mpiEventMgrEvent(MPIEventMgr    eventMgr,
                      MPIEventStatus *status)
Required Header stdmpi.h
Description

EventMgrEvent requests that the EventMgr (eventMgr) call mpiNotifyEvent(notify, status) for all Notify objects on that Event Manager’s list. Each Notify object represents a thread that has requested event notification. The Notify object will determine whether it accepts the event notification or not.

EventMgrEvent enables your application to use the Event Manager to distribute user-created events in the same way that events generated by the motion controller are distributed.
Return Values
MPIMessageOK if EventMgrEvent successfully requests that the EventMgr call mpiNotify Event(notify, status) for all Notify objects on that Event Manager’s list
See Also


mpiEventMgrFlush

Declaration
long mpiEventMgrFlush(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrFlush flushes any pending events from an EventMgr (eventMgr).
Return Values
MPIMessageOK if EventMgrFlush successfully flushes any pending EventMgr events
See Also


mpiEventMgrNotify

Declaration
MPINotify mpiEventMgrNotify(MPIEventMgr eventMgr,
                            long        index)
Required Header stdmpi.h
Description

EventMgrNotify returns the element at the position on the list indicated by "index".

eventMgr | a handle to the EventMgr object.
index | a position in the list.

Return Values
handle | to the indexth Notify object associated with an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if index is less than 0 if index is greater than or equal to mpiEventMgrCount(eventMgr)
MPIMessageARG_INVALID | index is a negative number.
MEIListMessageELEMENT_NOT_FOUND | index is greater than or equal to the number of elements in the list.
MPIMessageHANDLE_INVALID | eventMgr is an invalid handle.
See Also


mpiEventMgrNotifyAppend

Declaration
long mpiEventMgrNotifyAppend(MPIEventMgr eventMgr,
                             MPINotify   notify)
Required Header stdmpi.h
Description

EventMgrNotifyAppend appends a Notify object (notify) to the list of Notify objects maintained by an EventMgr object (eventMgr).

eventMgr | a handle to the EventMgr object.
notify | a handle to a Notify object.

Return Values
MPIMessageOK | if EventMgrNotifyAppend successfully appends a Notify object to the list of Notify objects maintained by an EventMgr object
MPIMessageHANDLE_INVALID | Either eventMgr or notify is an invalid handle.
MPIMessageOBJECT_ON_LIST | if notify is already on the list.
MPIMessageNO_MEMORY | if not enough memory was available.
See Also


mpiEventMgrNotifyCount

Declaration
long mpiEventMgrNotifyCount(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrNotifyCount returns the number of elements on the list.

eventMgr | a handle to the EventMgr object.

Return Values
number | of Notify objects in the list (of Notify objects) maintained by an EventMgr (eventMgr)
-1 | if eventMgr is invalid
0 | if the list (of Notify objects) is empty
See Also


mpiEventMgrNotifyFirst

Declaration
MPINotify mpiEventMgrNotifyFirst(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrNotifyFirst returns the first element in the list. This function can be used in conjuntion with mpiEventMgrNotifyNext() in order to iterate through the list.

eventMgr | a handle to the EventMgr object.

Return Values
handle | to the first Notify object in the list (of Notify objects) maintained by an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if the list (of Notify objects) is empty
MPIMessageHANDLE_INVALID | if eventMgr is an invalid handle.

See Also | mpiEventMgrNotifyLast


mpiEventMgrNotifyInsert

Declaration
long mpiEventMgrNotifyInsert(MPIEventMgr eventMgr,
                             MPINotify   notify,
                             MPINotify   insert)
Required Header stdmpi.h
Description

EventMgrNotifyInsert places a Notify object (insert) after another Notify object (notify) in the list (of Notify objects) maintained by an EventMgr object (eventMgr).

Return Values
MPIMessageOK if EventMgrNotifyInsert successfully places a Notify object after another Notify object in the list of Notify objects
See Also


mpiEventMgrNotifyIndex

Declaration
long mpiEventMgrNotifyIndex(MPIEventMgr eventMgr,
                            MPINotify   notify)
Required Header stdmpi.h
Description

EventMgrNotifyIndex returns the position of "notify" on the list.

eventMgr | a handle to the EventMgr object.
notify | a handle to the EventMgr object.

Return Values
index | of notify in the list (of Notify objects) maintained by an EventMgr (eventMgr)
-1 | if eventMgr is invalid if notify was not found in the list
See Also


mpiEventMgrNotifyLast

Declaration
MPINotify mpiEventMgrNotifyLast(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description

EventMgrNotifyLast returns the last element in the list. This function can be used in conjuntion with mpiEventMgrNotifyPrevious() in order to iterate through the list backwards.

eventMgr | a handle to the EventMgr object.

Return Values
handle | to the last Notify object in the list maintained by an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if the list (of Notify objects) is empty
MPIMessageHANDLE_INVALID | if eventMgr is an invalid handle.

See Also | mpiEventMgrNotifyFirst


mpiEventMgrNotifyListGet

Declaration
long mpiEventMgrNotifyListGet(MPIEventMgr eventMgr,
                              long        *notifyCount,
                              MPINotify   *notifyList)
Required Header stdmpi.h
Description

EventMgrNotifyListGet returns the list of Notify objects for an EventMgr object (eventMgr). EventMgrNotifyListGet also sets (writes) the number (of Notify objects in the list) to the location pointed to by notifyCount, and sets (writes) an array (of notifyCount Notify handles) to the contents of the location pointed to by notifyList.
Return Values
MPIMessageOK if EventMgrNotifyListGet successfully returns the list of Notify objects for an EventMgr object
See Also | mpiEventMgrNotifyListSet


mpiEventMgrNotifyListSet

Declaration
long mpiEventMgrNotifyListSet(MPIEventMgr  eventMgr,
                              long         notifyCount,
                              MPINotify    *notifyList)
Required Header stdmpi.h
Description

EventMgrNotifyListSet creates a list of Notify objects, where the number of Notify objects is specified by notifyCount, using the Notify handles specified by notifyList. The notifyList argument is the address of an array of notifyCount Notify handles, or is NULL if notifyCount is zero. Any existing notify object list is completely replaced.

You can also create a Notify object list incrementally (i.e., one Notify object is created at a time), by using the EventMgrAppend and/or EventMgrInsert methods. After creating a list of Notify objects, use the EventMgrList methods to examine and manipulate the list, regardless of how the list was created.

Return Values
MPIMessageOK if EventMgrNotifyListSet successfully creates a list of Notify objects using the Notify handles specified by notifyList
See Also | mpiEventMgrNotifyListGet


mpiEventMgrNotifyNext

Declaration
MPINotify mpiEventMgrNotifyNext(MPIEventMgr eventMgr,
                                MPINotify   notify)
Required Header stdmpi.h
Description

EventMgrNotifyNext returns the next element following "notify" on the list. This function can be used in conjuntion with mpiEventMgrNotifyFirst() in order to iterate through the list.

eventMgr | a handle to the EventMgr object.
notify | a handle to a Notify object.

Return Values
handle | to the Notify object after another Notify object (notify) in the list (of Notify objects) maintained by an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if notify is the last notify object in the list
MPIMessageHANDLE_INVALID | Either eventMgr or notify is an invalid handle.

See Also | mpiEventMgrNotifyPrevious


mpiEventMgrNotifyPrevious

Declaration
MPINotify mpiEventMgrNotifyPrevious(MPIEventMgr eventMgr,
                                    MPINotify   notify)
Required Header stdmpi.h
Description

EventMgrNotifyPrevious returns the previous element prior to "notify" on the list. This function can be used in conjuntion with mpiEventMgrNotifyLast() in order to iterate through the list backwards.

eventMgr | a handle to the EventMgr object.
notify | a handle to a Notify object.

Return Values
handle | to the Notify object just before another Notify object (notify) in the list (of Notify objects) maintained by an EventMgr (eventMgr)
MPIHandleVOID | if eventMgr is invalid if notify is the first Notify object in the list
MPIMessageHANDLE_INVALID | either eventMgr or notify is an invalid handle

See Also | mpiEventMgrNotifyNext


mpiEventMgrNotifyRemove

Declaration
long mpiEventMgrNotifyRemove(MPIEventMgr eventMgr,
                             MPINotify   notify)
Required Header stdmpi.h
Description

EventMgrNotifyRemove removes a Notify object (notify) from the list of Notify objects maintained by an EventMgr object (eventMgr).

Return Values
MPIMessageOK if EventMgrNotifyRemove successfully removes a Notify object from the list of Notify objects maintained by an EventMgr object
See Also


mpiEventMgrService

Declaration
long mpiEventMgrService(MPIEventMgr eventMgr,
                        MPIControl  control)
Required Header stdmpi.h
Description

EventMgrService obtains all pending asynchronous events from the motion controller (control).

Events generated by sources for which no prior call to mpiEventMgrEnable(...) has been made are discarded. Events generated by enabled sources are returned in First-In/First-Out (FIFO) order each time a thread calls mpiEventMgrWait(...).

Typically, after a motion controller generates a hardware interrupt, the Interrupt Service Routine (ISR) is invoked, and the ISR in turn invokes mpiEventMgrService(...) directly or indirectly.

If "control" is | Then
MPIHandleVOID | events will be obtained from all motion controllers on the EventMgr’s (eventMgr) control list
valid | control must also be present on the EventMgr’s (eventMgr) control list
Return Values
MPIMessageOK if EventMgrService successfully obtains all pending asynchronous events from the motion controller
See Also | meiEventMgrServiceConfigGet | meiEventMgrServiceConfigSet


meiEventMgrServiceConfigGet

Declaration

           long meiEventMgrServiceConfigGet(MPIEventMgr              eventMgr,
                                            MEIEventMgrServiceConfig *config)
Required Header stdmei.h
Description

EventMgrServiceConfigGet gets the configuration of an EventMgr object (eventMgr) and writes it into the structure pointed to by config.
Return Values
MPIMessageOK if EventMgrServiceConfigGet successfully gets the EventMgr’s configuration and writes it into the structure(s).
See Also | meiEventMgrServiceConfigSet | mpiEventMgrService


meiEventMgrServiceConfigSet

Declaration

            long meiEventMgrServiceConfigSet(MPIEventMgr              eventMgr,
                                             MEIEventMgrServiceConfig *config)
Required Header stdmei.h
Description

EventMgrServiceConfigSet sets (writes) the flash configuration for an EventMgr object (eventMgr) using data from the structure pointed to by config.

Return Values
MPIMessageOK if EventMgrServiceConfigSet successfully sets (writes) the EventMgr’s flash configuration using data from the structure(s)
See Also | meiEventMgrServiceConfigGet | mpiEventMgrService


mpiEventMgrValidate

Declaration
long mpiEventMgrValidate(MPIEventMgr eventMgr)
Required Header stdmpi.h
Description EventMgrValidate validates an EventMgr object and its handle (eventMgr).
Return Values
MPIMessageOK if EventMgr is a handle to a valid object.
See Also | mpiEventMgrCreate | mpiEventMgrDelete


Filter Objects

.

Filter Objects

Introduction

A Filter object manages a single filter on a controller. It represents the control algorithm used to control a motor in a closed-loop system. The Filter contains an algorithm, a set of coefficients, inputs, and an output. Its primary responsibility is to take the difference between the command and actual positions and then calculate the output based on the control algorithm and coefficients.

For simple systems, there is a one-to-one relationship between the Axis, Filter, and Motor objects.

Methods

Create, Delete, Validate Methods
 | mpiFilterCreate | Create Filter object
 | mpiFilterDelete | Delete Filter object
 | mpiFilterValidate | Validate Filter object

Configuration and Information Methods
 | mpiFilterConfigGet | Get Filter configuration
 | mpiFilterConfigSet | Set Filter configuration
 | mpiFilterFlashConfigGet | Get flash configuration for Filter
 | mpiFilterFlashConfigSet | Set flash configuration for Filter
 | mpiFilterGainGet | Get gain coefficients
 | mpiFilterGainSet | Set current gain index
 | mpiFilterGainIndexGet | Get current gain index
 | mpiFilterGainIndexSet | Set current gain index
 | mpiFilterStatus | Get Filter’s status

Memory Methods
 | mpiFilterMemory | Get address to Filter memory
 | mpiFilterMemoryGet | Copy data from Filter memory to application memory
 | mpiFilterMemorySet | Copy data from application memory to Filter memory

Relational Methods
 | mpiFilterAxisMapGet | Get object map of axes associated with Filter
 | mpiFilterAxisMapSet | Set axes associated with Filter
 | mpiFilterControl | Return handle of Control that is assoiciated with Filter
 | mpiFilterMotorMapGet | Get object map of Motors associated with Filter
 | mpiFilterMotorMapSet | Set Motors to be associated with Filter
 | mpiFilterNumber | Get index of Filter (for Control list)

Action Methods
mpiFilterIntergratorReset Reset the integrators of filter.

Postfilter Methods
 | meiFilterPostfilterGet | Reads postfilter information.
 | meiFilterPostfilterSet | Writes postfilter information.
 | meiFilterPostfilterSectionGet | Reads postfilter section information.
 | meiFilterPostfilterSectionSet | Writes postfilter section information.

Data Types

MPIFilterCoeff
MPIFilterConfig / MEIFilterConfig
MEIFilterForm
MPIFilterGain
MEIFilterGainIndex
MEIFilterGainPID
MEIFilterGainPIDCoeff
MEIFilterGainPIV
MEIFilterGainPIVCoeff
MEIFilterGainTypePID
MEIFilterGainTypePIV
MPIFilterMessage

Constants

MPIFilterCoeffCOUNT_MAX
MPIFilterGainCOUNT_MAX
MEIMaxBiQuadSections
MEIPostfilterSection
MEIFilterType


MPIFilterConfig / MEIFilterConfig

MPIFilterConfig

typedef struct MPIFilterConfig {
    long		gainIndex;
    MPIFilterGain	gain[MPIFilterGainCOUNT_MAX];

    MPIObjectMap	axisMap;
    MPIObjectMap	motorMap;
} MPIFilterConfig;

Description
 | gainIndex | gain table index. Gain tables number 0 to MPIFilterGainCOUNT_MAX -1 (MPIFilterGainCOUNT_MAX = 4).
 | gain | see MPIFilterGain
 | axisMap | see MPIObjectMap
 | motorMap | see MPIObjectMap

MEIFilterConfig
typedef struct MEIFilterConfig {
    MEIXmpAlgorithm	Algorithm;

    MEIXmpAxisInput	Axis[MEIXmpFilterAxisInputs];

    long		*VelPositionPtr;
    long		*AuxInput[MEIXmpFilterAuxInputs];

    MEIXmpSwitchType	 GainSwitchType;
    float	   	 GainDelay;
    long		 GainWindow;
    MEIXmpSwitchType 	 PPISwitchType;
    MEIXmpPPIMode 	 PPIMode;
    float		 PPIDelay;
    long		 PPIWindow;
    MEIXmpIntResetConfig ResetIntegratorConfig;
    float		 ResetIntegratorDelay;

    MEIXmpPostFilter	 PostFilter;
} MEIFilterConfig;
Description

MEIFilterConfig contains configuration information specific to a controller. With the exception of the Algorithm element, MEIFilterConfig contains configuration information that are more intuitively accessed by other means (Postfilter parameter) or information for advanced setups and custom controller firmware.
Algorithm

This value defines the algorithm that the filter is executing every servo cycle. The most common values are:

MEIXmpAlgorithmPID PID algorithm
MEIXmpAlgorithmPIV PIV algorithm
MEIXmpAlgorithmNONE No control algorithm
Axis[MEIXmpFilterAxisInputs] | This array defines the axis (pointer to the axis) and coefficient for the position input into the filter. The input to the filter is the position error of the axis, which is multiplied by the coefficient defined by the Axis array.
VelPositionPtr | Velocity position pointer to an encoder input for algorithms that require a velocity encoder position input (such as the PIV algorithm).
AuxInput[MEIXmpFilterAuxInputs] | This array is a place holder for additional filter inputs from analog sources. This is currently not supported and is reserved for future use.
GainSwitchType | Value to define the gain table switch type. Not implemented in standard firmware.
GainDelay | Custom Delay not implemented in standard firmware.
GainWindow | Custom Delay not implemented in standard firmware.
PPISwitchType | Value to define the gain switch type for PPI mode. Not implemented in standard firmware.
PPIMode | Value to define the PPI switch mode. Not implemented in standard firmware.
PPIDelay | Custom Delay not implemented in standard firmware.
PPIWindow | Custom Window not implemented in standard firmware.
ResetIntegratorConfig | Value to define the integrator's reset configuration. Not supported in standard firmware.
ResetIntegratorDelay | Value to define the integrator's reset delay. Not supported in standard firmware.
PostFilter

This array defines the configuration for the filter's postfilter (the type, the length and values for the post filter coefficients). Though the postfilter may be configured though this parameter, it is strongly recommended that users use the meiFilterPostfilter…() methods instead for a more intuitive interface.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.
Sample Code

/*   Test whether an MPIFilter object's control loop algorithm is PID.
     Sample usage:

     returnValue =
         isAlgorithmPid(filter, &isPid);
*/

long isAlgorithmPid(MPIFilter filter, long* isPid)
{
     MEIFilterConfig xmpConfig;
     long returnValue = (count==isPid) ? MPIMessageARG_INVALID : MPIMessageOK;

     if (returnValue == MPIMessageOK)
     {
         returnValue =
             mpiFilterConfigGet(filter, NULL, &xmpConfig);
         if (returnValue == MPIMessageOK)
         {
             *isPid = (xmpConfig.Algorithm == MEIXmpAlgorithmPID) ? TRUE : FALSE;
         }
      }

      return returnValue;
}

See Also | mpiFilterConfigGet | mpiFilterConfigSet | meiFilterPostfilterGet | meiFilterPostfilterSet | meiFilterPostfilterSectionGet | meiFilterPostfilterSectionSet |


MPIFilterCoeff

MPIFilterCoeff

typedef union {
    float	f;
    long	l;
} MPIFilterCoeff;

Description
 | f | float coefficient
 | l | long coefficient

See Also | MPIFilterCoeffCOUNT_MAX | MEIFilterGainPIDCoeff | MEIFilterGainPIVCoeff


MPIFilterCoeffCOUNT_MAX

MPIFilterCoeffCOUNT_MAX

#define MPIFilterCoeffCOUNT_MAX (20)

Description
 | FilterCoeffCOUNT_MAX is a constant that defines the maximum number of filter coefficients contained in a gain table.

See Also | MPIFilterCoeff


MEIFilterForm

MEIFilterForm

typedef enum{
    MEIFilterFormIIR,
    MEIFilterFormBIQUAD,
    MEIFilterFormSS_BIQUAD,
    MEIFilterFormINT_BIQUAD,
    MEIFilterFormINT_SS_BIQUAD,
} MEIfilterForm;
Description

FilterForm describes the form that a digital filter takes on the controller. Please note that the equations listed below use the coefficients loaded onto the controller, not necessarily the coefficients used by the MPI. A user may specify a low pass filter with only a single parameter (the breakpoint) and request that the form of the filter be a space-state biquad form on the controller.

Digital filtering on the XMP is accomplished through 32-bit words. This equates to the use of single precision floating point numbers - a 24-bit mantissa or about 7 decimal places of accuracy. This lack of precision can cause errors in the filtering process normally appearing as DC gain shifts or limit cycling, this especially true when the filter requires more than one section, a 6th order low pass filter would be one example. Filter forms using integer math can provide more internal precision for coefficients and internal registers but at the cost of less dynamic range. Filter forms using integer math take more processing time for the controller and can potentially limit the maximum sample rate of the controller.

The state-space (SS) filter forms allow the scaling of the input and the output, whereas the non-state-space forms only allow output scaling. This helps to prevent the loss of precision of the internal registers while still maintaining a very large dynamic range. Filter forms using state-space forms take more processing time for the controller and can potentially limit the maximum sample rate of the controller. However, a non-integer state-space filter form takes less processing power than an integer non-state-space filter form.
MEIFilterFormIIR

Deprecated. Cascaded biquad sections offer better precision and better calculation performance.
MEIFilterFormBIQUAD

Second Order digital filter form, for implementing low/high pass, notch, lead/lag and custom filters. The filter is a single precision floating point canonical form. The biquad filter is defined by the following discrete transfer function:

The XMP's representation of this filter is:

w0: Intermediate result
u(k): filter input
a1, a2, b0, b1, and b2: discrete biquad coefficients
y(k):filter output
x1k and x2k: filter states
MEIFilterFormSS_BIQUAD

Second order digital filter form, for implementing low/high pass, notch, lead/lag and custom filters. The filter is a single precision, floating point state space implementation. This filter applies input and output scaling to the canonical form. The XMP's state space representation of this filter is:

u(k): filter input
d1, c1, c2, a2, a1,b1: discrete biquad coefficients
y(k):filter output
p1k and p2k: filter states
MEIFilterFormINT_BIQUAD

Second Order digital filter form, for implementing low/high pass, notch, lead/lag and custom filters. The filter is a fixed point canonical form state space implementation. This form is a fixed point implementation of the floating point form MEIFilterFormBIQUAD. See the definition of MEIFilterFormBIQUAD above for the defining equations for this filter.

The input coefficients for this filter (b0, b1, b2, a1 and a2) should all be greater than -2, and less than 2. The coefficients are represented as 32 bit 2's complement, with 1=2^30. The coefficient's numerical format is 1.29 (1 bit whole, 29 bits fractional), and the controller uses an 80 bit accumulator. Only the 32 bit result of the multiplication is output from each section.
MEIFilterFormINT_SS_BIQUAD

Second Order digital filter form, for implementing low/high pass, notch, lead/lag and custom filters. The filter is a fixed point canonical form state space implementation. This form is a fixed point implementation of the floating point form MEIFilterFormSS_BIQUAD. See the definition of MEIFilterFormSS_BIQUAD above for the defining equations for this filter.

The input coefficients for this filter (d1, c1, c2, a2, a1 and b1) should all be greater than -2, and less than 2. The coefficients are represented as 32 bit 2's complement, with 1=2^30. The coefficient's numerical format is 1.29 (1 bit whole, 29 bits fractional), and the controller uses an 80 bit accumulator. Only the 32 bit result of the multiplication is output from each section.

See Also | MEIPostfilterSection


MPIFilterGain

MPIFilterGain

typedef struct MPIFilterGain {
    MPIFilterCoeff	coeff[MPIFilterCoeffCOUNT_MAX];
} MPIFilterGain;

Description
 | coeff | see MPIFilterCoeff

See Also | MPIFilterGainCOUNT_MAX | MEIFilterGainPIDCoeff | MEIFilterGainPIVCoeff


MPIFilterGainCOUNT_MAX

MPIFilterGainCOUNT_MAX

#define MPIFilterGainCOUNT_MAX (20)

Description
 | FilterGainCOUNT_MAX is a constant that defines the maximum number of filter gain tables. The first gain table is used by the standard filter types (all filter types except for the user filter type as defined by the structure MEIXmpAlgorithm). Additional gain tables can be used for manual or automatic gain switching. For firmware that implements automatic gain switching, please contact Motion Engineering. Manual gain switching can be accomplished by specifying the gainIndex of the mpiFilterConfig structure using the mpiFilterConfigSet method. Valid gainIndex values range from 0 to MPIFilterGainCOUNT_MAX.

See Also | MPIFilterGain


MEIFilterGainIndex

MEIFilterGainIndex

typedef enum {
    MEIFilterGainIndexINVALID   = -1,

    /* Gain table index for normal firmware. */
    MEIFilterGainIndexNO_MOTION = MEIXmpGainNOT_MOVING,
    MEIFilterGainIndexACCEL     = MEIXmpGainACCEL,
    MEIFilterGainIndexDECEL     = MEIXmpGainDECEL,
    MEIFilterGainIndexVELOCITY  = MEIXmpGainCONSTANT_VEL,

    /* Gain table index for Custom 1 firmware. */
    MEIFilterGainIndexSTOPPING2 = MEIXmpGainSTOPPED2,
    MEIFilterGainIndexSTOPPING1 = MEIXmpGainSTOPPED1,
    MEIFilterGainIndexSETTLING  = MEIXmpGainSETTLING,
    MEIFilterGainIndexMOVING    = MEIXmpGainMOVING,
    MEIFilterGainIndexSTOPPING3 = MEIXmpGainSTOPPED3,

    /* Gain table index for Custom 5 firmware. */
    MEIFilterGainIndexMIN       = MEIXmpGainMIN,
    MEIFilterGainIndexMAX       = MEIXmpGainMAX,
    MEIFilterGainIndexNONE      = MEIXmpGainNONE,
    MEIFilterGainIndexSLOPE     = MEIXmpGainSLOPE,

    MEIFilterGainIndexLAST      = MEIXmpGainLAST,
    MEIFilterGainIndexALL       = MEIFilterGainIndexLAST, /* used for gain get/set() */
    MEIFilterGainIndexFIRST     = MEIFilterGainIndexINVALID + 1,

    MEIFilterGainIndexDEFAULT   = MEIFilterGainIndexNO_MOTION,
} MEIFilterGainIndex;

Description
 | FilterGainIndex is a constant enum structure defining gain indexes used to select one of the four filter gain tables.
See Also


MEIFilterGainPID

MEIFilterGainPID

typedef	struct MEIFilterGainPID {
    struct {
    float   proportional;     /* Kp */
    float   integral;         /* Ki */
    float   derivative;       /* Kd */
    } gain;
    struct {
        float   position;     /* Kpff */
        float   velocity;     /* Kvff */
        float   acceleration; /* Kaff */
        float   friction;     /* Kfff */
    } feedForward;
    struct {
        float   moving;       /* MovingIMax */
        float   rest;         /* RestIMax */
    } integrationMax;
    long    dRate;            /* DRate */
    struct {
        float   limit;        /* OutputLimit */
        float   limitHigh;    /* OutputLimitHigh */
        float   limitLow;     /* OutputLimitLow */
        float   offset;       /* OutputOffset */
    } output;
    struct {
        float   positionFFT;  /* Ka0 */
        float   filterFFT;    /* Ka1 */
        float   velocityFFT;  /* Ka2 */
    } noise;
} MEIFilterGainPID;

Description
 | FilterGainPID is a structure that defines the filter coefficients for the PID filter algorithm.

See Also | High/Low Output Limits section for special instructions regarding MEIFilterGainPID. MEIFilterGainPIDCoeff


MEIFilterGainPIDCoeff

MEIFilterGainPIDCoeff

typedef		enum {
    MEIFilterGainPIDCoeffINVALID = -1,

    MEIFilterGainPIDCoeffGAIN_PROPORTIONAL, /* Kp */
    MEIFilterGainPIDCoeffGAIN_INTEGRAL,     /* Ki */
    MEIFilterGainPIDCoeffGAIN_DERIVATIVE,   /* Kd */

    MEIFilterGainPIDCoeffFEEDFORWARD_POSITION,     /* Kpff */
    MEIFilterGainPIDCoeffFEEDFORWARD_VELOCITY,     /* Kvff */
    MEIFilterGainPIDCoeffFEEDFORWARD_ACCELERATION, /* Kaff */
    MEIFilterGainPIDCoeffFEEDFORWARD_FRICTION,     /* Kfff */

    MEIFilterGainPIDCoeffINTEGRATIONMAX_MOVING, /* MovingIMax */
    MEIFilterGainPIDCoeffINTEGRATIONMAX_REST,   /* RestIMax */

    MEIFilterGainPIDCoeffDRATE,             /* DRate */

    MEIFilterGainPIDCoeffOUTPUT_LIMIT,      /* OutputLimit */
    MEIFilterGainPIDCoeffOUTPUT_LIMITHIGH,  /* OutputLimitHigh */
    MEIFilterGainPIDCoeffOUTPUT_LIMITLOW,   /* OutputLimitLow */
    MEIFilterGainPIDCoeffOUTPUT_OFFSET,     /* OutputOffset */

    MEIFilterGainPIDCoeffNOISE_POSITIONFFT, /* Ka0 */
    MEIFilterGainPIDCoeffNOISE_FILTERFFT,   /* Ka1 */
    MEIFilterGainPIDCoeffNOISE_VELOCITYFFT, /* Ka2 */

} MEIFilterGainPIDCoeff;

Description
 | FilterGainPIDCoeff is a structure of enums that defines the filter coefficients for the PID filter algorithm.

See Also | MEIFilterGainPID


MEIFilterGainPIV

MEIFilterGainPIV

typedef		struct MEIFilterGainPIV {
    struct {
        float   proportional;   /* Kpp */
        float   integral;       /* Kip */
    } gainPosition;
    struct {
        float   proportional;   /* Kpv */
    } gainVelocity1;
    struct {
        float   position;       /* Kpff */
        float   velocity;       /* Kvff */
        float   acceleration;   /* Kaff */
        float   friction;       /* Kfff */
    } feedForward;
    struct {
        float   moving;     /* MovingIMax */
        float   rest;       /* RestIMax */
    } integrationMax;
    struct {
        float   feedback;   /* Kdv */
    } gainVelocity2;
    struct {
        float   limit;      /* OutputLimit */
        float   limitHigh;  /* OutputLimitHigh */
        float   limitLow;   /* OutputLimitLow */
        float   offset;     /* OutputOffset */
    } output;
    struct {
        float   integral;        /* Kiv */
        float   integrationMax;  /* VintMax */
    } gainVelocity3;
    struct {
        float   positionFFT;  /* Ka0 */
        float   filterFFT;    /* Ka1 */
    } noise;
} MEIFilterGainPIV;

Description
 | FilterGainPIV is a structure that defines the filter coefficients for the PIV filter algorithm.

See Also | High/Low Output Limits section for special instructions regarding MEIFilterGainPIV. MEIFilterGainPIVCoeff


MEIFilterGainPIVCoeff

MEIFilterGainPIVCoeff

typedef		enum {
    MEIFilterGainPIVCoeffINVALID = -1,

    MEIFilterGainPIVCoeffGAINPOSITION_PROPORTIONAL,	/* Kpp */
    MEIFilterGainPIVCoeffGAINPOSITION_INTEGRAL,		/* Kip */

    MEIFilterGainPIVCoeffGAINVELOCITY_PROPORTIONAL,	/* Kpv */

    MEIFilterGainPIVCoeffFEEDFORWARD_POSITION,		/* Kpff */
    MEIFilterGainPIVCoeffFEEDFORWARD_VELOCITY,		/* Kvff */
    MEIFilterGainPIVCoeffFEEDFORWARD_ACCELERATION,	/* Kaff */
    MEIFilterGainPIVCoeffFEEDFORWARD_FRICTION,		/* Kfff */

    MEIFilterGainPIVCoeffINTEGRATIONMAX_MOVING,		/* MovingIMax */
    MEIFilterGainPIVCoeffINTEGRATIONMAX_REST,		/* RestIMax */

    MEIFilterGainPIVCoeffGAINVELOCITY_FEEDBACK,		/* Kdv */

    MEIFilterGainPIVCoeffOUTPUT_LIMIT,		/* OutputLimit */
    MEIFilterGainPIVCoeffOUTPUT_LIMITHIGH,	/* OutputLimitHigh */
    MEIFilterGainPIVCoeffOUTPUT_LIMITLOW,	/* OutputLimitLow */
    MEIFilterGainPIVCoeffOUTPUT_OFFSET,		/* OutputOffset */

    MEIFilterGainPIVCoeffGAINVELOCITY_INTEGRAL,		/* Kiv */
    MEIFilterGainPIVCoeffGAINVELOCITY_INTEGRATIONMAX,	/* Vintmax */

    MEIFilterGainPIVCoeffNOISE_POSITIONFFT,		/* Ka0 */
    MEIFilterGainPIVCoeffNOISE_FILTERFFT,		/* Ka1 */

} MEIFilterGainPIVCoeff;

Description
 | FilterGainPIVCoeff is a structure of enums that defines the filter coefficients for the PIV filter algorithm.

See Also | High/Low Output Limits section for special instructions regarding MEIFilterGainPIV. MEIFilterGainPIV


MEIFilterGainTypePID

MEIFilterGainTypePID

static MEIDataType MEIFilterGainTypePID[MPIFilterCoeffCOUNT_MAX] =
{
    MEIDataTypeFLOAT, /* Kp               */
    MEIDataTypeFLOAT, /* Ki               */
    MEIDataTypeFLOAT, /* Kd               */

    MEIDataTypeFLOAT, /* Kpff             */
    MEIDataTypeFLOAT, /* Kvff             */
    MEIDataTypeFLOAT, /* Kaff             */
    MEIDataTypeFLOAT, /* Kfff             */

    MEIDataTypeFLOAT, /* MovingIMax       */
    MEIDataTypeFLOAT, /* RestIMax         */

    MEIDataTypeLONG,  /* DRate            */

    MEIDataTypeFLOAT, /* OutputLimit      */
    MEIDataTypeFLOAT, /* OutputLimitHigh  */
    MEIDataTypeFLOAT, /* OutputLimitLow   */
    MEIDataTypeFLOAT, /* OutputOffset     */
    MEIDataTypeFLOAT, /* Ka0              */
    MEIDataTypeFLOAT, /* Ka1              */
    MEIDataTypeFLOAT, /* Ka2              */
};
Description

FilterGainTypePID is a static array that describes the data type of the coefficients for the PID algorithm. Specifically, an element of MEIFilterGainTypePID describes which member of the union MPIFilterCoeff to access when using the data structure MPIFilterCoeff.

MEIFilterGainTypePID allows for a more simple design of general case utilities and configuration routines. If it is known that only the PID parameters will be used, then the data structure MEIFilterGainPID can be used directly without having to manipulate MPIFilterCoeff, MPIFilterCoeff, and MEIFilterGainTypePID.

Sample Code

/*  Read the current value of a filter's PID coefficient.  Sample usage:

    returnValue =
        getPidFilterCoeff(filter, MEIFilterGainPIDCoeffGAIN_PROPORTIONAL, &kp);
*/
long getPidFilterCoeff(MPIFilter filter, long index, double* value)
{

    MPIFilterConfig config;
    long returnValue = (value==NULL) ? MPIMessageARG_INVALID : MPIMessageOK;

    if (returnValue == MPIMessageOK)
    {
        returnValue = mpiFilterConfigGet(filter, &config, NULL);

        if (returnValue == MPIMessageOK)
        {
            switch(MEIFilterGainTypePID[index])
            {
                case MEIDataTypeLONG:
                    *value = config.gain[config.gainIndex].coeff[index].l;
                    break;
                case MEIDataTypeFLOAT:
                    *value = config.gain[config.gainIndex].coeff[index].f;
                    break;
                default:
                    returnValue = MPIMessageARG_INVALID;
             }
         }
    }
return returnValue;
}

See Also | MPIFilterCoeff | MEIFilterGainTypePIV | MEIFilterGainPID | MEIDataType | MPIFilterGain |


MEIFilterGainTypePIV

MEIFilterGainTypePIV

static MEIDataType MEIFilterGainTypePIV[MPIFilterCoeffCOUNT_MAX] =
{
    MEIDataTypeFLOAT, /* Kpp              */
    MEIDataTypeFLOAT, /* Kip              */

    MEIDataTypeFLOAT, /* Kpv              */

    MEIDataTypeFLOAT, /* Kpff             */
    MEIDataTypeFLOAT, /* Kvff             */
    MEIDataTypeFLOAT, /* Kaff             */
    MEIDataTypeFLOAT, /* Kfff             */

    MEIDataTypeFLOAT, /* MovingIMax       */
    MEIDataTypeFLOAT, /* RestIMax         */

    MEIDataTypeFLOAT, /* Kdv              */

    MEIDataTypeFLOAT, /* OutputLimit      */
    MEIDataTypeFLOAT, /* OutputLimitHigh  */
    MEIDataTypeFLOAT, /* OutputLimitLow   */
    MEIDataTypeFLOAT, /* OutputOffset     */

    MEIDataTypeFLOAT, /* Kiv              */
    MEIDataTypeFLOAT, /* Vintmax          */

    MEIDataTypeFLOAT, /* Ka0              */
    MEIDataTypeFLOAT, /* Ka1              */
};
Description

FilterGainTypePIV is a static array that describes the data type of the coefficients for the PIV algorithm. Specifically, an element of MEIFilterGainTypePIV describes which member of the union MPIFilterCoeff to access when using the data structure MPIFilterCoeff.

MEIFilterGainTypePIV allows for a more simple design of general case utilities and configuration routines. If it is known that only the PIV parameters will be used, then the data structure MEIFilterGainPIV can be used directly without having to manipulate MPIFilterCoeff, MPIFilterCoeff, and MEIFilterGainTypePIV.

Sample Code

/*   Read the current value of a filter's PIV coefficient.  Sample usage:

     returnValue =
         getPivFilterCoeff(filter, MEIFilterGainPIVCoeffGAINVELOCITY_PROPORTIONAL, &kpv);
*/
long getPivFilterCoeff(MPIFilter filter, long index, double* value)
{
     MPIFilterConfig config;
     long returnValue = (value==NULL) ? MPIMessageARG_INVALID : MPIMessageOK;

     if (returnValue == MPIMessageOK)
     {

         returnValue = mpiFilterConfigGet(filter, &config, NULL);

         if (returnValue == MPIMessageOK)
         {
              switch(MEIFilterGainTypePIV[index])
              {
                   case MEIDataTypeLONG:
                        *value = config.gain[config.gainIndex].coeff[index].l;
                        break;
                   case MEIDataTypeFLOAT:
                        *value = config.gain[config.gainIndex].coeff[index].f;
                        break;
                   default:
                        returnValue = MPIMessageARG_INVALID;
              }
         }
    }

    return returnValue;
}

See Also | MPIFilterCoeff | MEIFilterGainTypePID | MEIFilterGainPIV | MEIDataType | MPIFilterGain |


MEIMaxBiQuadSections

MEIMaxBiQuadSections

#define MEIMaxBiQuadSections  (6)
Description

MEIMaxBiQuadSections is the maximum number of Bi-Quad sections a postfilter can use.

NOTE: The PIV algorithm uses the last Bi-Quad section internally. Thus a user can only use (MEIMaxBiQuadSections - 1) Bi-quad sections with the PIV algorithm.

See Also | MEIPostFilterSection | meiFilterPostfilterGet | meiFilterPostfilterSet | meiFilterPostfilterSectionGet | meiFilterPostfilterSectionSet


MPIFilterMessage

MPIFilterMessage

typedef enum {
    MPIFilterMessageFILTER_INVALID,
    MPIFilterMessageINVALID_ALGORITHM,
    MPIFilterMessageINVALID_DRATE,
} MPIFilterMessage;
Description
MPIFilterMessageFILTER_INVALID
The filter number is out of range. This message code is returned by mpiFilterCreate(…) if the filter number is less than zero or greater than or equal to MEIXmpMAX_Filters.
MPIFilterMessageINVALID_ALGORITHM
The filter algorithm is not valid. This message code is returned by mpiFilterIntegratorReset(…) if the filter algorithm is not a member of the MEIXmpAlgorithm enumeration (does not support integrators). This problem occurs if the filter type is set to user or an unknown type with mpiFilterConfigSet(…).
MPIFilterMessageINVALID_DRATE

The filter derivative rate is not valid. This message code is returned by mpiFilterConfigSet(…) if the filter derivative rate is less than 0 or greater than 7.

NOTE: The derivative rate for all gain tables must be in the range [0,7], not just the derivative rate for the current gain table.

See Also | mpiFilterCreate


MEIPostfilterSection

MEIPostfilterSection

typedef struct MEIPostfilterSection {
   MEIFilterType    type;
   MEIFilterForm    form;
   union {
        struct {
            double breakPoint;      /* Hz */
        } lowPass;

        struct {
            double breakPoint;     /* Hz */
        } highPass;

        struct {
            double centerFrequency; /* Hz */
            double bandwidth;       /* Hz */
        } notch;

        struct {
            double centerFrequency; /* Hz */
            double bandwidth;       /* Hz */
            double gain;            /* dB */
        } resonator;

        struct {
            double lowFrequencyGain;    /* dB */
            double highFrequencyGain;   /* dB */
            double centerFrequency;     /* Hz */
        } leadLag;

        /* Analog coefficients */
        struct {
            double a1;
            double a2;
            double b0;
            double b1;
            double b2;
        } biquad;

        struct {
            double a1;
            double a2;
            double b0;
            double b1;
            double b2;
        } digitalBiquad;

        struct {
            double d1;
            double c1;
            double c2;
            double a2;
            double a1;
            double b1;
        } stateSpaceBiquad;
        struct {
            long     numberOfCoefficients;
            double   coeff[MEIXmpMAX_PostFilterSize];
        } iir;
    } data;
} MEIPostfilterSection;
Description

MEIPostfilterSection holds the configuration data for a single section of an MPIFilter object's postfilter. The MPI calculates the post filter coefficients and takes into consideration the sample rate of the controller at that time. If you change the sample rate of the controller, you will need to recalculate the post filters. This can be done for all filters specified in Hertz by setting the filters again with the MPI. The MPI will calculate the filters using the current servo sample rate.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.
type | The postfilter section type. This field determines which field of the MEIPostfilterSection.data union is used by meiFilterPostfilter…() methods. More information about particular filter types can be found below and in the MEIFilterType documentation.
form | The form of a postfilter section. The form determines how a particular postfilter section is calculated on the controller. All forms have certain limitations and tradeoffs. Please refer to MEIFilterForm for more information.
lowPass.breakpoint

The break point (measured in Hertz) of a low pass postfilter section.

Example of a 50 Hz low pass filter.
highPass.breakpoint

The break point (measured in Hertz) of a high pass postfilter section.

Example of a 50 Hz High pass filter
notch.centerFrequency

The bandwidth (measured in Hertz) of a notch postfilter section.

Example of a 50 Hz Center / 50 Hz Bandwidth Notch filter. Note that phase wrapping gives the illusion that phase drops 180 degrees after the center frequency. The phase raises by 180 degrees.
notch.bandwidth

The center frequency (measured in Hertz) of a notch postfilter section.

Example of a 50 Hz Center / 50 Hz Bandwidth Notch filter. Note that phase wrapping gives the illusion that phase drops 180 degrees after the center frequency. The phase raises by 180 degrees.
resonator.centerFrequency

The center frequency (measured in Hertz) of a resonator postfilter section.

Example of a 50 Hz center / 50 Hz Bandwidth / -40 dB Gain Resonator filter. Note that phase wrapping gives the illusion that the phase drops 360 degrees after the center frequency.
resonator.bandwidth

The bandwidth (measured in Hertz) of a resonator postfilter section.

Example of a 50 Hz center / 50 Hz Bandwidth / -40 dB Gain Resonator filter. Note that phase wrapping gives the illusion that the phase drops 360 degrees after the center frequency.
resonator.gain

The center frequency gain (measured in dB) of a resonator postfilter section.

Example of a 50 Hz center / 50 Hz Bandwidth / -40 dB Gain Resonator filter. Note that phase wrapping gives the illusion that the phase drops 360 degrees after the center frequency.
leadLad.centerFrequency

The center frequency (measured in Hertz) of a lead or lag postfilter section. The amplitude at this frequency is the average amplitude of the low and high frequency amplitudes. The gain (measured in dB) at this point is given by:

Example of a -20 dB low frequency gain / -60 dB high frequency gain / 50 Hz center lead lag filter.
leadLag.lowFrequencyGain

The low frequency gain (measured in dB) of a lead or lag postfilter section.

Example of a -20 dB low frequency gain / -60 dB high frequency gain / 50 Hz center lead lag filter.
leadLag.highFrequencyGain

The high frequency gain (measured in dB) of a lead or lag postfilter section.

Example of a -20 dB low frequency gain / -60 dB high frequency gain / 50 Hz center lead lag filter.
biquad.a1

The analog coefficients of a single order or bi-quad postfilter section.

Analog values of the postfilter coefficients are produced as parts of a Laplace Transform:

and
biquad.a2
biquad.b0
biquad.b1
biquad.b2
iir.numberOfCoefficients | The number of coefficients of an IIR postfilter.
iir.coeff[] | The coefficients of an IIR postfilter. The maximum number of coefficient is MEIMaxIIRCoefficients.
digitalBiquad.a1

The digital coefficients of a single order or bi-quad postfilter section.

Currently not used by the MPI. These members are reserved for future use.
digitalBiquad.a2
digitalBiquad.b0
digitalBiquad.b1
digitalBiquad.b2
digitalBiquad.d1

The digital coefficients of a state-space bi-quad postfilter section.

Currently not used by the MPI. These members are reserved for future use.
digitalBiquad.c1
digitalBiquad.c2
digitalBiquad.a2
digitalBiquad.a1
digitalBiquad.b1
Sample Code

/*   Set a 4th order low-pass post-filter by using two 2nd order low-pass sections.
     Sample usage:

     returnValue =
         fourthOrderLowPass(filter, 300 /* Hz */);
*/
long filterFouthOrderLowpass(MPIFilter filter, long breakPointFrequency)
{
    MPIFilterConfig config;
    MEIPostfilterSection sections[2];
    long returnValue;

    section[0].type = MEIFilterTypeLOW_PASS;
    section[0].form = MEIFilterFormINT_BIQUAD;
    section[0].lowPass.breakpoint = breakPointFrequency;
    section[1] = section[0]; /* copy first section */

    returnValue =
        meiFilterPostfilterSet(filter, 2, sections);

    return returnValue;
}

See Also | MEIFilterType | MEIFilterForm | MEIMaxIIRCoefficients | meiFilterPostfilterGet | meiFilterPostfilterSet | meiFilterPostfilterSectionGet | meiFilterPostfilterSectionSet


MEIFilterType

MEIFilterType

typedef enum {
    MEIFilterTypeUNITY_GAIN,
        /* B0 = 1    B1=B2=A1=A2 = 0  (effectively acting as no filter) */
    MEIFilterTypeSINGLE_ORDER,
    MEIFilterTypeLOW_PASS,
    MEIFilterTypeHIGH_PASS,
    MEIFilterTypeNOTCH,
    MEIFilterTypeRESONATOR,
    MEIFilterTypeLEAD_LAG,
    MEIFilterTypeZERO_GAIN,
        /* b0=b1=b2=a1=a2 = 0  (this does act as a filter.... zeroing the output) */
    MEIFilterTypeUNKNOWN,
        /* algorithm couldn't figure out what this filter was from the coeffs! */
} MEIFilterType;

Description
 | MEIFilterTypeUNITY_GAIN | Sets the postfilter section to unity gain with bi-quad coefficients, effectively performing no filtering.
 | MEIFilterTypeBIQUAD | Sets the postfilter section to a bi-quad filter.
 | MEIFilterTypeSINGLE_ORDER | Sets the postfilter section to a single-order filter.
 | MEIFilterTypeLOW_PASS | Sets the postfilter section to a bi-quad filter low pass filter.
 | MEIFilterType_HIGH_PASS | Sets the postfilter section to a bi-quad filter high pass filter.
 | MEIFilterTypeNOTCH | Sets the postfilter section to a bi-quad notch filter.
 | MEIFilterTypeRESONATOR | Sets the postfilter section to a bi-quad resonator filter.
 | MEIFilterTypeLEAD_LAG | Sets the postfilter section to a bi-quad lead or lag filter.
 | MEIFilterTypeZERO_GAIN | Sets the postfilter section to zero gain with bi-quad coefficients, zeroing the output.
 | MEIFilterTypeUNKNOWN |
See Also | MEIPostfilterSection | meiFilterPosterfilterGet | meiFilterPosterfilterSet | meiFilterPosterfilterSectionGet | meiFilterPosterfilterSectionSet


mpiFilterAxisMapGet

Declaration
long mpiFilterAxisMapGet(MPIFilter    filter,
                         MPIObjectMap *axisMap)
Required Header stdmpi.h
Description

FilterAxisMapGet gets the object map of the Axes that are associated with a Filter (filter), and writes it into the structure pointed to by axisMap.
Return Values
MPIMessageOK if FilterAxisMapGet successfully writes the object map of Axes to the structure
See Also | mpiFilterAxisMapSet


mpiFilterAxisMapSet

Declaration
long mpiFilterAxisMapSet(MPIFilter    filter,
                         MPIObjectMap axisMap)
Required Header stdmpi.h
Description

FilterAxisMapSet sets the Axes associated with a Filter (filter), using data from the object map specified by axisMap.

Return Values
MPIMessageOK if FilterAxisMapSet successfully sets the Axes using the object map
See Also | mpiFilterAxisMapGet


mpiFilterConfigGet

Declaration
long mpiFilterConfigGet(MPIFilter       filter,
                        MPIFilterConfig *config,
                        void            *external)
Required Header stdmpi.h
Description

FilterConfigGet gets a Filter’s (filter) configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Filter’s configuration information in external is in addition to the Filter’s configuration information in config, i.e, the Filter’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIFilterConfig{} or is NULL.
Return Values
MPIMessageOK if FilterConfigGet successfully writes the Filter’s configuration to the structure(s)
See Also | mpiFilterConfigSet | MEIFilterConfig


mpiFilterConfigSet

Declaration
long mpiFilterConfigSet(MPIFilter       filter,
                        MPIFilterConfig *config,
                        void            *external)
Required Header stdmpi.h
Description

FilterConfigSet sets a Filter’s (filter) configuration using data from the structure pointed to by config, and from the implementation-specific structure pointed to by external (if external is not NULL).

The Filter’s configuration information in external is in addition to the Filter’s configuration information in config, i.e, the Filter’s configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIFilterConfig{} or is NULL.
Return Values
MPIMessageOK if FilterConfigSet successfully sets the Filter’s configuration using data from the structure(s)
See Also | mpiFilterConfigGet | MEIFilterConfig


mpiFilterControl

Declaration
MPIControl mpiFilterControl(MPIFilter filter)
Required Header stdmpi.h
Description

FilterControl returns a handle to the motion controller (Control object) associated with the specified Filter object (filter).

Return Values
handle | to a Control object that a Filter object is associated with
MPIHandleVOID | if the Filter object is invalid
See Also


mpiFilterCreate

Declaration
MPIFilter mpiFilterCreate(MPIControl  control,
                          long        number)
Required Header stdmpi.h
Description

FilterCreate creates a Filter object associated with a filter (number), that is located on a motion controller (control).
FilterCreate is the equivalent of a C++ constructor.

Return Values
handle | to an Filter object
MPIHandleVOID | if the Filter object could not be created

See Also | mpiFilterDelete | mpiFilterValidate


mpiFilterDelete

Declaration
long mpiFilterDelete(MPIFilter filter)
Required Header stdmpi.h
Description

FilterDelete deletes a Filter object and invalidates its handle (filter). FilterDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if FilterDelete successfully deletes a Filter object and invalidates its handle
See Also | mpiFilterCreate | mpiFilterValidate


mpiFilterFlashConfigGet

Declaration
long mpiFilterFlashConfigGet(MPIFilter       filter,
                             void            *flash,
                             MPIFilterConfig *config,
                             void            *external)
Required Header stdmpi.h
Description

FilterFlashConfigGet gets a Filter’s (filter) flash configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Filter’s flash configuration information in external is in addition to the Filter’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIFilterConfig{} or is NULL.

Return Values
MPIMessageOK if FilterFlashConfigGet successfully writes the Filter’s flash configuration to the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIFlash | mpiFilterFlashConfigSet |MEIFilterConfig


mpiFilterFlashConfigSet

Declaration
long mpiFilterFlashConfigSet(MPIFilter       filter,
                             void            *flash,
                             MPIFilterConfig *config,
                             void            *external)
Required Header stdmpi.h
Description

FilterFlashConfigSet sets a Filter’s (filter) flash configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Filter’s flash configuration information in external is in addition to the Filter’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEIFilterConfig{} or is NULL.
Return Values
MPIMessageOK if FilterFlashConfigSet successfully sets the Filter’s flash configuration using data from the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIFlash | mpiFilterFlashConfigGet | MEIFilterConfig


mpiFilterGainGet

Declaration
long mpiFilterGainGet(MPIFilter     filter,
                      long          gainIndex,
                      MPIFilterGain *gain)
Required Header stdmpi.h
Description

FilterGainGet gets the gain coefficients of a Filter (filter, for the gain index specified by gainIndex) and writes them into the structure pointed to by gain.
Return Values
MPIMessageOK if FilterGainGet successfully writes the gain coefficients to the structure
See Also | mpiFilterGainSet


mpiFilterGainIndexGet

Declaration
long mpiFilterGainIndexGet(MPIFilter filter,
                           long      *gainIndex)
Required Header stdmpi.h
Description

FilterGainIndexGet gets the current gain index of a Filter (filter) and writes it to the location pointed to by gainIndex.

Return Values
MPIMessageOK if FilterGainIndexGet successfully writes the gain index to the location
See Also | mpiFilterGainIndexSet


mpiFilterGainIndexSet

Declaration
long mpiFilterGainIndexSet(MPIFilter   filter,
                           long        gainIndex)
Required Header stdmpi.h
Description

FilterGainIndexSet sets the current gain index of a Filter (filter) to gainIndex.
Return Values
MPIMessageOK if FilterGainIndexSet successfully sets the current gain index to gainIndex
See Also | mpiFilterGainIndexGet


mpiFilterGainSet

Declaration
long mpiFilterGainSet(MPIFilter     filter,
                      long          gainIndex,
                      MPIFilterGain *gain)
Required Header stdmpi.h
Description

FilterGainSet sets the gain coefficients of a Filter (filter, for the gain index specified by gainIndex) using data from the structure pointed to by gain.

Return Values
MPIMessageOK if FilterGainSet successfully sets the gain coefficients of a Filter using data from the structure
See Also | mpiFilterGainGet


mpiFilterIntergratorReset

.

mpiFilterIntegratorReset

Declaration
long mpiFilterIntegratorReset(MPIFilter filter)
Required Header stdmpi.h
Description

FilterIntegratorReset resets the integrators of filter.

Return Values
MPIMessageOK | if mpiFilterIntegratorReset successfully clears the integrators of filter.
MPIFilterMessageINVALID_ALGORITHM | if the filter's current algorithm does not use integrators.

Sample Code

/* Enable the amplifier for every motor attached to a motion supervisor */
void motionAmpEnable(MPIMotion	motion)
{
    MPIControl		control;
    MPIAxis			axis;
    MPIMotor		motor;
    MPIFilter		filter;
    MPIObjectMap	map;
    MPIObjectMap	motionMotorMap;
    long			motorIndex;
    long			filterIndex;
    long			returnValue;
    double			position;
    long			enableState;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* For every axis */
                for (axis =  mpiMotionAxisFirst(motion);
                     axis != MPIHandleVOID;
                     axis =  mpiMotionAxisNext(motion, axis)) {

                    /* Get the object map for the motors */
                    returnValue = mpiAxisMotorMapGet(axis, &map);
                    msgCHECK(returnValue);

                    /* If axis is attached to motor ... */
                    if (mpiObjectMapBitGET(map, motorIndex)) {

                        /* Get the actual position of the axis */
                        returnValue = mpiAxisActualPositionGet(axis, &position);
                        msgCHECK(returnValue);

                        /* Set command position equal to actual position */
                        returnValue = mpiAxisCommandPositionSet(axis, position);
                        msgCHECK(returnValue);
                    }
                }

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &map);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MEIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(map, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

See Also | MPIFilter | MEIFilterConfig | MEIFilterGainPID | MEIFilterGainPIV mpiAxisActualPositionGet | mpiAxisCommandPositionSet

Troubleshooting / Helpful Hints

If an axis is not in an error state and the filter associated with that axis' motor has a non-zero integration term, then it is very likely that the integrator has built up a substantial integral term. Enabling the motor's amplifier when this has happened could cause the motor to jump with enormous force. Use mpiFilterIntegratorReset to reset the integrator before enabling the motor's amplifier to prevent this kind of jump.

Another condition that can cause the motor to jump upon enabling its amplifier is that the command position of the axis is not equal to the actual position of the axis. To prevent this situation, one should use mpiAxisActualPositionGet and mpiAxisCommandPositionSet. Please refer to this functions for a more in depth discussion.


mpiFilterMemory

Declaration
long mpiFilterMemory(MPIFilter  filter,
                     void       **memory)
Required Header stdmpi.h
Description

FilterMemory writes an address, which is used to access a Filter’s (filter) memory to the contents of memory. This address, or an address calculated from it, can be passed as the src parameter to MPIFilterMemoryGet(...) and as the dst parameter to MPIFilterMemorySet(...).

Return Values
MPIMessageOK if FilterMemory successfully writes the Filter’s memory address to the contents of memory
See Also | mpiFilterMemoryGet | mpiFilterMemorySet


mpiFilterMemoryGet

Declaration
long mpiFilterMemoryGet(MPIFilter filter,
                        void      *dst,
                        void      *src,
                        long      count)
Required Header stdmpi.h
Description FilterMemoryGet copies count bytes of a Filter’s (filter) memory (starting at address src) and writes them into application memory (starting at address dst).
Return Values
MPIMessageOK if FilterMemoryGet successfully copies data from Filter memory to application memory
See Also | mpiFilterMemorySet | mpiFilterMemory


mpiFilterMemorySet

Declaration
long mpiFilterMemorySet(MPIFilter filter,
                        void      *dst,
                        void      *src,
                        long      count)
Required Header stdmpi.h
Description FilterMemorySet copies count bytes of application memory (starting at address src) and writes them into a Filter’s (filter) memory (starting at address dst).
Return Values
MPIMessageOK if FilterMemoryGet successfully copies data from application memory to Filter memory
See Also | mpiFilterMemoryGet | mpiFilterMemory


mpiFilterMotorMapGet

Declaration
long mpiFilterMotorMapGet(MPIFilter    filter,
                          MPIObjectMap *motorMap)
Required Header stdmpi.h
Description FilterMotorMapGet gets the object map of the Motors associated with the Filter (filter), and writes it into the structure pointed to by motorMap.
Return Values
MPIMessageOK if FilterMotorMapGet successfully writes the object map of the Motors to the structure
See Also | mpiFilterMotorMapSet


mpiFilterMotorMapSet

Declaration
long mpiFilterMotorMapSet(MPIFilter    filter,
                          MPIObjectMap motorMap)
Required Header stdmpi.h
Description FilterMotorMapSet sets the Motors associated with the Filter (filter) using data from the object map specified by motorMap.
Return Values
MPIMessageOK if FilterMotorMapGet successfully sets the Motors using data from the object map
See Also | mpiFilterMotorMapGet


mpiFilterNumber

Declaration
long mpiFilterNumber(MPIFilter  filter,
                     long       *number)
Required Header stdmpi.h
Description For a motion controller that filter is associated with, FilterNumber writes the index of filter to the contents of number.
Return Values
MPIMessageOK if FilterNumber successfully writes the index of a Filter to the contents of number
See Also


meiFilterPostfilterGet

Declaration
long meiFilterPostfilterGet(MPIFilter             filter,
                            long                  *sectionCount,
                            MEIPostfilterSection  *sections);
Required Header stdmei.h
Description

PostfilterGet reads an MPIFilter object's postfilter configuration. It writes to sectionCount the number of sections within a postfilter if sectionCount is not NULL. It also writes to sections the current array of filter's postfilter sections if sections is not NULL.

The MPI calculates the post filter coefficients and takes into consideration the sample rate of the controller at that time. If you change the sample rate of the controller, you will need to recalculate the post filters. This can be done for all filters specified in Hertz by setting the filters again with the MPI. The MPI will calculate the filters using the current servo sample rate.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.

filter | the handle of the MPIFilter object whose postfilter configuration is to be read.
*sectionCount | the data location where the postfilter's current section count will be written.
*sections | the data location where the postfilter's current section configuration data will be written.
Sample Code

/*   Count the number of resonator sections in a MPIFilter object's postfilter.
     Sample usage:

     returnValue =
         filterResonatorCount(filter, &resonatorCount);
*/

long filterResonatorCount(MPIFilter filter, long* count)
{
     MPIFilterConfig config;
     MEIPostfilterSection sections[MEIMaxBiQuadSections];
     long sectionCount, index;
     long returnValue = (count==NULL) ? MPIMessageARG_INVALID : MPIMessageOK;

     if (returnValue == MPIMessageOK)
     {
         returnValue =
             meiFilterPostfilterGet(filter, &sectionCount, sections);

         if (returnValue == MPIMessageOK)
         {
             for (*count=0, index=0; index sectionCount; ++index)
             {
                  if (section[index].type == MEIFilterTypeRESONATOR) ++(*count);
             }
         }
      }
      return returnValue;
}
Return Values
MPIMessageOK if PostfilterGet successfully retrieves postfilter information.
See Also | MEIPostfilterSection | meiFilterPostfilterSet | meFilterPostfilterSectionGet | MEIMaxBiQuadSections |


meiFilterPostfilterSectionGet

Declaration
long meiFilterPostfilterSectionGet(MPIFilter             filter,
                                   long                  sectionNumber,
                                   MEIPostfilterSection  *section);
Required Header stdmei.h
Description

PostfilterSectionGet reads the configuration of a single section of an MPIFilter object's postfilter. It writes to *section the configuration of filter's postfilter sectionNumberth section.

The MPI calculates the post filter coefficients and takes into consideration the sample rate of the controller at that time. If you change the sample rate of the controller, you will need to recalculate the post filters. This can be done for all filters specified in Hertz by setting the filters again with the MPI. The MPI will calculate the filters using the current servo sample rate.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.

filter | the handle of the MPIFilter object whose postfilter section configuration is to be read.
sectionNumber | the index of the postfilter section whose configuration is to be read.
section | the data location where the postfilter's current section configuration data will be written.
Sample Code

/*   Test a section of a MPIFilter object's postfilter to see if it is a notch type.
     Sample usage:

     returnValue =
         isSectionTypeNotch(filter, 0, &isNotch);
*/
long isSectionTypeNotch(MPIFilter filter, long sectionIndex, long* isNotch)
{
    MPIFilterConfig config;
    MEIPostfilterSection section;
    long returnValue = (isNotch==NULL) ? MPIMessageARG_INVALID : MPIMessageOK;

    if (returnValue == MPIMessageOK)
    {
        returnValue =
            meiFilterPostfilterSectionGet(filter, sectionIndex, §ion);
        if (returnValue == MPIMessageOK)
        {
            *isNotch = (section.type == MEIFilterTypeNOTCH) ? TRUE : FALSE;
        }
     }

     return returnValue;
}
Return Values
MPIMessageOK if PostfilterSectionGet successfully reads postfilter section information.
See Also | MEIPostfilterSection | meiFilterPostfilterGet | meFilterPostfilterSectionSet | MEIMaxBiQuadSections


meiFilterPostfilterSectionSet

Declaration
long meiFilterPostfilterSectionSet(MPIFilter             filter,
                                   long                  sectionNumber,
                                   MEIPostfilterSection  *section);
Required Header stdmei.h
Description

PostfilterSectionSet sets the configuration of a single section of an MPIFilter object's postfilter. It sets filter's postfilter sectionNumberth section to the configuration specified in *section. If the postfilter type is IIR, then this method is essentially equivalent to meiFilterPostfilterSet().

The MPI calculates the post filter coefficients taking into consideration the sample rate of the controller at that time. If you change the change the sample rate of the controller, you will need to recalculate your post filters. This can be done for all filters specified in Hertz by setting the filters again using the MPI. The MPI will calculate the filters using the current servo sample rate.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.

filter | the handle of the MPIFilter object whose postfilter section configuration is to be set.
sectionNumber | the index of the postfilter section whose configuration is to be set.
*section | the data location of the section configuration to copy to the controller.
Sample Code

/*   Set a section of a MPIFilter object's postfilter to a unity gain filter type.
     Sample usage:

     returnValue =
         setSectionTypeUnityGain(filter, 3);
*/
long setSectionTypeUnityGain(MPIFilter filter, long sectionIndex)
{
    MPIFilterConfig config;
    MEIPostfilterSection section;
    long returnValue;

    section.type = MEIFilterTypeUNITY_GAIN;
    section.form = MEIFilterFormBIQUAD;

    returnValue =
        meiFilterPostfilterSectionSet(filter, sectionIndex, §ion);

    return returnValue;
}
Return Values
MPIMessageOK if PostfilterSectionSet successfully writes postfilter section information.
See Also | MEIPostfilterSection | meiFilterPostfilterSet | meFilterPostfilterSectionGet | MEIMaxBiQuadSections


meiFilterPostfilterSet

Declaration
long meiFilterPostfilterSet(MPIFilter             filter,
                            long                  *sectionsCount,
                            MEIPostfilterSection  *sections);
Required Header stdmei.h
Description

PostfilterSet sets the number of postfilter sections within an MPIFilter object and configures each postfilter section as well. If numberOfSections equals zero, then sections can be NULL and the postfilter will be disabled.

The MPI calculates the post filter coefficients and takes into consideration the sample rate of the controller at that time. If you change the sample rate of the controller, you will need to recalculate the post filters. This can be done for all filters specified in Hertz by setting the filters again with the MPI. The MPI will calculate the filters using the current servo sample rate.

Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.

filter | the handle of the MPIFilter object whose postfilter sections will be configured.
*sectionsCount | the number of postfilter sections to set in the filter object.
*sections | a pointer to an array of MEIPostfilterSection data structures to be set in filter.
Sample Code

/*   Set a 4th order low-pass post-filter by using two 2nd order low-pass sections.
     Sample usage:

     returnValue =
         fourthOrderLowPass(filter, 300 /* Hz */);
*/
long filterFouthOrderLowpass(MPIFilter filter, long breakPointFrequency)
{
    MPIFilterConfig config;
    MEIPostfilterSection section[MEIMaxBiQuadSections];
    long returnValue;

    section[0].type = MEIFilterTypeLOW_PASS;
    section[0].form = MEIFilterFormINT_BIQUAD;
    section[0].data.lowPass.breakpoint = breakPointFrequency;
    section[1] = section[0]; /* copy first section */

    returnValue =
        meiFilterPostfilterSet(filter, 2, section);

    return returnValue;
}
Return Values
MPIMessageOK if PostfilterSet successfully writes postfilter information.
See Also | MEIPostfilterSection | meiFilterPostfilterGet | meFilterPostfilterSectionSet | MEIMaxBiQuadSections |


mpiFilterStatus

Declaration
long mpiFilterStatus(MPIFilter  filter,
                     MPIStatus  *status,
                     void       *external)
Required Header stdmpi.h
Description

FilterStatus writes a Filter’s (filter) status into the structure pointed to by status, and also into the implementation-specific structure pointed to by external (if external is not NULL).

The Filter’s status information in external is in addition to the Filter’s status information in status, i.e, the status configuration information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIFilterStatus{} or is NULL.
Return Values
MPIMessageOK if FilterStatus successfully writes the status of a Filter to the structure(s)
See Also


mpiFilterValidate

Declaration
long mpiFilterValidate(MPIFilter filter)
Required Header stdmpi.h
Description

FilterValidate validates the Filter object and its handle (filter).
Return Values
MPIMessageOK if Filter is a handle to a valid object.
See Also | mpiFilterCreate | mpiFilterDelete


High / Low Output Limits (MEIFilterGainPID and PIV)

.

Special Note: High / Low Output Limits (MEIFilterGainPID and PIV)

In the 19990820 release, the MEIFilterGainPID and MEIFilterGainPIV structures were expanded to support High and Low output limits for PID and PIV algorithms. The "High" output limit prevents the filter output from exceeding the "High" value. The "Low" output limit prevents the filter output from falling below the "Low" value. This feature will allow an application to have upper and lower limits which are not centered on zero volts. If the "High" and "Low" values have the same sign, then the output will be limited to either the positive or negative range bounded by "High" and "Low".

The standard Output Limit is still valid. The controller will simultaneously use the standard Output Limit and the High / Low Output Limits to bound the output. The limits, (standard or high or low) that are closest to zero will be used as the boundary for the output.

Return to MEIFilterGainPID or MEIFilterGainPIV


Flash Objects

.

Flash Objects

Introduction

A Flash object manages nonvolatile flash memory on the XMP motion controller. Because all of flash memory must be written as one contiguous piece (which takes a lot of time), and a host-resident flash memory cache is used to provide faster writing performance, and to also reduce the number of write cycles performed.

After your application creates a Flash object (using meiFlashCreate(...)), the Flash object then creates a host-resident flash memory cache, initializing it using a copy of actual flash memory [by calling meiFlashMemoryToFile(fileName=Null)]. Using the data structures defined in xmp.h and pointers to those structures (returned by the mpiControlMemory(...) method), your application can then use the meiFlashData[Get/Set](...) methods to access this memory cache. Note that the meiFlashDataSet(...) method updates the flash cache, and doesn’t update the actual flash memory. To write the flash memory cache to actual flash memory, your application must call meiFlashMemoryFromFile(fileName=Null).

Use the FlashDataGet/Set(...) methods to move data between your application and the flash cache. Use the FlashMemoryTo/FromFile(...) methods to move data between the flash cache (or file) and the actual flash memory. Typically, your application would:

  1. Create a Flash object [using meiFlashCreate(...)].

  2. Pass the MEIFlash handle to the FlashConfig[Get/Set](...) methods of the objects to be configured (which in turn call the meiFlashData[Get/Set](...) methods).

  3. Write the flash cache to actual flash memory [using meiFlashMemoryFromFile(...)].

  4. Delete the Flash object.

Methods

Create, Delete, Validate Methods
 | meiFlashCreate | Create Flash object
 | meiFlashDelete | Delete Flash object
 | meiFlashValidate | Validate Flash object

Configuration and Information Methods
 | meiFlashConfigGet | Copy flash config from cache to application memory
 | meiFlashConfigSet | Copy flash config from application memory to cache
 | meiFlashDataGet | Get count bytes of flash data memory and write them in application memory
 | meiFlashDataSet | Set count bytes of flash data memory using application memory

Memory Methods
 | meiFlashMemoryErase | Erase actual flash memory on XMP
 | meiFlashMemoryFromFileType | Write actual flash memory using the binary image contained in filename
 | meiFlashMemoryGet | Copy count bytes of flash memory to application memory
 | meiFlashMemoryModified | Determine if flash cache has been modified
 | meiFlashMemorySet | Copy count bytes of application memory to flash memory
 | meiFlashMemoryFromFile | Write actual flash memory to cache or to file
 | meiFlashMemoryToFile | Save actual flash memory to cache or to file
 | meiFlashMemoryVerify |

Relational Methods
meiFlashControl Return handle of Control that is associated with Flash

Data Types

MEIFlashConfig
MEIFlashFileMaxNameChars
MEIFlashFileMaxChars
MEIFlashFileMaxPathChars
MEIFlashFiles
MEIFlashFileType
MEIFlashMessage
MEIFlashSection


MEIFlashConfig

MEIFlashConfig

typedef struct MEIFlashConfig {
    long               wordSize;
    long               sectorSize;
    MEIFlashSection    all;
    MEIFlashSection    code;
    MEIFlashSection    codeBoot;
    MEIFlashSection    codeMain;
    MEIFlashSection    data;
    MEIFlashSection    dataExt;
    MEIFlashSection    FPGA0;
    MEIFlashSection    FPGA1;
} MEIFlashConfig;
Description

The FlashConfig structure contains the flash configuration parameters.

wordSize | The size of a flash word in bytes.
sectorSize | The size of a flash sector in bytes.
extMemSize | The size of the controller's external memory in bytes.
all | The flash section parameters for the controller's code, data, and local FPGA images.
code | The flash section parameters for the controller's boot and main code.
codeBoot | The flash section parameters for the controller's boot code.
codeMain | The flash section parameters for the controller's main code.
data | The flash section parameters for the controller's internal data memory.
dataExt | The flash section parameters for the controller'd external data memory.
FPGA0 | The flash section parameters for the local FPGA image number 0.
FPGA1 | The flash section parameters for the local FPGA image number 1.

See Also | MEIFlashSection | MEIFlashFileType | meiFlashConfigGet | meiFlashConfigSet


MEIFlashFileMaxChars

Declaration
#define MEIFlashFileMaxChars   (120)
Required Header stdmei.h
Description

The MPI has to create filenames with the full path in order to open the flash files. FlashFileMaxChars is an arbitrary size that is used by the MPI to allocate memory space for the filename. Full path filenames should not exceed 120 characters.

See Also | MEIFlashFileMaxNameChars | MEIFlashFileMaxPathChars


MEIFlashFileMaxNameChars

Declaration
#define MEIFlashFileMaxNameChars     (12)  /*8.3 format */
Required Header stdmei.h
Description

The FlashFileMaxNameChars define is used internally by the MPI when linking a series of strings to create the full path name of the flash file. If the user tries to use a file with more than 12 characters (8.3 format), then the MPI will not be able to create the correct filename and may result in problems when opening the file.

See Also | MEIFlashFileMaxChars | MEIFlashFileMaxPathChars


MEIFlashFileMaxPathChars

Declaration
#define MEIFlashFileMaxPathChars  (MEIFlashFileMaxChars -
                                   MEIFlashFileMaxNameChars)
Required Header stdmei.h
Description

FlashFileMaxPathChars is used internally by the MPI when creating full path filenames. This is the number of characters available for the path, not including the actual filename.

See Also | MEIFlashFileMaxNameChars | MEIFlashFileMaxChars


MEIFlashFiles

MEIFlashFiles

typedef struct MEIFlashFiles {
    char binFile[MEIFlashFileMaxChars];
    char FPGAFile[MEIXmpFlashMaxFPGAFiles][MEIFlashFileMaxChars];
} MEIFlashFiles;
Description

The FlashFiles structure specifies the binary files to be downloaded to the controller.

binFile | A controller firmware filename. The firmware file contains configuration data and executable code. The firmware file format is binary.
FPGAFile | An array of FPGA filenames. The FPGA file contains the binary image that is loaded into the FPGA component.

See Also | meiFlashMemoryFromFile


MEIFlashFileType

MEIFlashFileType

typedef enum {
    MEIFlashFileTypeNONE = 0,
    MEIFlashFileTypeCode,
    MEIFlashFileTypeDataInt,
    MEIFlashFileTypeDataExt,
    MEIFlashFileTypeCodeAndData,
    MEIFlashFileTypeFPGA0,
    MEIFlashFileTypeFPGA1,
    MEIFlashFileTypeALL    /* Loads Code and all FPGAs
                              (for .bin files that include
                              the FPGA images) */
} MEIFlashFileType;
Description

FlashFileType is an enumeration of file types. Each file type contains code or data for the controller's flash memory. This enumeration is used to specify what code/data is to be copied to flash memory with meiFlashMemoryFromFileType(...) or copied from flash memory with meiFlashMemoryToFile(...).

MEIFlashFileTypeCode | Controller processor code only.
MEIFlashFileTypeDataInt | Controller internal data only.
MEIFlashFileTypeDataExt | Controller external data only.
MEIFlashFileTypeCodeAndData | Controller processor code and data.
MEIFlashFileTypeFPGA0 | Local FPGA image number 0.
MEIFlashFileTypeFPGA1 | Local FPGA image number 1.
MEIFlashFileTypeALL | All code, data, and FPGA images.

See Also | meiFlashMemoryFromFileType | meiFlashMemoryToFile | meiFlashMemoryVerify


MEIFlashMessage

MEIFlashMessage

typedef enum {

    MEIFlashMessageFLASH_INVALID,
    MEIFlashMessageFLASH_READ_ERROR,
    MEIFlashMessageFLASH_WRITE_ERROR,
    MEIFlashMessagePATH,
    MEIFlashMessageNETWORK_TOPOLOGY_WARNING,
} MEIFlashMessage;
Description

FlashMessage lists the error messages returned by the MEIFlash module.

MEIFlashMessageFLASH_INVALID
 | The flash object is not valid. This message code is returned by meiFlashMemoryFromFile(…), meiFlashMemoryFromFileType(…), meiFlashMemoryToFile(…), or meiFlashMemoryVerify(…) if the flash object's memory cache has not been allocated. The flash memory cache is allocated in mpiFlashCreate(…). To prevent this problem, create flash objects with mpiFlashCreate(…) and check the return value.
MEIFlashMessageFLASH_READ_ERROR
 | The flash memory read failed. This message code is returned by meiFlashMemoryVerify(…) if the read from flash memory does not match the read from the file. This indicates the specified flash file is different from the flash memory. This message code can also be returned from meiFlashMemoryFromFile(…), since it calls meiFlashMemoryVerify(…). To correct this problem, first check that the specified file is the one you intended. If the specified file is correct, use meiFlashMemoryFromFile(…) to download the file.
MEIFlashMessageFLASH_WRITE_ERROR
 | The flash memory write failed. This message code is returned by meiFlashMemoryErase(…), meiFlashMemoryFromFile(…), or meiFlashMemoryFromFileType(…) if the flash memory write fails. This indicates a problem in the flash memory component or subsystem.
MEIFlashMessagePATH
 | The flash file path is too long. This message code is returned by meiFlashMemoryFromFile(…) if the file path is longer than MEIFlashFileMaxPathChars. To correct this problem, use a shorter path.
MEIFlashMessageNETWORK_TOPOLOGY_WARNING
 | The network topology has not been saved to flash. This message code is returned by object flash config set methods if the network topology has not been previously saved to flash. This message code serves as a warning of a potential safety problem. Saving object configurations to flash will cause those values to be sent to nodes during the next network intialization, even if the flash configurations are not compatible with the network topology. If the network topology is saved to flash, then the controller will automatically verify the topology before sending object configuration values to the nodes.

See Also | MEIFlash


MEIFlashSection

MEIFlashFiles

typedef struct MEIFlashSection {
    unsigned char   *address;
    long            size;
    long            sectorIndex;
} MEIFlashSection;
Description

The FlashSection structure contains the flash configuration parameters for a specified section.

*address | A pointer to a flash sector address.
size | Length of the flash memory in bytes.
sectorIndex | The flash sector number.

See Also | MEIFlashConfig | meiFlashConfigGet | meiFlashConfigSet


meiFlashConfigGet

Declaration
long meiFlashConfigGet(MEIFlash       flash,
                       MEIFlashConfig *config)
Required Header stdmei.h
Description

FlashConfigGet gets the flash configuration and writes it into the structure pointed to by config. The flash configuration includes data about the actual flash memory device (its type and size).

Return Values
MPIMessageOK if FlashConfigGet successfully gets the flash configuration and writes it into the structure
See Also | meiFlashConfigSet


meiFlashConfigSet

Declaration
long meiFlashConfigSet(MEIFlash       flash,
                       MEIFlashConfig *config)
Required Header stdmei.h
Description

FlashConfigSet sets (reads) the control configuration from the structure pointed to by config.

Return Values
MPIMessageOK if FlashConfigSet successfully reads the control configuration from the structure
See Also | meiFlashConfigGet


meiFlashControl

Declaration
MPIControl meiFlashControl(MEIFlash flash)
Required Header stdmei.h
Description

FlashControl returns a handle to the motion controller (Control object) that a Flash object (flash) is associated with.

Return Values
handle | to a Control object that a Flash object is associated with
MPIHandleVOID | if the Flash object is invalid
See Also


meiFlashCreate

Declaration
MEIFlash meiFlashCreate(MPIControl control)
Required Header stdmpi.h
Description

FlashCreate creates a Flash object and a host-resident copy of flash memory on motion controller control (called the flash cache). FlashCreate is the equivalent of a C++ constructor.

Return Values
handle | to a Flash object
MPIHandleVOID | if the object could not be created

See Also | meiFlashDelete | meiFlashValidate


meiFlashDelete

Declaration
long meiFlashDelete(MEIFlash flash)
Required Header stdmei.h
Description

FlashDelete deletes a Flash object and invalidates its handle (flash). FlashDelete is the equivalent of a C++ destructor.

Return Values
MPIMessageOK if FlashDelete successfully deletes a Flash object and invalidates its handle
See Also | meiFlashCreate | meiFlashValidate


meiFlashDataGet

Declaration
long meiFlashDataGet(MEIFlash flash,
                     void     *dst,
                     void     *src,
                     long     count)
Required Header stdmei.h
Description

FlashDataGet gets count bytes of flash data memory starting at address src and puts (writes) them in application memory starting at address dst. The src pointer must point into the MEIXmpData{...} structure defined in xmp.h and be based on the firmware address (MEIXmpData *) returned by mpiControlMemory(...).

Your application cannot access Flash memory directly; instead your application will access the host-resident flash memory cache maintained by flash.

meiFlashDataGet(...) reads from the flash cache and is called only by applications and utilities, while meiFlashMemoryGet(...) is a low-level method that reads directly from actual flash memory and is called primarily by other flash methods.

Return Values
MPIMessageOK if FlashDataGet successfully gets count bytes of flash data memory writes them to application memory
See Also | mpiControlMemory | meiFlashMemoryGet | meiFlashDataSet


meiFlashDataSet

Declaration
long meiFlashDataSet(MEIFlash flash,
                     void     *dst,
                     void     *src,
                     long     count)
Required Header stdmei.h
Description

FlashDataSet sets (writes) count bytes of flash data memory (starting at address dst) using application memory (starting at address src). The dst pointer must point into the MEIXmpData{...} structure defined in xmp.h and be based on the firmware address (MEIXmpData *) returned by mpiControlMemory(...).

Your application cannot access Flash memory directly; instead your application will access the host-resident flash memory cache maintained by flash.

mpiControlMemory(...) returns an external pointer that points to the MEIXmpBufferData{...} structure. You cannot use this external pointer with the FlashDataSet method to access flash data memory.

Return Values
MPIMessageOK if FlashDataSet successfully writes to the flash cache
See Also | mpiControlMemory | meiFlashDataGet


meiFlashMemoryErase

Declaration
long meiFlashMemoryErase(MEIFlash flash,
                         long     erase,
                         long     verify)
Required Header stdmei.h
Description

FlashMemoryErase erases actual flash memory, and also verifies that actual flash memory is erased.

flash | a handle to a Flash object
erase | a value, either zero or non-zero
verify | a value, either zero or non-zero
Return Values
MPIMessageOK if FlashMemoryErase successfully erases the flash memory.
See Also | meiFlashCreate


meiFlashMemoryFromFile

Declaration
long meiFlashMemoryFromFile(MEIFlash      flash,
                            MEIFlashFiles *filesIn,
                            MEIFlashFiles *filesOut);
Required Header stdmei.h
Description

FlashMemoryFromFile reads the filenames pointed to by filesIn and copies the binary images into the controller's flash memory. The array of structures pointed to by filesOut is filled in with the names of the files that were successfully copied into the controller's flash memory. After the next power cycle or mpiControlReset(…) the controller will load the flash images into the local processor and FPGA(s).

flash | a handle to a flash object
*filesIn | a pointer to an array of flash filename structures to download to the controller. See MEIFlashFiles.
*filesOut | a pointer to an array of flash filename structures that were successfully downloaded to the controller. See MEIFlashFiles.
Return Values
MPIMessageOK if FlashMemoryFromFile successfully writes to actual flash memory using the file or using flash cache
See Also | MEIFlashFiles | mpiControlReset


meiFlashMemoryFromFileType

Declaration
long meiFlashMemoryFromFileType(MEIFlash         flash,
                                const char       *fileName,
                                MEIFlashFileType fileType)
Required Header stdmei.h
Description

FlashMemoryFromFileType writes actual flash memory using the binary image contained in fileName, or using the flash memory cache.

flash | a handle to a Flash object
*filename | a string
fileType | an enumeration corresponding to the flash file types
Return Values
MPIMessageOK if FlashMemoryFromFileType successfully copies the data from the file to the flash.
See Also | meiFlashCreate | meiFlashMemoryFromFile


meiFlashMemoryGet

Declaration
long meiFlashMemoryGet(MEIFlash flash,
                       void     *dst,
                       void     *src,
                       long     count)
Required Header stdmei.h
Description

FlashMemoryGet copies count bytes of actual flash memory (flash, starting at address src) to application memory (starting at address dst).

You should calculate the src pointer by considering flash memory as a stream of bytes, because FlashMemoryGet will adjust the pointer for the actual type of flash memory.

meiFlashMemoryGet(...) is a low-level method that reads directly from actual flash memory and is called primarily by other flash methods, while meiFlashDataGet(...) reads from the flash cache and is called only by applications and utilities.

XMP Only

flash memory is of type unsigned long *.

Return Values
MPIMessageOK if FlashMemoryGet successfully copies flash memory to application memory
See Also | meiFlashMemorySet


meiFlashMemoryModified

Declaration
long meiFlashMemoryModified(MEIFlash flash,
                            long     *modified)
Required Header stdmei.h
Description

FlashMemoryModified determines if the flash memory cache has been modified. Note that unless meiFlashDataSet(...) has been called previously, the meiFlashMemoryModified(...) method will always return False, regardless of whether the cache has been modified or not modified.

If the "flash cache" | Then
has been modified | FlashMemoryModified writes True to the location pointed to by modified
has not been modified | FlashMemoryModified writes False to the location pointed to by modified
Return Values
MPIMessageOK if FlashMemoryModified successfully determines if the flash cache has been modified
See Also | meiFlashDataSet


meiFlashMemorySet

Declaration
long meiFlashMemorySet(MEIFlash flash,
                       void     *dst,
                       void     *src,
                       long     count)
Required Header stdmei.h
Description

FlashMemorySet copies application memory (starting at address src) to count bytes of flash memory (flash, starting at address dst).

You should calculate the dst pointer by considering flash memory as a stream of bytes, because FlashMemoryGet will adjust the pointer for the actual type of flash memory.
XMP Only

flash memory is of type unsigned long *.
Return Values
MPIMessageOK if FlashMemorySet successfully copies application memory to flash memory
See Also | meiFlashMemoryGet


meiFlashMemoryToFile

Declaration
long meiFlashMemoryToFile(MEIFlash          flash,
                          const char        *fileName,
                          MEIFlashFileType  fileType)
Required Header stdmei.h
Description

FlashMemoryToFile saves actual flash memory to a binary image contained in fileName, or to the flash memory cache.

Return Values
MPIMessageOK if FlashMemoryToFile successfully saves actual flash memory to file or to cache
See Also


meiFlashMemoryVerify

Declaration
long meiFlashMemoryVerify(MEIFlash           flash,
                          const char         *fileName,
                          MEIFlashFileType   fileType);
Required Header stdmei.h
Description

FlashMemoryVerify is function that verifies Flash memory against an input file. It takes a flash object, the filename of the input file, and a file type.

The fileType is used to tell the function what part of flash memory to verify (Code space, data space, both, etc… see MEIFlashFileType enum in flash.h).

NOTE: meiFlashMemoryVerify has been added back to the MPI in order to allow customers who wish to verify that the file loaded in flash is the same as the default file.

flash | a handle to a Flash object
*filename | a string
fileType | an enumeration corresponding to the flash file types

Return Values
MPIMessageOK | if FlashMemoryVerify successfully verifies the Flash memory against an input file.
MEIFlashMessageFLASH_READ_ERROR | if the input file does not match what is in flash memory.
See Also


meiFlashValidate

Declaration
long meiFlashValidate(MEIFlash flash)
Required Header stdmei.h
Description

FlashValidate validates the Flash object and its handle (flash).

Return Values
MPIMessageOK if Flash is a handle to a valid object.
See Also | meiFlashCreate | meiFlashDelete


Global Objects

.

Global Objects

Introduction

Data types that are used by more than one module are defined in the mpidef.h header file.The definitions listed in this section are available to all modules, and are defined in mpidef.h.

Data Types

MPIAction / MEIAction
MEIDataType
MPIIoSource
MPIIoType
MPIIoTrigger
MEIMaxBiQuadSections
MPIModuleId / MEIModuleId
MEINetworkPort
MEINetworkType
MPIState
MPIStatus
MEIStatusFlag
MPIStatusMask / MEIStatusMask
MPITrajectory
MPIWait

Macros

mpiStatusMaskBIT


MPIAction / MEI Action

.

MPIAction / MEIAction

MPIAction

typedef enum {
    MPIActionINVALID,

    MPIActionNONE,
    MPIActionSTOP,
    MPIActionE_STOP,
    MPIActionE_STOP_ABORT,
    MPIActionE_STOP_CMD_EQ_ACT,
    MPIActionABORT,

    MPIActionDONE,
    MPIActionSTART,
    MPIActionRESUME,
    MPIActionRESET,

} MPIAction;

Description
 | MPIActionNONE | Performs no action. Use with MPIMotorEventConfig to prevent a motor event from performing an action.
 | MPIActionSTOP | Makes a motion supervisor perform a stop. This action can be commanded with mpiMotionAction(…) or by a motor event on the controller. Please see MPIMotionDecelTime for more information about stop actions.
 | MPIActionE_STOP | Makes a motion supervisor perform an e-stop. This action can be commanded with mpiMotionAction(…) or by a motor event on the controller. Please see MPIMotionDecelTime for more information about e-stop actions.
 | MPIActionE_STOP_ABORT | Makes a motion supervisor perform an e-stop and then an abort. This action can be commanded with mpiMotionAction(…) or by a motor event on the controller. Please see MPIMotionDecelTime for more information about e-stop actions.
 | MPIActionE_STOP_CMD_EQ_ACT | The command position is set equal to the previous sample's actual position. After the E_STOP time expires, the AmpEnable is disabled. The settling parameters are supported for this action, when settleOnEstopCmdEqAct in the MPIAxisConfig structure is enabled.
 | MPIActionABORT | Makes a motion supervisor perform an abort. This action can be commanded with mpiMotionAction(…) or by a motor event on the controller.
 | MPIActionDONE | is currently not supported and is reserved for future use.
 | MPIActionSTART | Intended to force a motion supervisor to start when it is waiting for some event (a delay or hold) before starting. This action is currently not supported.
 | MPIActionRESUME | Makes a motion supervisor to resume motion after a stop action has occurred. A motion supervisor can only resume a motion after a stop event, not an e-stop event. This action can be commanded with mpiMotionAction(…).
 | MPIActionRESET | Makes a motion supervisor return to an idle state after an error has occurred or after a stop, e-stop, abort, or e-stop/abort action has occurred. While abort actions and certain errors cause all associated motors to turn off their amp-enable lines, this action does not change the state of any amp-enable lines. One will have to call the method mpiMotorAmpEnableSet(…) to re-enable the amplifiers. This action can be commanded with mpiMotionAction(…).
Remarks
MPIAction enumerations are used to perform some sort of action on an MPI object. Currently, only MPIMotion and MPIMotor use the MPIAction enumerations. One can command an MPIMotion object to perform some action with the mpiMotionAction(…) method, while one can get and set the types of actions that will be performed when certain motor events occur with the MPIMotorEventConfig structure with the mpiMotorEventConfigGet(…) and mpiMotorEventConfigSet(…) methods.

An MPIAction can be generated from the host or the firmware. Below is a table where MPIActions originate (start):

MPIAction | Originating from Host | Originating from XMP Firmware
Start Resume Reset Stop | mpiMotionAction(…) (currently unsupported) mpiMotionAction(…) mpiMotionAction(…) mpiMotionAction(…) | NEVER NEVER NEVER Event
E_Stop ABORT | mpiMotionAction(…) mpiMotionAction(…) | Event Event
DONE | NEVER | NEVER

MEIAction

typedef enum {
    MEIActionMAP = MPIActionLAST,

} MEIAction;

Description
 | MPIActionMAP | MotionAction will write the axis mapping relationship of the motion supervisor to the controller. This mapping is written automatically when mpiMotionStart() is called.

See Also | mpiMotionAction | MPIMotionDecelTime | MPIMotorEventConfig mpiMotorEventConfigGet | mpiMotorEventConfigSet | MPIEvent | MPIAxisConfig


MEIDataType

.

MEIDataType

typedef enum {
    MEIDataTypeINVALID = 0, /* this should stay zero - static arrays init
                            to zero by default */
    MEIDataTypeCHAR,
    MEIDataTypeSHORT,
    MEIDataTypeUSHORT,
    MEIDataTypeLONG,
    MEIDataTypeULONG,
    MEIDataTypeFLOAT,
    MEIDataTypeDOUBLE,
} MEIDataType;

static MEIDataType  MEIFilterGainTypePID[MPIFilterCoeffCOUNT_MAX] =
{
    MEIDataTypeFLOAT, /* Kp               */
    MEIDataTypeFLOAT, /* Ki               */
    MEIDataTypeFLOAT, /* Kd               */

    MEIDataTypeFLOAT, /* Kpff             */
    MEIDataTypeFLOAT, /* Kvff             */
    MEIDataTypeFLOAT, /* Kaff             */
    MEIDataTypeFLOAT, /* Kfff             */

    MEIDataTypeFLOAT, /* MovingIMax       */
    MEIDataTypeFLOAT, /* RestIMax         */

    MEIDataTypeLONG,  /* DRate            */

    MEIDataTypeFLOAT, /* OutputLimit      */
    MEIDataTypeFLOAT, /* OutputLimitHigh  */
    MEIDataTypeFLOAT, /* OutputLimitLow   */
    MEIDataTypeFLOAT, /* OutputOffset     */
    MEIDataTypeFLOAT, /* Ka0              */
    MEIDataTypeFLOAT, /* Ka1              */
    MEIDataTypeFLOAT, /* Ka2              */
};
Description

DataType is an enumeration of data types for the filter coefficients.

MEIDataTypeCHAR | character filter data type
MEIDataTypeSHORT | short integer filter data type
MEIDataTypeUSHORT | unsigned short integer filter data type
MEIDataTypeLONG | long integer filter data type
MEIDataTypeULONG | unsigned long filter data type
MEIDataTypeFLOAT | floating point filter data type
MEIDataTypeDOUBLE | double precision floating point filter data type
See Also


MPIIoSource

MPIIoSource

typedef union {
    MPIHandle	motor;	/* MOTOR */
    long	index;	/* USER */
} MPIIoSource;

Description
 | motor | Handle to a motor object that is the source for the IO.
 | index | Value of the index for a user input. User IO's are no longer supported by the xmp (user IO's are handled through the motor object).
See Also


MPIIoTrigger

MPIIoTrigger

typedef struct MPIIoTrigger {
    MPIIoType        type;
    MPIIoSource      source;
    unsigned long    mask;
    unsigned long    pattern;
} MPIIoTrigger;

Description
 | type | see MPIIoType.
 | source | see MPIIoSource.
 | mask | Value that specifies the mask to be applied to the IO.
 | pattern | Value that specifies the pattern to be compared to the masked IO.
See Also


MPIIoType

MPIIoType

typedef enum {
    MPIIoTypeINVALID,

    MPIIoTypeMOTOR,
    MPIIoTypeUSER,

} MPIIoType;

Description
 | MPIIoTypeMotor | Value specifies the IO type as motor (the IO source is a motor object).
 | MPIIoTypeUSER | Value specifies the IO type as user (User IO types are currently not supported. User IO is available through the motor objects).
See Also


MEIMaxBiQuadSections

MEIMaxBiQuadSections

#define MEIMaxBiQuadSections	(6)
Description

MaxBiQuadSections defines the maximum number of biquad sections in an MPIFilter's postfilter. Postfilters are used to digitally filter the output of a control loop. One common use for postfilters is the compensation of system resonances.

NOTE: The PIV algorithm uses the last biquad section internally and so the user can only use (MEIMaxBiQuadSections-1) sections if the PIV algorithm is the current control algorithm.

See Also | meiFilterPostfilterGet | meiFilterPostfilterSet | meiFilterPostfilterSectionGet | meiFilterPostfilterSectionSet


MPIModuleId / MEIModuleId

MPIModuleId

typedef enum {
    MPIModuleIdINVALID,

    MPIModuleIdMESSAGE,
    MPIModuleIdADC,
    MPIModuleIdAXIS,
    MPIModuleIdCAPTURE,
    MPIModuleIdCOMMAND,
    MPIModuleIdCOMPARE,
    MPIModuleIdCONTROL,

    MPIModuleIdEVENT,
    MPIModuleIdEVENTMGR,
    MPIModuleIdFILTER,

    MPIModuleIdMOTION,
    MPIModuleIdMOTOR,

    MPIModuleIdNOTIFY,
    MPIModuleIdPATH,
    MPIModuleIdRECORDER,
    MPIModuleIdSEQUENCE,

    MPIModuleIdEXTERNAL = 0x80,

    MPIModuleIdMAX = 0xFF
} MPIModuleId;
Description

ModuleId is used to identify what module a particular MPIHandle belongs to. If the handle is an external memory pointer instead of an MPI object handle, MPIModuleIdEXTERNAL will be returned by MPI methods.

MEIModuleId

typedef enum {
    MEIModuleIdPLATFORM,

    MEIModuleIdCAN,

    MEIModuleIdCLIENT,
    MEIModuleIdELEMENT,
    MEIModuleIdFLASH,
    MEIModuleIdLIST,
    MEIModuleIdMAP,
    MEIModuleIdPACKET,
    MEIModuleIdSERVER,

    MEIModuleIdSYNQNET,
    MEIModuleIdSQNODE,
    MEIModuleIdDRIVE_MAP,

    MEIModuleIdBLOCK = MEIModuleIdSQNODE,

}MEIModuleId;
Description

ModuleId is used to identify what module a particular MPIHandle belongs to. If the handle is an external memory pointer instead of an MPI object handle, MPIModuleIdEXTERNAL will be returned by MPI methods.

See Also | mpiObjectModuleId | mpiObjectValidate


MEINetworkPort

MEINetworkPort

typedef enum MEINetworkPort {
    MEINetworkPortIN0,
    MEINetworkPortOUT0,
} MEINetworkPort;
Description

MEINetworkPort enumerations are used to specify a network port. Network ports represent the physical network connections into which the cables are plugged. These ports are commonly found in pairs on SynqNet controllers and SynqNet nodes. OUT ports from the controller or an upstream node connect to the IN port of a downstream node. When the OUT port of the last downstream node is connected back to the IN port of the controller, the network is considered to be configured as a RING network type.

MEINetworkPortIN0 | "IN" Network port 0
MEINetworkPortOUT0 | "OUT" Network port 0

See Also | MEINetworkType


MEINetworkType

MEINetworkType

typedef enum MEINetworkType {
    MEINetworkTypeINVALID = -1,   /* no nodes found */
    MEINetworkTypeSTRING,
    MEINetworkTypeSTRING_TERMINATED,
    MEINetworkTypeRING,
} MEINetworkType;
Description

The NetworkType enumeration lists all network topologies supported by this MPI release.

NOTE: Due to the un-terminated nature of the MEINetworkTypeSTRING network type discovering a topology of this type requires a timeout period to detect the end of the string. Thus discovering a string topology will take a longer time than other networks types.

MEINetworkTypeINVALID | No nodes were found on the network
MEINetworkTypeSTRING | The network topology type is a string of nodes
MEINetworkTypeSTRING_TERMINATED | The network topology type is a string of nodes. The last node on the string is terminated.
MEINetworkTypeRING | The network topology type is a ring of nodes.

See Also | MEISynqNetInfo | meiSynqNetInfo


MPIState

MPIState

typedef enum {
    MPIStateIDLE,
    MPIStateMOVING,
    MPIStateSTOPPING,
    MPIStateSTOPPED,
    MPIStateSTOPPING_ERROR,
    MPIStateERROR,
} MPIState;
Description

State is an MPI enum that is used to describe the current state of the controller's motion state machine. MPIState resides in the MPIStatus structure. Currently MPIState is only used with motion module.

MPIStateIDLE | The state of motion is idle and waiting to resume motion.
MPIStateMOVING | The state of the motion is moving.
MPIStateSTOPPING | The state of the motion is stopping. This occurs from a Stop event, but not an E_Stop, E_Stop Abort, or Abort events. The stop command could have come from the firmware or MPI.
MPIStateSTOPPED | The move has stopped due to a STOP command. It requires a MotionReset to go back to IDLE OR a MotionResume to resume stopped motion. MotionStart can also be called at any time to start a new move.
MPIStateSTOPPING_ERROR | The state of the motion is performing an emergency stop and/or abort on all axes. The move is stopping due to an error (ESTOP, ABORT, etc…).
MPIStateERROR | The state of the motion is in error. The error state is generated from an E_Stop or Abort event. It requires a MotionReset to get back to IDLE before loading another move.

See Also | MPIStatus


MPIStatus

MPIStatus

typedef struct MPIStatus {
    MPIState        state;
    MPIAction       action;
    MPIEventMask    eventMask;

    long    settled;
    long    atTarget;

    MPIStatusMask    statusMask;
} MPIStatus;

Description
 | state | Value that indicates the state of an xmp controller's motion supervisor.
 | action | Value that indicates the action to perform for a motion supervisor.
 | eventMask | Array that defines the event mask bits. The array is defined as typedef MPIEventMaskELEMENT_TYPE MPIEventMask[MPIEventMaskELEMENTS].
 | settled | Value that indicates if an axis associated with a motion supervisor has settled (is in fine position).
 | atTarget | Value that indicates if an axis associated with a motion supervisor has completed its command trajectory (i.e. the command position has reached the targeted end point of the move).

See Also | MPIState | MPIStatusMask


MEIStatusFlag

MEIStatusFlag

typedef enum {
    MEIStatusFlagBROKEN_WIRE,               /* 1 */
    MEIStatusFlagILLEGAL_STATE,             /* 2 */
    MEIStatusFlagABS_ENCODER_FAULT,         /* 3 */
    MEIStatusFlagABS_ENCODER_TIMEOUT,       /* 4 */
    MEIStatusFlagBROKEN_WIRE_SECONDARY,     /* 5 */
    MEIStatusFlagILLEGAL_STATE_SECONDARY,   /* 6 */
} MEIStatusFlag;
Description

StatusFlag is an enumeration of status flags (bits) for an object. The status flags represent the present condition for an object.

Please see MEIStatusMask data type for more information.

See Also | MEIStatusMask | MPIStatusMask


MPIStatusMask / MEIStatusMask

MPIStatusMask

typedef enum {
    MPIStatusMaskNONE	= 0x0,

    MPIStatusMaskMOTOR	= MPIStatusMaskNONE, /* 0x00000001 */

    MPIStatusMaskALL	= mpiStatusMaskBIT(MPIStatusFlagLAST) - 1
                           /* 0x00000001 */
} MPIStatusMask;

Description
 | MPIStatusMaskMOTOR | Value specifies the motor's status mask.
 | MPIStatusMaskALL | Value specifies the status mask that encompasses all the possible status flags.

See Also | MPIStatus

MEIStatusMask

typedef enum {
    MEIStatusMaskBROKEN_WIRE             = mpiStatusMaskBIT(MEIStatusFlagBROKEN_WIRE),             /* 0x00000002 */
    MEIStatusMaskILLEGAL_STATE           = mpiStatusMaskBIT(MEIStatusFlagILLEGAL_STATE),           /* 0x00000004 */
    MEIStatusMaskABS_ENCODER_FAULT       = mpiStatusMaskBIT(MEIStatusFlagABS_ENCODER_FAULT),       /* 0x00000008 */
    MEIStatusMaskABS_ENCODER_TIMEOUT     = mpiStatusMaskBIT(MEIStatusFlagABS_ENCODER_TIMEOUT),     /* 0x00000010 */
    MEIStatusMaskBROKEN_WIRE_SECONDARY   = mpiStatusMaskBIT(MEIStatusFlagBROKEN_WIRE_SECONDARY),   /* 0x00000020 */
    MEIStatusMaskILLEGAL_STATE_SECONDARY = mpiStatusMaskBIT(MEIStatusFlagILLEGAL_STATE_SECONDARY), /* 0x00000040 */

    MEIStatusMaskMOTOR =   /* 0x0000001E */
                             (MEIStatusMaskBROKEN_WIRE	|
                              MEIStatusMaskILLEGAL_STATE |
                              MEIStatusMaskABS_ENCODER_FAULT |
                              MEIStatusMaskABS_ENCODER_TIMEOUT),

    MEIStatusMaskALL   =   /* 0x0000001E */
         (mpiStatusMaskBIT(MEIStatusFlagLAST) - 1) & ~MPIStatusMaskALL
} MEIStatusMask;
Description

StatusMask is an enumeration of bit masks for the MEIStatusFlags. The status masks represent the present condition for an object.

MEIStatusMaskBROKEN_WIRE | Broken wire on the primary encoder input signals. Occurs when any of the differential encoder input channels (A+ and A-, B+ and B-, or I+ and I-), have the same logic state. This mask indicates either a floating or shorted encoder input signal.
MEIStatusMaskILLEGAL_STATE | Illegal encoder logic state on the primary encoder input signals. Occurs when the A and B encoder input channels transition simultaneously. This mask indicates either faulty encoder signal logic, encoder frequencies that are too high, or noisy encoder signals.
MEIStatusMaskABS_ENCODER_FAULT | Absolute encoder initialization failure. Occurs when the hardware fails to read the absolute position information from an encoder.
MEIStatusMaskABS_ENCODER_TIMEOUT | Absolute encoder response timeout. Occurs when the encoder fails to respond to a request for absolute position data.
MEIStatusMaskBROKEN_WIRE_SECONDARY | Broken wire on the secondary encoder input signals. Occurs when any of the differential encoder input channels (A+ and A-, B+ and B-, or I+ and I-), have the same logic state. This mask indicates either a floating or shorted encoder input signal.
MEIStatusMaskILLEGAL_STATE_SECONDARY | Illegal encoder logic state on the secondary encoder inputs. Occurs when the A and B encoder input channels transition simultaneously. This flag indicates either faulty encoder signal logic, encoder frequencies that are too high, or noisy encoder signals.
MEIStatusMaskMOTOR | Bit mask containing all of the motor specific MEIStatusFlags set.
MEIStatusMaskALL | Bit mask containing all of the MEIStatusFlags set.

See Also | MPIStatus | MEIStatusFlag | MPIStatusFlag | MPIStatusMask


MPITrajectory

MPITrajectory

typedef struct MPITrajectory {
    double    velocity;
    double    acceleration;
    double    deceleration;
    double    jerkPercent;
    double    accelerationJerk;
    double    decelerationJerk;
} MPITrajectory;
Description

The Trajectory structure contains the motion profile parameters for simple point to point type motion.

NOTE: Not all firmware binaries support S_CURVE_JERK and VELOCITY_JERK motion types due to code space limitations. mpiMotionStart(…) and mpiMotionModify(…) will return MPIMotionMessagePROFILE_NOT_SUPPORTED if the controller does not support the requested move type.

velocity | Rate of change of position. Specifies the constant slew rate for S_CURVE, TRAPEZOIDAL, S_CURVE_JERK, VELOCITY, and VELOCITY_JERK motion types. Units are counts per second.
acceleration | Rate of change of velocity. Specifies the initial ramp to reach constant velocity for TRAPEZOIDAL and VELOCITY motion types. Also, specifies the ramp from the initial jerk to the next jerk before constant velocity for S_CURVE, S_CURVE_JERK and VELOCITY_JERK motion types. Units are counts per second * second.
deceleration | Rate of change of velocity. Specifies the final ramp to reach zero velocity for TRAPEZOIDAL and VELOCITY motion types. Also, specifies the ramp from the jerk after constant velocity to the final jerk for S_CURVE and S_CURVE_JERK motion types. Units are counts per second * second.
jerkPercent | Portion of acceleration and deceleration ramp to perform jerk profile for S_CURVE, VELOCITY, S_CURVE_JERK, and VELOCITY_JERK motion types. Units are in percent.
accelerationJerk | Rate of change of acceleration. Specifies the initial jerk rates to reach constant velocity for S_CURVE_JERK and VELOCITY_JERK motion types. Units are counts per second * second * second.
decelerationJerk | Rate of change of deceleration. Specifies the final jerk rate to reach zero velocity for S_CURVE_JERK motion types. Units are counts per second * second * second.

See Also | MPIMotionType | mpiMotionTrajectory | mpiMotionStart | mpiMotionModify


MPIWait

MPIWait

typedef enum {
    MPIWaitFOREVER = -1,
    MPIWaitPOLL = 0,
    MPIWaitMSEC
} MPIWait;
Description

Wait enumerations define basic wait times for certain MPI methods.

MPIWaitFOREVER | Makes MPI methods wait forever for an event to occur before returning.
MPIWaitPOLL | Makes MPI methods see if a certain event has occurred. If an event has not occurred, then the MPI method will generally return immediately returning the value MPIMessageTIMEOUT.
MPIWaitMSEC | Defines a period of one millisecond. If used alone, this will make MPI methods wait for one millisecond for an event occurs before returning. One can pass an an agument a multiple of MPIWaitMSEC to make MPI methods wait longer periods of time. For example, the following statement will make mpiPlatformKey wait 5 milliseconds for a user keystroke: mpiPlatformKey( 5 * MPIWaitMSEC ); If an event does not occur within the specified time, MPI methods will generally return the value MPIMessageTIMEOUT.

WARNING
 | The MPI depends on the ability of the operating system it is running on to be able to activate threads or put threads to sleep for a specified period of time in order for these times to be accurate. Microsoft Windows platforms are not real-time operating systems and are known to be unable to activate threads any quicker than 10 milliseconds. If you encounter a timing problem, it is likely an operating system timing issue.

See Also | mpiControlInterruptWait | mpiNotifyEventWait | mpiObjectTimeoutGet mpiObjectTimeoutSet | meiPlatformKey


mpiStatusMaskBIT

Declaration
#define	  mpiStatusMaskBIT(flag)	(0x1 << (flag))
Required Header stdmpi.h
Description

StatusMaskBIT converts the status flag into the status mask.

See Also | MPIStatusMask


Message Objects

.

Message Objects

Introduction

The Message module manages text strings associated with the error/warning code return values that can be returned from MPI methods. Each method return value has a unique value which can be decoded using the Message methods and macros.

For example, a return value of MEISynqNetMessagePLL_ERROR has a defined value of 0x192E. Passing this value to the mpiMessage(…) function returns the following text string:

"SynqNet: node PLL unable to lock with drive"

If MEISynqNetMessagePLL_ERROR was the last return value received from an MPI method, the string returned from mpiMessage(…) would also contain extended message information. The extended message information provides greater insight into the problem that has just occurred. In this case, the extended message information would indicate which node had the PLL locking problem:

"SynqNet: node PLL unable to lock with drive : Node 3"

Notice that the extended message information is delimited from the more generic message by a colon surrounded by spaces " : "

Extended message information may not always be returned. Extended information is only available for the very last return value from the MPI -- if a second (non-zero) return value has been returned between the time when the first return value was returned and the call to mpiMessage(…), then no extended information would be returned. In addition, not all messages return extended error information.

Methods

Configuration and Information Methods
 | mpiMessage |
 | mpiMessageFunction | Associate message text with a function

Data Types

MPIMessageFunction

Macros

mpiMessageID
mpiMessageMODULE
mpiMessageNUMBER


MPIMessageFunction

MPIMessageFunction

typedef const char *(*MPIMessageFunction)(long);
Description

MessageFunction is the type definition for the callback function used by mpiMessage(…). A default callback function is provided internally to all MPI/MEI modules, but an application can also be written to override it and provide a custom message function instead.

See Also | mpiMessage | mpiMessageFunction


mpiMessageFunction

Declaration
long mpiMessageFunction(MPIModuleId        moduleId,
                        MPIMessageFunction function)
Required Header stdmpi.h
Description

MessageFunction registers function as the function to be called by mpiMessage(...) (in order to obtain the text for a message associated with module moduleId).

MessageFunction is typically called internally by object create methods. Applications generally do not need to call MessageFunction directly.

Return Values
MPIMessageOK if MessageFunction successfully registers function as the function to be called by mpiMessage(...)
See Also | mpiMessage


mpiMessageID

Declaration

#define mpiMessageID(module number) \
((long)((((module) & MPIModuleIdMAX) << 8) | \ ((number) & 0xFF)))
Required Header stdmpi.h
Description

MessageID converts the message module value and number to a unique message identification value.

See Also | mpiMessage


mpiMessageMODULE

Declaration

#define mpiMessageMODULE(messageId) \
(((messageId) & (MPIModuleIdMAX << 16)) >> 16)
Required Header stdmpi.h
Description

MessageMODULE converts the message identification value to the message module value.

See Also | mpiMessage


mpiMessage

Declaration
const char *mpiMessage(long  messageId,
                       char  *messageText)
Required Header stdmpi.h
Description

mpiMessage returns the text message associated with messageId and copies the text to messageText if messageText is not NULL.

If "messageText" is | Then
NULL | Message returns a pointer to message text resident in the library
not NULL | Message returns the pointer messageText, which must point to a buffer large enough to hold the message text (that will be copied into it)

Return Values
NULL | if messageId is invalid
Pointer to an empty string (" ") | if the messge utility is not enabled or the message function pointer associated with messageId is NULL.
Pointer to a non-zero-length string | if the mpiMessage successsfully retrieves the message associated with messageId.

See Also | mpiMessageFunction


mpiMessageNUMBER

Declaration

#define mpiMessageNUMBER(messageId) ((messageId) & 0xFF)
Required Header stdmpi.h
Description

MessageNUMBER converts the message identification value to the message number.

See Also | mpiMessage


Motion Objects

.

Motion Objects

Introduction

A Motion object manages a single axis or group of axes. Its primary function is to provide an interface to command movement on a coordinate system. It also provides status information about all the axes under its control, so motion can be either stopped or resumed in a controlled manner, especially in the event of error recovery. The Motion object is really a host-based object, with a corresponding Motion Supervisor object in the controller. The Motion Supervisor handles the real-time issues associated with axis data and status synchronization.

Some careful consideration should be given to Motion object (Motion Supervisor) to axis mapping. While it's possible to have multiple Motion objects share the same axes, only one Motion Supervisor can command motion to an axis at a time. Motion object to axis maps can be changed dynamically at any time, but Motion Supervisor to axis maps should NOT be changed when the axes are moving.

To learn more about using MPI Motion Attributes and MEI Motion Attributes, click here.

| Error Messages |

Methods

Create, Delete, Validate Methods
 | mpiMotionCreate | Create Motion object
 | mpiMotionDelete | Delete Motion object
 | mpiMotionValidate | Validate Motion object

Configuration and Information Methods
 | mpiMotionConfigGet | Get Motion configuration
 | mpiMotionConfigSet | Set Motion configuration
 | mpiMotionFlashConfigGet | Get Motion flash config
 | mpiMotionFlashConfigSet | Set Motion flash config
 | meiMotionFrameBufferLoad |
 | meiMotionFrameBufferStatus | Get a Motion object (motion) frame buffer status.
 | meiMotionLogClose | Frees memory buffer for motion logging
 | meiMotionLogOpen | Allocates a memory buffer for motion logging.
 | meiMotionLogPrint | Writes motion log buffer data
 | mpiMotionParamsGet | Get Motion parameters
 | mpiMotionParamsSet | Set Motion parameters
 | meiMotionParamsValidate | Validate Motion parameters
 | mpiMotionPositionGet | Get position parameters of all axes associated with Motion
 | mpiMotionPositionSet | Set position parameters of all axes associated with Motion
 | mpiMotionStatus | Get Motion status
 | mpiMotionTrajectory | Get trajectories for all Axis associated with Motion

Event Methods
 | mpiMotionEventNotifyGet | Get event mask
 | mpiMotionEventNotifySet | Set event mask
 | mpiMotionEventReset | Reset events specified in event mask

Action Methods
 | mpiMotionAction | Perform an action on a Motion
 | meiMotionActionFunction |
 | mpiMotionModify | Modify parameters of Motion while it is executing
 | mpiMotionStart | Start Motion (idle state > moving state)

Memory Methods
 | mpiMotionMemory | Set address to be used to access Motion memory
 | mpiMotionMemoryGet | Get bytes of Motion memory and place it into application memory
 | mpiMotionMemorySet | Put (set) bytes of application memory into Motion memory

Relational Methods
 | mpiMotionControl | Return handle of Control object associated with Motion
 | mpiMotionNumber | Get index of Motion
 | mpiMotionAxis | Return handle of axis by index number
 | mpiMotionAxisAppend | Append axis to list
 | mpiMotionAxisCount | Return number of axes in list
 | mpiMotionAxisFirst | Return handle to first axis in list
 | mpiMotionAxisIndex | Return index value of an axis in list
 | mpiMotionAxisInsert | Insert axis into list associated with Motion
 | mpiMotionAxisLast | Return handle to last axis in list
 | mpiMotionAxisListGet | Get list of axes associated with Motion
 | mpiMotionAxisListSet | Create a list of axes associated with Motion
 | mpiMotionAxisNext | Get handle to next axis in list
 | mpiMotionAxisPrevious | Get handle to previous axis in list
 | mpiMotionAxisRemove | Remove handle to axis in list

Data Types

*MEIMotionActionFunction
MPIMotionAttr / MEIMotionAttr
MEIMotionAttrHold
MEIMotionAttrHoldSource
MEIMotionAttrHoldType
MPIMotionAttrMask / MEIMotionAttrMask
MEIMotionAttrOutput
MEIMotionAttrOutputType
MPIMotionAttributes / MEIMotionAttributes
MPIMotionBESSEL
MPIMotionBSPLINE
MPIMotionConfig / MEIMotionConfig
MPIMotionDecelTime
MEIMotionFrame
MEIMotionFrameBufferStatus
MPIMotionMessage / MEIMotionMessage
MPIMotionParams / MEIMotionParams
MPIMotionPoint
MPIMotionPT
MPIMotionPTF
MPIMotionPVT
MPIMotionPVTF
MPIMotionSCurve
MPIMotionSCurveJerk
MPIMotionSPLINE
MEIMotionTrace
MPIMotionTrapezoidal
MPIMotionType / MEIMotionType
MPIMotionVelocity

Macros

mpiMotionATTR
mpiMotionAttrMaskBIT
mpiMotionTYPE


MEIMotionActionFunction

MEIMotionActionFunction

typedef long   /* Callback prototype */
    (*MEIMotionActionFunction)(MPIMotion        motion,
                               MPIMotionType    type,
                               MEIXmpAction     xmpAction);

Description
 | motion
 | type
 | xmpAction
See Also


MPIMotionAttr / MEIMotionAttr

MPIMotionAttr
typedef enum {
    MPIMotionAttrINVALID,

    MPIMotionAttrAPPEND,
    MPIMotionAttrAUTO_START,
    MPIMotionAttrDELAY,
    MPIMotionAttrID,
    MPIMotionAttrELEMENT_ID,
    MPIMotionAttrRELATIVE,
    MPIMotionAttrSYNC_END,
    MPIMotionAttrSYNC_START,
    MPIMotionAttrCOUNT,
} MPIMotionAttr;
Description

The motion attributes are used to generate the motion attribute masks to enable features with mpiMotionStart(…) and mpiMotionModify(…). Please see MPIMotionAttrMask data type for more information.

MEIMotionAttr

typedef enum {

    MEIMotionAttrEVENT,
    MEIMotionAttrFINAL_VEL,
    MEIMotionAttrNO_REVERSAL,
    MEIMotionAttrHOLD,
    MEIMotionAttrHOLD_LESS,
    MEIMotionAttrHOLD_GREATER,
    MEIMotionAttrOUTPUT,

    MEIMotionAttrCOUNT,
} MEIMotionAttr;
Description

The motion attributes are used to generate the motion attribute masks to enable features with mpiMotionStart(…) and mpiMotionModify(…). Please see MPIMotionAttrMask for more information.

MPIMotionAttrHOLD_LESS | Motion attribute bit for less than or equal hold logic.
MPIMotionAttrHOLD_GREATER | Motion attribute bit for greater than or equal hold logic.

See Also | MPIMotionAttrMask | mpiMotionStart | mpiMotionModify


MEIMotionAttrHold

MEIMotionAttrHold

typedef	struct MEIMotionAttrHold {
    MEIMotionAttrHoldType     type;
    MEIMotionAttrHoldSource   source;
    float                     timeout;
} MEIMotionAttrHold;

Description
 | type | This value specifies the motion hold type. Please see MEIMotionAttrHoldType for more information.
 | source | This value specifies the motion hold conditions. Please see MEIMotionAttrHoldSource for more information.
 | timeout | This value specifies the motion hold expiration time (samples). When the time exceeds the timeout value or the hold conditions are met, the motion profile will execute.

See Also | MEIMotionAttrHoldType | MEIMotionAttrHoldSource


MEIMotionAttrHoldSource

MEIMotionAttrHoldSource

typedef union {
    long	gate;
    struct {
        long    *input;
        long    mask;
        long    pattern;
    } input;
    struct {
        long    number;
        long    mask;
        long    pattern;
    } motor;
    struct {
        long    number;
        long    position;
    } axis;
    struct {
        long    *address;
        long    mask;
        long    pattern;
    } user;
} MEIMotionAttrHoldSource;

Description
 | gate | This value specifies the control gate number when MEIMotionAttrHoldTypeGATE is used. Valid values are between 0 and 31. See meiControlGateGet/Set(…) for more information.
 | input.input | This value specifies the input address when MEIMotionAttrHoldTypeINPUT is used.
 | input.mask | This value specifies the AND mask when MEIMotionAttrHoldTypeINPUT is used.
 | input.pattern | This value specifies the comparison pattern when MEIMotionAttrHoldTypeINPUT is used. The value at input.input is bit-wise ANDed with the input.mask and compared to the input.pattern.
 | motor.number | This value specifies the motor number when MEIMotionAttrHoldTypeMOTOR is used.
 | motor.mask | This value specifies the AND mask when MEIMotionAttrHoldTypeMOTOR is used.
 | motor.pattern | This value specifies the comparison pattern when MEIMotionAttrHoldTypeMOTOR is used. The motor input word is bit-wise ANDed with the motor.mask and compared to the motor.pattern.
 | axis.number | An axis's number (0, 1, 2, etc.). Must be specified when the AXIS_POSITION_COMMAND or AXIS_POSITION_ACTUAL motion hold types are used.
 | axis.position | A position comparison value. Must be specified when the AXIS_POSITION_COMMAND or AXIS_POSITION_ACTUAL motion hold types are used.
 | user.address | A controller memory address. Must be specified when the USER_ADDRESS motion hold type is used.
 | user.mask | A bitwise AND mask for the user specified controller memory address. Must be specified when the USER_ADDRESS motion hold type is used.
 | user.pattern | A comparison value for the masked user.address. When the pattern matches the masked value, the motion will be triggered. Must be specified when the USER_ADDRESS motion hold type is used.

See Also | MEIMotionAttrHoldType | meiControlGateGet | meiControlGateSet


MEIMotionAttrHoldType

MEIMotionAttrHoldType

typedef enum {
    MEIMotionAttrHoldTypeINVALID,
    MEIMotionAttrHoldTypeNONE,
    MEIMotionAttrHoldTypeGATE,
    MEIMotionAttrHoldTypeINPUT,
    MEIMotionAttrHoldTypeMOTOR,
    MEIMotionAttrHoldTypeAXIS_POSITION_ACTUAL,
    MEIMotionAttrHoldTypeAXIS_POSITION_COMMAND,
    MEIMotionAttrHoldTypeUSER_ADDRESS,
} MEIMotionAttrHoldType;

Description
 | MEIMotionAttrHoldTypeNONE | This type disables the hold trigger condition.
 | MEIMotionAttrHoldTypeGATE | This type configures a control gate for the hold trigger condition. See meiControlGateGet/Set(…) for more information.
 | MEIMotionAttrHoldTypeINPUT | This type configures a memory address for the hold trigger condition.
 | MEIMotionAttrHoldTypeMOTOR | This type configures a motor's input bit(s) for the hold trigger condition.
 | MEIMotionAttrHoldTypeAXIS_POSITION_ACTUAL | Motion hold input trigger from an axis's actual position.
 | MEIMotionAttrHoldTypeAXIS_POSITION_COMMAND | Motion hold input trigger from an axis's command position.
 | MEIMotionAttrHoldTypeUSER_ADDRESS | Motion hold input trigger from a user specifiable controller memory address.
Remarks
 | These types specify the motion profile trigger condition. The hold trigger value is specified with the MEIMotionAttrHoldSource data type.

See Also | MEIMotionAttrHoldSource | MEIMotionAttrHold


MPIMotionAttrMask / MEIMotionAttrMask

MPIMotionAttrMask

typedef	enum {
    MPIMotionAttrMaskAPPEND,
    MPIMotionAttrMaskAUTO_START,
    MPIMotionAttrMaskDELAY,
    MPIMotionAttrMaskID,
    MPIMotionAttrMaskELEMENT_ID,
    MPIMotionAttrMaskRELATIVE,
    MPIMotionAttrMaskSYNC_END,
    MPIMotionAttrMaskSYNC_START,
    MPIMotionAttrMaskALL,
} MPIMotionAttrMask;

Description
 | MPIMotionAttrMaskAPPEND | This mask enables the motion profile to be added to the end of a previous motion profile, in the controller's memory buffer. The APPENDed profile will begin execution after the previous profile has completed and the settling criteria has been met. The APPEND mask can be used with mpiMotionStart(…) or mpiMotionModify(…).
 | MPIMotionAttrMaskAUTO_START | This mask converts a mpiMotionModify(…) call to a mpiMotionStart(…) if the modify occurs after the previous motion profile has completed. If the previous profile had completed, then mpiMotionModify(…) will return an error code, MPIMotionMessageAUTO_START.
 | MPIMotionAttrMaskDELAY | This mask enables a time delay (seconds) before the motion profile begins. Please see MPIMotionAttributes for more information. This mask can be used with mpiMotionStart(…).
 | MPIMotionAttrMaskID | This mask enables an identification tag to be stored in the motion profile. Please see MPIMotionAttributes for more information. This mask can be used with mpiMotionStart(…) and mpiMotionModify(…).
 | MPIMotionAttrMaskELEMENT_ID | - This mask enables an identification tag to be stored in the path motion profiles. Please see MPIMotionAttributes for more information.
 | MPIMotionAttrMaskRELATIVE | This mask changes the profile target position from absolute to relative coordinates.
 | MPIMotionAttrMaskSYNC_END | This mask synchronizes the motion profiles for multiple axes so they will all end at the same time. Delays are inserted before the shorter profiles. When enabled, each axis will use its own MPITrajectory values.
 | MPIMotionAttrMaskSYNC_START | This mask synchronizes the motion profiles for multiple axes so they will all start at the same time. Delays are inserted after the shorter profiles. When enabled, each axis will use its own MPITrajectory values.
Remarks

The motion attribute masks are used to enable features with mpiMotionStart(…) and mpiMotionModify(…). The masks are ORed with the MPIMotionType to enable each feature.

For the motion types MPIMotionTypeS_CURVE_JERK, MPIMotionTypeS_CURVE, MPIMotionTypeTRAPEZOIDAL, if neither MPIMotionAttrMaskSYNC_START nor MPIMotionAttrMaskSYNC_END are specified, then only one MPITrajectory structure will be used for by mpiMotionStart() and mpiMotionModify(). Please refer to MPIMotionAttr for more information.

Trajectory

MEIMotionAttrMask

typedef enum {
    MEIMotionAttrMaskEVENT,
    MEIMotionAttrMaskFINAL_VEL,
    MEIMotionAttrMaskNO_REVERSAL,
    MEIMotionAttrMaskHOLD,
    MEIMotionAttrMaskHOLD_LESS,
    MEIMotionAttrMaskHOLD_GREATER,
    MEIMotionAttrMaskOUTPUT,
    MEIMotionAttrMaskALL,
} MEIMotionAttrMask;

Description
 | MEIMotionAttrMaskEVENT | This mask allows the user to specify an MPIEventMask during a motion.
 | MEIMotionAttrMaskFINAL_VEL | This mask allows the user to specify a non-zero target velocity for point to point motion types.
 | MEIMotionAttrMaskNO_REVERSAL | This mask prevents a motion profile from changing direction.
 | MEIMotionAttrMaskHOLD | This mask prevents a motion profile from executing until the specified trigger conditions are met.
 | MEIMotionAttrMaskHOLD_LESS | Motion attribute mask for less than or equal hold logic.
 | MEIMotionAttrMaskHOLD_GREATER | Motion attribute mask for greater than or equal hold logic.
 | MEIMotionAttrMaskOUTPUT | This mask allows the user to set or clear bits during a motion.

See Also | mpiMotionStart | mpiMotionModify | MPIMotionType | MPITrajectory | MPIEventMask


MEIMotionAttrOutput

MEIMotionAttrOutput

typedef	struct MEIMotionAttrOutput {
    MEIMotionAttrOutputType	type;
    union {
        long	*output;
        long	motor;
    } as;
    long	mask;
    long	pattern;
    long	pointIndex;	/* MEIMotionAttrMaskOUTPUT for path motion - point
                        index for turning on output - used with point lists */
} MEIMotionAttrOutput;

Description
 | type | This value specifies the output type to determine the output bits to be set or cleared.
 | *output | This value specifies the memory address when MEIMotionAttrOutputTypeOUTPUT is used.
 | motor | This value specifies the motor number when MEIMotionAttrOutputTypeMOTOR is used.
 | mask | This value specifies the AND mask when MEIMotionAttrHoldTypeOUTPUT is used.
 | pattern | This value specifies the comparison pattern when MEIMotionAttrHoldTypeOUTPUT is used. The motor output word or output address is bit-wise ANDed with the mask and compared to the pattern.
 | pointIndex | This value specifies an index to a point, when multiple point motion is used.

See Also | MEIMotionAttrOutputType


MEIMotionAttrOutputType

MEIMotionAttrOutputType

typedef enum {
    MEIMotionAttrOutputTypeINVALID,
    MEIMotionAttrOutputTypeNONE,
    MEIMotionAttrOutputTypeMOTOR,
    MEIMotionAttrOutputTypeOUTPUT,
} MEIMotionAttrOutputType;

Description
 | MEIMotionAttrOutputTypeNONE | This type disables the setting/clearing of output bit(s) during motion.
 | MEIMotionAttrOutputTypeMOTOR | This type configures a motor's output bit(s) to be set or cleared during motion.
 | MEIMotionAttrOutputTypeOUTPUT | This type configures bit(s) at a memory address to be set or cleared during motion.

See Also | MEIMotionAttrOutput


MPIMotionAttributes / MEIMotionAttributes

MPIMotionAttributes

typedef struct MPIMotionAttributes {
    double	*delay;		/* MPIMotionAttrMaskDELAY */
    long	id;		/* MPIMotionAttrMaskID */
    long	*elementId;	/* MPIMotionAttrMaskELEMENT_ID */
} MPIMotionAttributes;

Description
 | delay | This array defines the delay time (seconds) before a motion profile begins execution.
 | id | This value defines the identity for a point to point motion.
 | elementId | This array defines the identity for each element of a path motion.

MEIMotionAttributes

typedef struct MEIMotionAttributes {
    MPIEventMask	eventMask;	/* MEIMotionAttrMaskEVENT */
    double		*finalVelocity;	/* MEIMotionAttrMaskFINAL_VEL */
    MEIMotionAttrHold	*hold;		/* MEIMotionAttrMaskHOLD */
    long		*outputCount;	/* MEIMotionAttrMaskOUTPUT for path motion
                                       - number of outputs - per axis */
    MEIMotionAttrOutput	*output;	/* MEIMotionAttrMaskOUTPUT for path and non
                                       path motion - outputs - per axis */
} MEIMotionAttributes;

Description
 | eventMask | This structure specifies the mask to enable event generation. See MPIEventMask for more information.
 | *finalVelocity | This array specifies the target velocity for each axis when MEIMotionAttrMaskFINAL_VEL is used.
 | *hold | This array specifies the hold configurations for each axis when MEIMotionAttrMaskHOLD is used.
 | *outputCount | This array specifies the number of points per axis, to set/clear an output when MEIMotionAttrMaskOUTPUT is used.
 | *output | This structure specifies the output configuration for each axis when MEIMotionAttrMaskOUTPUT is used.

See Also | MPIEventMask | MEIMotionAttrMask


MPIMotionBESSEL

MPIMotionBESSEL

typedef	struct MPIMotionBESSEL {
    long	pointCount;
    double	*position;
    double	*time;

    MPIMotionPoint  point;
} MPIMotionBESSEL;

Description
 | positionCount | This value specifies the number of points.
 | *position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
 | *time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
 | point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionPoint


MPIMotionBSPLINE

MPIMotionBSPLINE

typedef	struct MPIMotionBSPLINE {
    long		pointCount;
    double		*position;
    double		*time;

    MPIMotionPoint	point;
} MPIMotionBSPLINE;

Description
 | pointCount | This value specifies the number of points.
 | *position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
 | *time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
 | point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionPoint


MPIMotionConfig / MEIMotionConfig

MPIMotionConfig

typedef struct MPIMotionConfig {
    MPIMotionDecelTime	decelTime;
    float		normalFeedrate;
    float		pauseFeedrate;
}MPIMotionConfig;

Description
 | decelTime | This structure defines the deceleration time for Stop and E-Stop actions. Please see MPIMotionDecelTime data type documentation for more information.
 | normalFeedrate | This value defines the normal feed speed rate. The default value is 1.0 (100%).
 | pauseFeedrate | This value defines the feed speed rate for the Stop action. The default value is 0.0.

MEIMotionConfig

typedef struct	MEIMotionConfig {
    long	axisCount;
    long	axisNumber[MEIXmpMAX_COORD_AXES];
    double	blendLimit;
} MEIMotionConfig;

Description
 | axisCount | The current number of axes mapped to the Motion Supervisor on the controller.
 | axisNumber | This array specifies the axis numbers of the current Axis to Motion Supervisor mapping on the controller.
 | blendLimit | This value specifies the acceleration blending limit criteria. If the change direction is greater than 90 degrees (0 degrees = no change, 180 degrees = about face) the acceleration resulting from the blending can exceed the acceleration limit specified in the motion parameters (180 degrees = acceleration*2.0). The blendLimit allows the user to limit the sharpness of turns to be blended. If cosine (turn angle defined above) is greater than the blendLimit, the motion will be blended. A blend limit value of 0 exclude turns sharper than 90 degrees. 1.0 causes all moves to be blended. -1.0 allows no blending

See Also | MPIMotionDecelTime | mpiMotionModify


MPIMotionDecelTime

MPIMotionDecelTime

typedef struct MPIMotionDecelTime {
    float	stop;	/* seconds */
    float	eStop;	/* seconds */
} MPIMotionDecelTime;

Description
 | stop | This value defines the deceleration time (seconds) for a Stop action. The default value is .5 seconds.
 | eStop | This value defines the deceleration time (seconds) for an E-Stop action. The default value is .05 seconds.
See Also


MEIMotionFrame

MEIMotionFrame

typedef	struct MEIMotionFrame {
    long		pointCount;
    MEIXmpFrame		*frame;
    MPIMotionPoint	point;
} MEIMotionFrame;

Description
 | pointCount | The value specifies the number of frames.
 | *frame | This structure contains the frame data for each frame. See MEIXmpFrame for more information.
 | point | This structure specifies the points configuration. See MPIMotionPoint for more information.

See Also | MPIMotionPoint


MEIMotionFrameBufferStatus

MEIMotionFrameBufferStatus

typedef struct MEIMotionFrameBufferStatus {
    long	size;
    long	frameCount;
} MEIMotionFrameBufferStatus;

Description
 | size | This value specifies the size of the controller's frame buffer.
 | frameCount | This value specifies the number of frames in the controller's frame buffer.
See Also


MPIMotionMessage and MEIMotionMessage

.

MPIMotionMessage / MEIMotionMessage

MPIMotionMessage

typedef enum {
    MPIMotionMessageMOTION_INVALID,
    MPIMotionMessageAXIS_NOT_FOUND,
    MPIMotionMessageAXIS_COUNT,
    MPIMotionMessageTYPE_INVALID,
    MPIMotionMessageATTRIBUTE_INVALID,
    MPIMotionMessageIDLE,
    MPIMotionMessageMOVING,
    MPIMotionMessageSTOPPING,
    MPIMotionMessageSTOPPED,
    MPIMotionMessageSTOPPING_ERROR,
    MPIMotionMessageERROR,
    MPIMotionMessageAUTO_START,
    MPIMotionMessagePROFILE_ERROR,
    MPIMotionMessagePROFILE_NOT_SUPPORTED,
    MPIMotionMessagePATH_ERROR,
    MPIMotionMessageFRAMES_LOW,
    MPIMotionMessageFRAMES_EMPTY,
} MPIMotionMessage;

Description
MPIMotionMessageMOTION_INVALID
 | The motion supervisor number is out of range. This message code is returned by mpiMotionCreate(…) if the motion supervisor number is less than zero or greater than or equal to MEIXmpMAX_MSs.
MPIMotionMessageAXIS_NOT_FOUND
 | The specified axis object is not available. This message is returned from mpiMotionAxisRemove(…) if the axis that is being removed is not a member of the motion object.
MPIMotionMessageAXIS_COUNT
 | The number of axes is out of range. This message is returned from mpiMotionConfigSet(…), mpiMotionStart(…), or mpiMotionModify(…) if there are no axes associated with the motion object or if the axis count exceeds MEIXmpMAX_COORD_AXES.
MPIMotionMessageTYPE_INVALID
 | The motion type or motion attribute is not valid. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) if the motion type or motion attribute mask is not recognized by the library. To correct the problem, select a motion type/attribute from the MPI and/or MEI enumerations.
MPIMotionMessageATTRIBUTE_INVALID
 | The motion attribute is not valid. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) if the motion attribute mask is not compatible with the specified motion type. To correct the problem, do not use the motion attribute mask with the specified motion type or select a different motion type.
MPIMotionMessageIDLE
 | All motion supervisor axes are not moving and are ready to move. This message code is returned from mpiMotionModify(…) when the motion supervisor is in the IDLE state. A motion cannot be modified if no motion is in progress. To correct the problem, use the AUTO_START attribute for mpiMotionModify(…) or use mpiMotionStart(…) instead. This message code is also returned from mpiMotionAction(…) when a STOP or RESUME is commanded when the motion supervisor is in the IDLE state. A motion cannot be stopped if there is no motion in progress and a motion cannot be resumed if there is no motion profile pending.
MPIMotionMessageMOVING
 | At least one motion supervisor axis is moving. This message code is returned from mpiMotionStart(…) when the motion supervisor is in the MOVING state. A motion cannot be started if a motion is in progress. To correct the problem, use mpiMotionModify(…) instead. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the MOVING state. A motion cannot be resumed or reset while a motion is in progress.
MPIMotionMessageSTOPPING
 | Motion supervisor axes are stopping due to a STOP action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the STOPPING state. A motion cannot be commanded when a stop is in progress. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the STOPPING state. A motion cannot be resumed or reset while a stop is in progress.
MPIMotionMessageSTOPPED
 | Motion supervisor axes are stopped due to a STOP action. This message code is returned from mpiMotionAction(…) when a STOP action is commanded while the motion supervisor is already in the STOPPED state.
MPIMotionMessageSTOPPING_ERROR
 | Motion supervisor axes are stopping due to an E_STOP or ABORT action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the STOPPING_ERROR state. A motion cannot be commanded when a stopping on error action is in progress. This message code is also returned from mpiMotionAction(…) when a RESUME or RESET is commanded when the motion supervisor is in the STOPPING state. A motion cannot be resumed or reset while a stopping on error action is in progress.
MPIMotionMessageERROR
 | Motion supervisor axes are in an error state due to an E_STOP or ABORT action. This message code is returned from mpiMotionStart(…) or mpiMotionModify(…) when the motion supervisor is in the ERROR state. A motion cannot be commanded when the motion supervisor is in an error state. This message code is also returned from mpiMotionAction(…) when a STOP or RESUME is commanded when the motion supervisor is in the ERROR state. To correct the problem, fix the condition that caused the E_STOP or ABORT action and then clear the ERROR state using mpiMotionAction(…) with a RESET.
MPIMotionMessageAUTO_START
 | The motion modify was automatically converted to a motion start. This message code is returned from mpiMotionModify(…) when the AUTO_START attribute mask was specified and the motion was commanded while the motion supervisor is in the IDLE state. This message code is useful for notifying an application of an auto-start, it is not an error condition.
MPIMotionMessagePROFILE_ERROR
 | The motion profile is not possible with the specified constraints. This message code is returned by mpiMotionModify(…) when the NO_REVERSAL attribute mask is specified, but the specified target position is in the reverse direction. To correct the problem, either remove the NO_REVERSAL constraint or specify a target position that is in the same direction as the motion profile in progress.
MPIMotionMessagePROFILE_NOT_SUPPORTED
 | The controller firmware does not support the specified motion profile type. This message code is returned by mpiMotionStart(…) or mpiMotionModify(…) when an S_CURVE_JERK or VELOCITY_JERK motion type is commanded, but not supported by the controller firmware. Due to programming memory space constraints, specific revisions of controller firmware may not support jerk motion types. To correct the problem, use the S_CURVE or VELOCITY motion instead.
MPIMotionMessagePATH_ERROR
 | The specified multi-point motion path is not valid. This message code is returned by mpiMotionStart(…) or mpiMotionModify(…) when the final point is not specified or the time slice is less than one controller sample.
MPIMotionMessageFRAMES_LOW
 | The controller's frame buffer is low. This message code is returned by the internal method, meiMotionFramesLow(…). This is an internal message code used by the library to manage the frame buffering.
MPIMotionMessageFRAMES_EMPTY
 | The controller's frame buffer is empty. This message code is returned by the internal method, meiMotionFramesLow(…). This is an internal message code used by the library to manage the frame buffering.

MEIMotionMessage

typedef enum {
    MEIMotionMessageRESERVED0,
    MEIMotionMessageRESERVED1,
    MEIMotionMessageRESERVED2,
    MEIMotionMessageNO_AXES_MAPPED,
} MEIMotionMessage;

Description
 | MEIMotionMessageRESERVED0 | Reserved for specialized use.
 | MEIMotionMessageRESERVED1 | Reserved for specialized use.
 | MEIMotionMessageRESERVED2 | Reserved for specialized use.
 | MEIMotionMessageNO_AXES_MAPPED | The motion object has no axes. This message code is returned by mpiMotionStart(…), mpiMotionModify(…) or mpiMotionAction(…) if there are no axes mapped to the motion object. To correct this problem, make sure there is at least one axis object associated with the motion object before commanding any motion or motion actions.

See Also | MPIMotionType | MPIMotionAttrMask | mpiMotionModify | mpiMotionAction mpiMotionStart


MPIMotionParams / MEIMotionParams

MPIMotionParams

typedef	struct MPIMotionParams {

    MPIMotionPT         pt;
    MPIMotionPTF        ptf;
    MPIMotionPVT        pvt;
    MPIMotionPVTF       pvtf;
    MPIMotionSPLINE	spline;
    MPIMotionBESSEL	bessel;
    MPIMotionBSPLINE	bspline;

    MPIMotionSCurve	    sCurve;
    MPIMotionSCurve	    sCurveJerk;
    MPIMotionTrapezoidal    trapezoidal;

    MPIMotionVelocity	velocity;
    MPIMotionVelocity	velocityJerk;

    MPIMotionAttributes	attributes;

    void		*external;
} MPIMotionParams;
Description

The Params structure contains the motion trajectory parameters for each motion type and the motion attributes.

pt | This structure contains the parameters for a PT motion type. Please see MPIMotionPT data type for more information.
ptf | This structure contains the parameters for a PTF (position, time, and feedforward) motion type. Please see MPIMotionPTF data type for more information.
pvt | This structure contains the parameters for a PVT motion type. Please see MPIMotionPVT data type for more information.
pvtf | This structure contains the parameters for a PTF (position, velocity, time, and feedforward) motion type. Please see MPIMotionPVTF data type for more information.
spline | This structure contains the parameters for a SPLINE motion type. Please see MPIMotionSPLINE data type for more information.
bessel | This structure contains the parameters for a BESSEL motion type. Please see MPIMotionBESSEL data type for more information.
bspline | This structure contains the parameters for a BSPLINE motion type. Please see MPIMotionBSPLINE data type for more information.
sCurve | This structure contains the parameters for a S_CURVE motion type. Please see MPIMotionSCurve data type for more information.
sCurveJerk | This structure contains the parameters for an S-Curve Jerk point to point motion type. Please see MPIMotionSCurveJerk data type for more information.
trapezoidal | This structure contains the parameters for a Trapezoidal point to point motion type. Please see MPIMotionTrapezoidal data type for more information.
velocity | This structure contains the parameters for a VELOCITY motion type. Please see MPIMotionVelocity data type for more information.
velocityJerk | This structure contains the parameters for a VELOCITY_JERK motion type. Please see MPIMotionVelocity data type for more information.
attributes | This structure contains the parameters for motion attributes. Please see MPIMotionAttributes data type for more information.
*external | This points to an external structure, containing controller specific parameters. Presently, this only supports MEIMotionAttributes. Please see MEIMotionAttributes data type for more information.

MEIMotionParams

typedef		struct MEIMotionParams {
    MEIMotionFrame	   frame;
    MPIMotionAttributes    attributes;
    MEIMotionAttributes    attributesMEI;
} MEIMotionParams;

Description
 | frame | This structure contains the frame data and points configuration. See MEIMotionFrame for more information.
 | attributes | This structure contains the motion attributes data. See MPIMotionAttributes for more information.
 | attributesMEI | This structure contains the motion attributes data. See MEIMotionAttributes for more information.

See Also | MEIMotionFrame | MPIMotionAttributes | MEIMotionAttributes For more information, please see the PT and PVT Path Motion for the XMP application note.


MPIMotionPoint

MPIMotionPoint

typedef struct MPIMotionPoint {
    long	retain;		/* FALSE => flush points after use */
    long	final;		/* FALSE => more points to come */
    long	emptyCount;	/* # of remaining points to trigger empty event, -1 => disable */
} MPIMotionPoint;

Description
 | retain | This value specifies whether or not the points should be stored in a buffer after execution. If retain=0, the points will not be stored after execution. If retain=1, the points will be stored in a buffer. This feature is useful for backing up on path.
 | final | This value specifies if more points will be loaded. If final=1, no more points will be loaded. If final=0, more points can be loaded using mpiMotionModify(…) with the MPIMotionAttrMaskAPPEND attribute mask.
 | emptyCount | This value specifies the minimum number of points in the buffer. If the number of points in the buffer is below emptyCount, an E_STOP action will occur. When emptyCount is (-1), the buffer low trigger is disabled.

See Also | mpiMotionModify | MPIMotionAttrMaskAPPEND | MPIMotionPT


MPIMotionPT

MPIMotionPT

typedef  struct MPIMotionPT {
    long             pointCount;
    double           *position;
    double           *time;
    MPIMotionPoint   point;
} MPIMotionPT;

Description
 | pointCount | This value specifies the number of points.
 | position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
 | time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
 | point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionPoint For more information, please see the PT and PVT Path Motion for the XMP application note.


MPIMotionPTF

MPIMotionPTF

typedef	struct MPIMotionPTF {
    long            pointCount;
    double          *position;
    double          *feedforward;
    double          *time;
    MPIMotionPoint  point;
} MPIMotionPTF;
Description

The MotionPTF structure contains the motion parameters for the MPIMotionTypePTF.

pointCount | This value specifies the number of points.
*position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
*feedforward | This array stores the feedforward values for the motion profile. There is one feedforward value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The feedforward values are interleaved in the array by the axis index. The units are raw DAC counts (range -32768 to +32767).
*time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionParams | MPIMotionType | MPIMotionPoint | mpiMotionStart | mpiMotionModify


MPIMotionPVT

MPIMotionPVT

typedef	struct MPIMotionPVT {
    long		pointCount;
    double		*position;
    double		*velocity;
    double		*time;
    MPIMotionPoint	point;
} MPIMotionPVT;

Description
 | pointCount | This value specifies the number of points.
 | position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
 | velocity | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the next position (point). The length of the time array must be equal to pointCount.
 | time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
 | point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionPoint For more information, please see the PT and PVT Path Motion for the XMP application note.


MPIMotionPVTF

MPIMotionPVTF

typedef	struct MPIMotionPVTF {
    long            pointCount;
    double          *position;
    double          *velocity;
    double          *feedforward;
    double          *time;
    MPIMotionPoint  point;
} MPIMotionPVTF;
Description

The MotionPVTF structure contains the motion parameters for the MPIMotionTypePVTF.

pointCount | This value specifies the number of points.
*position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
*velocity | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the next position (point). The length of the time array must be equal to pointCount.
*feedforward | This array stores the feedforward values for the motion profile. There is one feedforward value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The feedforward values are interleaved in the array by the axis index. The units are raw DAC counts (range -32768 to +32767).
*time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionParams | MPIMotionType | MPIMotionPoint | mpiMotionStart | mpiMotionModify


MPIMotionSCurve

MPIMotionSCurve

typedef struct MPIMotionSCurve {
    MPITrajectory   *trajectory;
    double          *position;
} MPIMotionSCurve;
Description

The SCurve structure contains the motion trajectory parameters and final target positions that specify the point-to-point motion profile. Only the velocity, acceleration, deceleration, and jerkPercent trajectory parameters are applicable to S-Curve motion profiles.

*trajectory | A pointer to an array of trajectory structures. Each trajectory structure contains the motion profile parameters for each axis associated with the motion object. If more than one axis is associated with the motion and neither the MPIMotionAttrMaskSYNC_START nor MPIMotionAttrMaskSYNC_END attributes are specified, then only the first trajectory structure will be applied as the vector trajectory for all the axes.
*position | A pointer to an array of target positions. Each position value specifies the target for each axis associated with the motion object. Some motion types, like VELOCITY and VELOCITY_JERK do not require target positions and will ignore these values.

See Also | MPITrajectory | MPIMotionType | mpiMotionStart | mpiMotionModify


MPIMotionSCurveJerk

MPIMotionSCurveJerk

typedef MPIMotionSCurve MPIMotionSCurveJerk;
Description

The SCurveJerk structure contains the motion trajectory parameters and final target positions that specify the point-to-point motion profile. Only the velocity, acceleration, deceleration, accelerationJerk, and decelerationJerk trajectory parameters are applicable to S-Curve Jerk motion profiles.

See Also | MPITrajectory | MPIMotionType | mpiMotionStart | mpiMotionModify


MPIMotionSPLINE

MPIMotionSPLINE

typedef		struct MPIMotionSPLINE {
    long		pointCount;
    double		*position;
    double		*time;

    MPIMotionPoint	point;
} MPIMotionSPLINE;

Description
 | pointCount | This value specifies the number of points.
 | *position | This array stores the positions for the motion profile. There is one position value per point, per axis. The length of the array must be equal to pointCount multiplied by the number of axes. The positions are interleaved in the array by the axis index.
 | *time | This array stores the times for the motion profile. There is one time value per point. The time specifies the number of seconds between the specified position, and the previous position (point). The length of the time array must be equal to pointCount.
 | point | This structure contains the point configuration. Please see MPIMotionPoint data type for more information.

See Also | MPIMotionPoint


MPIMotionTrapezoidal

MPIMotionTrapezoidal

typedef MPIMotionSCurve MPIMotionTrapezoidal;
Description

The Trapezoidal structure contains the motion trajectory parameters and final target positions that specify the point-to-point motion profile. Only the velocity, acceleration, and deceleration trajectory parameters are applicable to Trapezoidal motion profiles.

See Also | MPITrajectory | MPIMotionType | mpiMotionStart | mpiMotionModify


MEIMotionTrace

MEIMotionTrace

typedef enum {

    MEIMotionTraceSTATUS,
    MEIMotionTracePARAMS,
} MEIMotionTrace;

Description
 | MEIMotionTraceSTATUS | This trace bit enables motion status tracing for mpiMotion calls.
 | MEIMotionTracePARAMS | This trace bit enables motion parameters tracing for mpiMotion calls.
See Also


MPIMotionType and MEIMotionType

.

MPIMotionType / MEIMotionType

MPIMotionType

typedef enum {
    MPIMotionTypeINVALID,

    MPIMotionTypePT,
    MPIMotionTypePTF,
    MPIMotionTypePVT,
    MPIMotionTypePVTF,
    MPIMotionTypeSPLINE,
    MPIMotionTypeBESSEL,
    MPIMotionTypeBSPLINE,
    MPIMotionTypeBSPLINE2,

    MPIMotionTypeS_CURVE,
    MPIMotionTypeTRAPEZOIDAL,
    MPIMotionTypeS_CURVE_JERK,

    MPIMotionTypeVELOCITY,
    MPIMotionTypeVELOCITY_JERK,
    MPIMotionTypeMASK  = 0xFF,
} MPIMotionType;
Description

MPIMotionType is an enumeration of motion profile types. It specifies the motion profile to be generated with mpiMotionStart(…) and mpiMotionModify(…). The motion type also defines the trajectory parameters that must be passed to mpiMotionStart(...) and mpiMotionModify(...). For each MPIMotionType and MEIMotionType there is a corresponding element in the MPIMotionParams{...} or MEIMotionParams{...} structure. For example, when MPIMotionTypeS_CURVE is specified, the MPIMotionSCurve{...} structure must be filled in to specify the trajectory for the S-Curve profile.

The motion profile characteristics can be specified by bitwise OR-ing the MPIMotionType with one or more motion attribute masks. The MPIMotionAttrMask and MEIMotionAttrMask enumerations contain the attribute masks. Attribute masks can be used to enable special features or configure the motion profile calculation and execution properties.

Internally, the motion profile is calculated and broken up into smaller trajectory segments called frames. The frames contain position, time, velocity, acceleration, and jerk trajectory information. The controller buffers the frames in its memory and executes them by loading the values into its trajectory calculator. For simple MotionTypes, like VELOCITY, TRAPEZOIDAL, and S_CURVE, the frames are calculated by the controller. For complex, multi-point motions, like PT, PVT, SPLINE, etc. the frames are calculated in the MPI Library. MotionTypes that are calculated in the controller can be modified on-the-fly with mpiMotionModify(...).

MPIMotionTypePT | This type fits constant velocity profile segments through a list of position and time points. Please see MPIMotionPT for more information.
MPIMotionTypePTF | PTF motion is identical to PT except host-calculated feedforward values can be specified for each PTF motion segment.
MPIMotionTypePVT | This type fits jerk profile segments through a list of position, velocity and time points. Please see MPIMotionPVT for more information.
MPIMotionTypePVTF | PVTF motion is identical to PVT except host-calculated feedforward values can be specified for each PVTF motion segment.
MPIMotionTypeSPLINE | This type fits a Cubic spline through a specified list of position and time points. Please see MPIMotionSPLINE data type for more information.
MPIMotionTypeBESSEL | This type fits a Bessel spline through a specified list of position and time points. Please see MPIMotionBESSEL data type for more information.
MPIMotionTypeBSPLINE | This type fits a 3rd order B spline through a list of position and time points. Please see MPIMotionBSPLINE data type for more information.
MPIMotionTypeBSPLINE2 | This type fits a 2nd order B spline through a list of position and time points. Please see MPIMotionBSPLINE data type for more information.
MPIMotionTypeS_CURVE | This type specifies point to point motion using a S-Curve velocity profile. The profile is specified by acceleration, velocity, deceleration, jerkPercent, and final position. Please see MPIMotionSCurve data type for more information.
MPIMotionTypeS_CURVE_JERK | This type specifies point to point motion using a S-Curve velocity profile. The profile is specified by acceleration, velocity, deceleration, accelerationJerk, decelerationJerk, and final position. Please see MPIMotionSCurve data type for more information.
MPIMotionTypeTRAPEZOIDAL | This type specifies simple point to point motion using a trapezoidal velocity profile. The profile trajectory is specified by acceleration, velocity, deceleration and final position. Please see MPIMotionTrapezoidal data type for more information.
MPIMotionTypeVELOCITY | This type specifies S-Curve acceleration to a constant velocity. The profile trajectory is specified by acceleration, velocity, and jerkPercent. Please see MPIMotionVelocity data type for more information.
MPIMotionTypeVELOCITY_JERK | This type specifies S-Curve acceleration to a constant velocity. The profile trajectory is specified by acceleration, velocity, accelerationJerk and decelerationJerk. Please see MPIMotionVelocity data type for more information.

MEIMotionType

typedef enum {
    MEIMotionTypeFRAME,
} MEIMotionType;
Description

MEIMotionType is an enumeration of the controller specific motion profile types. See MPIMotionType for details.

MEIMotionTypeFRAME | This motion type is used to construct motion profiles at the frame level.

See Also | mpiMotionStart | mpiMotionModify | mpiMotionTYPE | MPIMotionParams | MEIMotionParams | MPIMotionAttr | MEIMotionAttr |


MPIMotionVelocity

MPIMotionVelocity

typedef struct MPIMotionVelocity {
    MPITrajectory	*trajectory;
} MPIMotionVelocity;
Description

The Velocity structure contains the motion trajectory parameters that specify velocity motion profiles. Only the velocity, acceleration, jerkPercent, and accelerationJerk trajectory parameters are applicable to velocity and velocity-jerk motion profiles.

*trajectory | This structure specifies the parameters for the motion profile, except deceleration is ignored. Please see MPITrajectory data type for more information.

See Also | MPITrajectory | MPIMotionType | mpiMotionStart | mpiMotionModify


mpiMotionAction

Declaration
long mpiMotionAction(MPIMotion   motion,
                     MPIAction   action)
Required Header stdmpi.h
Description

MotionAction performs the specified action on the Motion object (motion).

The deceleration stop and Estop times can be set with:

mpiMotionConfigSet(MPIMotion motion, MPIMotionConfig *config, void *external);

where the structure MPIMotionConfig, contains the elements:

MPIMotionConfig.decelTime.stop /* seconds */
MPIMotionConfig.decelTime.eStop /* seconds */

If "action" is | Then
MPIActionABORT or MPIActionE_STOP or MPIActionE_STOP_ABORT | the Motion will perform an emergency stop and/or abort on all axes, and then change to the error state (MPIStateSTOPPING_ERROR to MPIStateERROR). Before starting another Motion, you must first make a call to mpiMotionAction(motion, MPIActionRESET).
MPIActionABORT | MotionAction will disable the PID control (or other algorithm), set the DAC output to the offset value, and disable the amp enable outputs. After the abort completes, the Motion will be set to the ERROR state .
MPIActionE_STOP | MotionAction will decelerate the axis (or axes) to a stop in the time specified by the “eStop” time. After the Motion stops, the Motion will be set to the ERROR state.
MPIActionE_STOP_ABORT | MotionAction will decelerate the axis (or axes) to a stop in the time specified by the “eStop” time. Next, MotionAction will generate an MPIActionABORT. After the abort completes, the Motion is set to the ERROR state. The E_STOP_ABORT first performs an E_STOP, and then performs an ABORT. The E_STOP decelerates the axis to a stop, then the ABORT disables PID control and disables the amp enable output.
MPIActionRESET | if the Motion (motion) is in the error state (MPIStateERROR), the Motion will change to the idle state (MPIStateIDLE), so that motion can be restarted. If the error state was caused by an Abort action, then the command position will be set equal to the actual position during the Reset.
MPIActionRESUME | if the Motion is in the idle state (MPIStateIDLE), it will change to the moving state (MPIStateMOVING), and the Motion will resume if it was stopped by a prior call to mpiMotionAction(motion, MPIActionSTOP).
MPIActionSTOP | if the Motion is in the moving state (MPIStateMOVING), it will performing a stop on all axes and change to the idle state (MPIStateSTOPPING to MPIStateIDLE). MPIActionSTOP decelerates the axis (or axes) to a stop in the time specified by the “stop” time. After the motion stops, the Motion is set to the ERROR state.
Return Values
MPIMessageOK if MotionAction successfully performs the specified action on the Motion object
See Also


meiMotionActionFunction

Declaration
MEIMotionActionFunction  meiMotionActionFunction(MPIMotion    motion,
                                  MEIMotionActionFunction     function);
Required Header stdmpi.h
Description

MotionActionFunction

motion | a handle to the Motion object
function |
Return Values
MPIMessageOK if MotionActionFunction successfully
See Also


mpiMotionATTR

Declaration

#define	 mpiMotionATTR(type,attr)
((type) |= mpiMotionAttrMaskBIT(attr))
Required Header stdmpi.h
Description

MotionATTR turns on the specified motion attribute mask bits in the motion type.

See Also | MPIMotionAttr | MPIMotionAttrMask


mpiMotionAttrMaskBIT

Declaration
#define mpiMotionAttrMaskBIT(attr) (0x1 << (attr))
Required Header stdmpi.h
Description

MotionAttrMaskBIT converts the motion attribute into the motion attribute mask.

See Also | MPIMotionAttr | MPIMotionAttrMask


mpiMotionAxis

Declaration
MPIAxis mpiMotionAxis(MPIMotion motion,
                      long      index)
Required Header stdmpi.h
Description

MotionAxis returns the element at the position on the list indicated by index.

motion | a handle to the Motion object.
index | a position in the list.

Return Values
handle | to the indexth Axis of a Motion (motion)
MPIHandleVOID | if motion is invalid if index is less than 0 if index is greater than or equal to mpiMotionAxisCount(motion)
MPIMessageARG_INVALID | index is a negative number.
MEIListMessageELEMENT_NOT_FOUND | index is greater than or equal to the number of elements in the list.
MPIMessageHANDLE_INVALID | motion is an invalid handle.
See Also


mpiMotionAxisAppend

Declaration
long mpiMotionAxisAppend(MPIMotion  motion,
                         MPIAxis    axis)
Required Header stdmpi.h
Description

MotionAxisAppend appends an Axis (axis) to a Motion (motion).

motion | a handle to the Motion object.
axis | a handle to an Axis object.

Return Values
MPIMessageOK | if MotionAxisAppend successfully appends an Axis to a Motion object
MPIMessageHANDLE_INVALID | Either motion or axis is an invalid handle.
MPIMessageUNSUPPORTED | The list already contains the maximum number of elements (MEIXmpMAX_COORD_AXES). -or- motion and axis are on different controllers.
MPIMessageOBJECT_NOT_ENABLED | axis is not an enabled axis.
MPIMessageOBJECT_ON_LIST | axis is already on the list.
MPIMessageNO_MEMORY | Not enough memory was available.
See Also


mpiMotionAxisCount

Declaration
long mpiMotionAxisCount(MPIMotion motion)
Required Header stdmpi.h
Description

MotionAxisCount returns the number of elements on the list.

motion | a handle to the Motion object.

Return Values
number | of Axes in a Motion (motion)
-1 | if motion is invalid
0 | if motion is empty

See Also | mpiMotionAxis | mpiMotionAxisAppend


mpiMotionAxisFirst

Declaration
MPIAxis mpiMotionAxisFirst(MPIMotion  motion)
Required Header stdmpi.h
Description

MotionAxisFirst return the first element in the list. This function can be used in conjuntion with mpiMotionAxisNext() in order to iterate through the list.

motion | a handle to the Motion object.

Return Values
handle | to the first Axis of a Motion (motion)
MPIHandleVOID | if motion is invalid if motion is empty
MPIMessageHANDLE_INVALID | motion is an invalid handle.

See Also | mpiMotionAxisNext | mpiMotionAxisLast


mpiMotionAxisInsert

Declaration
long mpiMotionAxisInsert(MPIMotion motion,
                         MPIAxis   axis,
                         MPIAxis   insert)
Required Header stdmpi.h
Description

MotionAxisInsert inserts an Axis (insert) in a Motion (motion), just after the specified Axis (axis).

Return Values
MPIMessageOK if MotionAxisInsert successfully inserts an Axis (insert) in a Motion (motion) following a specified Axis (axis)
See Also | mpiMotionAxis


mpiMotionAxisIndex

Declaration
long mpiMotionAxisIndex(MPIMotion motion,
                        MPIAxis   axis)
Required Header stdmpi.h
Description

MotionAxisIndex returns the position of "axis" on the list.

motion | a handle to the Motion object.
axis | a handle to an Axis object.

Return Values
index | of an Axis (axis) in a Motion (motion)
-1 | if motion is invalid if the Axis (axis) was not found in the Motion (motion)

See Also | mpiMotionAxis


mpiMotionAxisLast

Declaration
MPIAxis mpiMotionAxisLast(MPIMotion motion)
Required Header stdmpi.h
Description

MotionAxisLast returns the last element in the list. This function can be used in conjuntion with mpiMotionAxisPrevious() in order to iterate through the list backwards.

motion | a handle to the Motion object.

Return Values
handle | to the last Axis of a Motion (motion)
MPIHandleVOID | if motion is invalid if motion is empty
MPIMessageHANDLE_INVALID | Either motion or axis is an invalid handle.

See Also | mpiMotionAxisPrevious


mpiMotionAxisListGet

Declaration
long mpiMotionAxisListGet(MPIMotion  motion,
                          long       *axisCount,
                          MPIAxis    *axisList)
Required Header stdmpi.h
Description

MotionAxisListGet gets the coordinate system of a Motion object (motion).

MotionAxisListGet writes the number of axes (in the coordinate system) to a location (pointed to by axisCount), and also writes an array (of axisCount Axis handles) to another location (pointed to by axisList).

Return Values
MPIMessageOK if MotionAxisListGet successfully gets the coordinate system of a Motion object
See Also | mpiMotionAxisListSet | mpiMotionAxis


mpiMotionAxisListSet

Declaration
long mpiMotionAxisListSet(MPIMotion  motion,
                          long       axisCount,
                          MPIAxis    *axisList)
Required Header stdmpi.h
Description

MotionAxisListSet creates a coordinate system of axisCount dimensions, using the Axis handles specified by axisList. Any existing coordinate system is completely replaced.

The axisList parameter is the address of an array of axisCount Axis handles, or is NULL (if axisCount is equal to zero).

A coordinate system may also be created incrementally (i.e. one Axis at a time) by using the append and/or insert methods described in this section. The initial Axis of a coordinate system may be specified using the axis parameter of mpiMotionCreate(...). The list methods in this section may be used to examine and manipulate a coordinate system (i.e. axis list) regardless of how it was created.
Return Values
MPIMessageOK if MotionAxisListSet successfully creates a coordinate system
See Also | mpiMotionCreate | mpiMotionAxisListGet | mpiMotionAxis


mpiMotionAxisNext

Declaration
MPIAxis mpiMotionAxisNext(MPIMotion motion,
                          MPIAxis   axis)
Required Header stdmpi.h
Description

MotionAxisNext returns the next element following "axis" on the list. This function can be used in conjuntion with mpiMotionAxisFirst() in order to iterate through the list.

motion | a handle to the Motion object.
axis | a handle to an Axis object.

Return Values
handle | to the Axis just after the specified Axis (axis) in a Motion (motion)
MPIHandleVOID | if motion is invalid if the specified Axis (axis) is the last axis in a Motion (motion)
MPIMessageHANDLE_INVALID | Either motion or axis is an invalid handle.

See Also | mpiMotionAxisFirst | mpiMotionAxisPrevious


mpiMotionAxisPrevious

Declaration
MPIAxis mpiMotionAxisPrevious(MPIMotion motion,
                              MPIAxis   axis)
Required Header stdmpi.h
Description

MotionAxisPrevious returns the previous element prior to "axis" on the list. This function can be used in conjuntion with mpiMotionAxisLast() in order to iterate through the list backwards.

motion | a handle to the Motion object.
axis | a handle to an Axis object.

Return Values
handle | to the Axis preceding the specified Axis (axis) in a Motion (motion)
MPIHandleVOID | if motion is invalid if the specfied Axis (axis) is the first Axis in a Motion (motion)
MPIMessageHANDLE_INVALID | Either motion or axis is an invalid handle.

See Also | mpiMotionAxisLast | mpiMotionAxisNext


mpiMotionAxisRemove

Declaration
long mpiMotionAxisRemove(MPIMotion  motion,
                         MPIAxis    axis)
Required Header stdmpi.h
Description

MotionAxisRemove removes an Axis (axis) from a Motion (motion).

Return Values
MPIMessageOK if MotionAxisRemove successfully removes the Axis from the Motion object
See Also


mpiMotionConfigGet

Declaration
long mpiMotionConfigGet(MPIMotion        motion,
                        MPIMotionConfig  *config,
                        void             *external)
Required Header stdmpi.h
Description

MotionConfigGet gets the configuration of a Motion object (motion) and puts (writes) it in the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIMotionConfig{} or is NULL.

Return Values
MPIMessageOK if MotionConfigGet successfully gets the configuration of a Motion object and writes it into the structure(s)
See Also | mpiMotionConfigSet | MEIMotionConfig


mpiMotionConfigSet

Declaration
long mpiMotionConfigSet(MPIMotion       motion,
                        MPIMotionConfig *config,
                        void            *external)
Required Header stdmpi.h
Description

MotionConfigSet sets (writes) the configuration of a Motion object (motion) using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIMotionConfig{} or is NULL.
Return Values
MPIMessageOK if MotionConfigSet successfully writes the configuration of a Motion object using data from the structure(s)
See Also | mpiMotionConfigGet | MEIMotionConfig


mpiMotionControl

Declaration
MPIControl mpiMotionControl(MPIMotion  motion)
Required Header stdmpi.h
Description

MotionControl returns a handle to the Control object with which the motion is associated.

motion | a handle to the Motion object

Return Values
MPIControl | handle to a Control object
MPIHandleVOID | if motion is invalid

See Also | mpiMotionCreate | mpiControlCreate


mpiMotionCreate

Declaration
MPIMotion mpiMotionCreate(MPIControl control,
                                long       number,
                                MPIAxis    axis)
Required Header stdmpi.h
Description

MotionCreate creates a Motion object associated with the motion supervisor identified by number located on motion controller control. MotionCreate is the equivalent of a C++ constructor.

If number is -1, MotionCreate selects the next unused motion supervisor. The axis parameter specifies the initial element in the list of Axis objects which determine the coordinate system (axis may be MPIHandleVOID).

Return Values
handle | handle to a Motion object
MPIHandleVOID | if the object could not be created

See Also | mpiMotionDelete | mpiMotionValidate


mpiMotionDelete

Declaration
long mpiMotionDelete(MPIMotion motion)
Required Header stdmpi.h
Description

MotionDelete deletes a Motion object (motion) and invalidates its handle. MotionDelete is the equivalent of a C++ destructor.

Deleting a Motion object does not delete any of the Axis objects in the coordinate system.
Return Values
MPIMessageOK if MotionDelete successfully deletes a Motion object and invalidates its handle
See Also | mpiMotionCreate | mpiMotionValidate


mpiMotionEventNotifyGet

Declaration
long mpiMotionEventNotifyGet(MPIMotion    motion,
                             MPIEventMask *eventmask,
                             void         *external)
Required Header stdmpi.h
Description

MotionEventNotifyGet writes the event mask (that specifies the event type(s) for which host notification has been requested) to the location pointed to by eventMask, and also writes it into the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventmask, i.e, the event notification information in eventmask and in external is not the same information. Note that eventmask or external can be NULL (but not both NULL).

Event notification is enabled for event types specified in eventmask, which is a bit mask generated by the logical OR of the MPIEventMask bits associated with the desired MPIEventType values.
Event notification is disabled for event types not specified in eventmask.

XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL.
The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).

Return Values
MPIMessageOK if MotionEventNotifyGet successfully writes the event mask to the location(s)
See Also | MPIEventType | MEIEventNotifyData | MEIEventStatusInfo mpiMotionEventNotifySet


mpiMotionEventNotifySet

Declaration
long mpiMotionEventNotifySet(MPIMotion    motion,
                             MPIEventMask eventmask,
                             void         *external)
Required Header stdmpi.h
Description

MotionEventNotifySet requests host notification of the event(s) that are generated by motion and specified by eventMask, and also specified by the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventmask, i.e, the event notification information in eventmask and in external is not the same information. Note that eventmask or external can be NULL (but not both NULL).

Event notification is enabled for event types specified in eventMask, a bit mask generated by the bitwise OR of the MPIEventMask bits associated with the desired MPIEventType values. Event notification is disabled for event types that are not specified in eventMask.

The mask of event types generated by a Motion object consists of bits from MPIEventMaskMOTION and MPIEventMaskAXIS.

XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL.
The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).

To... | Then...
enable host notification of all events | set eventmask to MPIEventMaskALL
disable host notification of all events | set eventmask to MPIEventTypeNONE
Return Values
MPIMessageOK if MotionEventNotifySet successfully requests host notification of the event(s) that are specified by eventMask and generated by motion
See Also | MPIEventType | MEIEventNotifyData | MEIEventStatusInfo mpiEventMaskMOTION | mpiEventMaskAXIS | mpiMotionEventNotifyGet


mpiMotionEventReset

Declaration
long mpiMotionEventReset(MPIMotion    motion,
                         MPIEventMask eventMask)
Required Header stdmpi.h
Description

MotionEventReset resets the event(s) that are specified in eventMask and generated by motion.
Your application must call MotionEventReset only after one or more latchable events have occurred.

Return Values
MPIMessageOK if MotionEventReset successfully resets the event(s) that are specified in eventMask and generated by motion
See Also


mpiMotionFlashConfigGet

Declaration
long mpiMotionFlashConfigGet(MPIMotion       motion,
                             void            *flash,
                             MPIMotionConfig *config,
                             void            *external)
Required Header stdmpi.h
Description

MotionFlashConfigGet gets the flash configuration for a Motion object (motion) and puts (writes) it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Motion’s flash configuration information in external is in addition to the Motion’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL). The implementation-specific flash argument is used to access flash memory.

XMP Only

external either points to a structure of type MEIMotionConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
Return Values
MPIMessageOK if MotionFlashConfigGet successfully gets the Motion’s flash configuration and writes it into the structure(s).
See Also | mpiMotionFlashConfigSet


mpiMotionFlashConfigSet

Declaration
long mpiMotionFlashConfigSet(MPIMotion       motion,
                             void            *flash,
                             MPIMotionConfig *config,
                             void            *external)
Required Header stdmpi.h
Description

MotionFlashConfigSet sets (writes) the flash configuration of a Motion object (motion) using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Motion’s flash configuration information in external is in addition to the Motion’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL). The implementation-specific flash argument is used to access flash memory.
XMP Only

external either points to a structure of type MEIMotionConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.

Return Values
MPIMessageOK if MotionFlashConfigSet successfully sets (writes) the Motion’s flash configuration using data from the structure(s)
See Also | MEIMotionConfig | MEIFlash | mpiMotionFlashConfigGet


meiMotionFrameBufferLoad

Declaration

        long meiMotionFrameBufferLoad(MPIMotion    motion,
                                      long         initial,
                                      long         lock,
                                      long         frameLowEvent);
Required Header stdmpi.h
Description

MotionFrameBufferLoad ...

motion | a handle to the Motion object
initial |
lock |
frameLowEvent |
Return Values
MPIMessageOK if MotionFrameBufferLoad successfully
See Also


mpiMotionFrameBufferStatus

.

meiMotionFrameBufferStatus

Declaration

        long meiMotionFrameBufferStatus(MPIMotion                   motion,
                                        MEIMotionFrameBufferStatus  *status)
Required Header stdmpi.h
Description

MotionFrameBufferStatus gets a Motion object (motion) frame buffer status and writes it to the structure pointed to by status.

motion | a handle to the Motion object
*status | a pointer to the motion frame buffer status structure returned by the method
Return Values
MPIMessageOK if MotionFrameBufferStatus successfully gets the frame buffer status
See Also | MEIMotionFrameBufferStatus


meiMotionLogClose

Declaration
long meiMotionLogClose(MPIMotion    motion);
Required Header stdmpi.h
Description

MotionLogClose frees the memory buffer for motion logging.

motion | a handle to the Motion object
Return Values
MPIMessageOK if MotionLogClose successfully frees the memory buffer for motion logging.
See Also | meiMotionLogOpen | meiMotionLogPrint


meiMotionLogOpen

Declaration
long meiMotionLogOpen(MPIMotion    motion,
                      long         maxEntries);
Required Header stdmpi.h
Description

MotionLogOpen allocates a memory buffer for motion logging.

motion | a handle to the Motion object
maxEntries | The maximum number of log entries. This value determines the log buffer memory size.
Return Values
MPIMessageOK if MotionLogOpen successfully allocates a memory buffer for motion logging.
See Also | meiMotionLogClose | meiMotionLogPrint


meiMotionLogPrint

Declaration
long meiMotionLogOpen(MPIMotion    motion,
                      char         *filename);
Required Header stdmpi.h
Description

MotionLogPrint reads the motion log buffer entries and writes the data into a file specified by the fileName.

motion | a handle to the Motion object
*filename | a pointer to a file name string.
Return Values
MPIMessageOK if MotionLogClose successfully writes the data into a file specified by the fileName.
See Also | meiMotionLogOpen | meiMotionLogClose


mpiMotionMemory

Declaration
long mpiMotionMemory(MPIMotion  motion,
                     void       **memory)
Required Header stdmpi.h
Description

MotionMemory sets (writes) the address [that is used to access a Motion’s (motion) memory] to the contents of memory. This address (or an address calculated from it) is passed as the src argument to mpiMotionMemoryGet(...), and also as the dst argument to mpiMotionMemorySet(...).

Return Values
MPIMessageOK if MotionMemory successfully writes the address (used to access a Motion’s memory) to the contents of memory
See Also | mpiMotionMemoryGet | mpiMotionMemorySet


mpiMotionMemoryGet

Declaration
long mpiMotionMemoryGet(MPIMotion motion,
                        void      *dst,
                        void      *src,
                        long      count)
Required Header stdmpi.h
Description

MotionMemoryGet copies count bytes of a Motion’s (motion) memory (starting at address src) to application memory (starting at address dst).

Return Values
MPIMessageOK if MotionMemoryGet successfully copies count bytes of a Motion’s memory to application memory
See Also | mpiMotionMemorySet | mpiMotionMemory


mpiMotionMemorySet

Declaration
long mpiMotionMemorySet(MPIMotion motion,
                        void      *dst,
                        void      *src,
                        long      count)
Required Header stdmpi.h
Description

MotionMemorySet copies count bytes of application memory (starting at address src) to a Motion’s (motion) memory (starting at address dst).

Return Values
MPIMessageOK if MotionMemorySet successfully copies count bytes of application memory to a Motion’s memory
See Also | mpiMotionMemoryGet | mpiMotionMemory


mpiMotionModify

Declaration
long mpiMotionModify(MPIMotion       motion,
                     MPIMotionType   type,
                     MPIMotionParams *params)
Required Header stdmpi.h
Description

MotionModify modifies the parameters of a Motion object (motion) if motion is in progress (MPIStateMOVING). The types of motion whose parameters can be modified while moving are MPIMotionTypeTRAPEZOIDAL, MPIMotionTypeS_CURVE, MPIMotionTypeVELOCITY, MPIMotionTypePT and MPIMotionTypePVT.

Use the MPIMotionAttrAUTO_START attribute to automatically start a motion profile if the MotionModify call is made too late (i.e., after the previous move has finished).

Return Values
MPIMessageOK | if MotionModify successfully modifies the parameters of a Motion object
MPIMotionMessageIDLE | if no Motion was in progress when MotionModify was called. In order for MotionModify to work, there must be a Motion in progress.
MPIMotionMessageAUTO_START | if MotionModify was called when no motion was in progress and the Auto-Start attribute was specified. In this case, the MotionModify is automatically converted into a MotionStart.
MPIMotionMessagePROFILE_ERROR | if the controller cannot generate the motion profile (based on the specified motion parameters and attributes).
For more Returns, click here |
See Also


mpiMotionNumber

Declaration
long mpiMotionNumber(MPIMotion  motion,
                     long       *number)
Required Header stdmpi.h
Description

MotionNumber writes the index of a Motion object (motion, on the motion controller that the Motion object is associated with) to the contents of number.
Return Values
MPIMessageOK if MotionNumber successfully writes the index of a Motion object to the contents of number
See Also


mpiMotionParamsGet

Declaration
long mpiMotionParamsGet(MPIMotion       motion,
                        MPIMotionParams *params)
Required Header stdmpi.h
Description

MotionParamsGet reads the parameters of a Motion object (motion) and writes it to the structure pointed to by params. These motion parameters will be used if mpiMotionStart(…) is called with Null motion params.

motion | a handle to the Motion object
*params | a pointer to the motion parameters structure returned by the method

Return Values
MPIMessageOK | if MotionParamsGet successfully returns the parameters associated with a Motion object
motion parameters | that are associated with a Motion object (motion). To set these motion parameters, call either mpiMotionParamsSet(...) or mpiMotionStart(...)

See Also | mpiMotionParamsSet | mpiMotionStart | meiMotionParamsValidate


mpiMotionParamsSet

Declaration
long mpiMotionParamsSet(MPIMotion       motion,
                        MPIMotionParams *params)
Required Header stdmpi.h
Description

.MotionParamsSet sets the parameters of a Motion object (motion). These motion parameters will be used if mpiMotionStart(...) is called with a Null motion parameter.

If Motion (motion) is active, MotionParamsSet will set motion parameters “on-the-fly,” i.e., at the first opportunity.
Return Values
MPIMessageOK if MotionParamsSet successfully sets the parameters of a Motion object
See Also | mpiMotionStart | mpiMotionParamsGet


meiMotionParamsValidate

Declaration
long meiMotionParamsValidate(MPIMotion       motion,
                             MPIMotionType   type,
                             MPIMotionParams *params,
                             MEIXmpAction    action,
                             long            *points)
Required Header stdmei.h
Description

MotionParamsValidate validates the type-specific motion parameters pointed to by params, using the coordinate system of motion.

If "*point" is | Then
not Null | the number of points specified by params is written to the location (pointed to by points)
Return Values
MPIMessageOK if MotionParamsValidate successfully validates the type-specific motion parameters using the coordinate system of motion
See Also


mpiMotionPositionGet

Declaration
long mpiMotionPositionGet(MPIMotion  motion,
                          double     *actual,
                          double     *command)
Required Header stdmpi.h
Description

MotionPositionGet gets the actual and command position values for all axes associated with a Motion (motion). The actual and command arguments each point to an array with a size equal to the number of axes associated with motion.

Return Values
MPIMessageOK if MotionPositionGet successfully gets the actual and command position values for all axes associated with a Motion object
See Also | mpiMotionPositionSet


mpiMotionPositionSet

Declaration
long mpiMotionPositionSet(MPIMotion motion,
                          double    *actual,
                          double    *command)
Required Header stdmpi.h
Description

MotionPositionSet sets the actual and command position values for all axes associated with a Motion (motion). The actual and command arguments each point to an array with a size equal to the number of axes associated with motion.

Return Values
MPIMessageOK if MotionPositionSet successfully sets the actual and command position values for all axes associated with a Motion object
See Also | mpiMotionPositionGet


mpiMotionStart

Declaration
long mpiMotionStart(MPIMotion       motion,
                    MPIMotionType   type,
                    MPIMotionParams *params)
Required Header stdmpi.h
Description

MotionStart changes a Motion object (motion) from the idle state (MPIStateIDLE) to the moving state (MPIStateMOVING), by initiating a motion of the given type using the specified parameters (params).If params is Null, then the motion parameters that were set by the most recent call to mpiMotionParamsSet(...) will be used to define the motion.

The coordinate system is defined by the ordered list of Axis object(s) that have been associated with the Motion object (motion). There must be at least one Axis in the coordinate system.

Return Values
MPIMessageOK | MotionStart successfully changes a Motion object from the idle state to the moving state
MPIMotionMessageMOVING | if MotionStart was called when a Motion is in progress
For more Returns, click here |
See Also | mpiMotionParamsSet | MPIState | See diagram on how mpiMotionStart works


mpiMotionStatus

Declaration
long mpiMotionStatus(MPIMotion  motion,
                     MPIStatus  *status,
                     void       *external)
Required Header stdmpi.h
Description

MotionStatus gets a Motion’s (motion) status and writes it to the structure pointed to by status, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Motion’s status information in external is in addition to the Motion’s status information in status, i.e., the status information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIMotionStatus{} or is NULL.

Return Values
MPIMessageOK if MotionStatus successfully writes the Motion’s status to the structure(s)
See Also


mpiMotionTrajectory

Declaration
long mpiMotionTrajectory(MPIMotion     motion,
                         MPITrajectory *trajectory)
Required Header stdmpi.h
Description

MotionTrajectory reads the current velocity and acceleration for all axes associated with a Motion object (motion). The trajectory argument points to an array of MPITrajectory structures, with a size equal to the number of axes associated with the Motion object (motion).

NOTE: deceleration, jerkPercent, accelerationJerk, and decelerationJerk fields cannot be read from the controller and consequently are set to zero.
Return Values
MPIMessageOK if MotionTrajectory successfully gets the trajectories for all axes associated with a Motion object
See Also | MPITrajectory


mpiMotionTYPE

Declaration

#define	 mpiMotionTYPE(type) 	((type) & MPIMotionTypeMASK)
Required Header stdmpi.h
Description

MotionType masks off all other bits in type, leaving the motion type.

See Also | MPIMotionType


mpiMotionValidate

Declaration
long mpiMotionValidate(MPIMotion  motion)
Required Header stdmpi.h
Description

MotionValidate validates the Motion object (motion) and its handle. Always call mpiMotionValidate after creating a new Motion object.
Return Values
MPIMessageOK if Motion is a handle to a valid object.
See Also | mpiMotionCreate | mpiMotionDelete


Diagram of mpiMotionStart

.

Diagram of mpiMotionStart

The diagram below explains how mpiMotionStart(...) executes.

Return to mpiMotionStart


Motion Error Codes and Messages

.

Motion Error Codes and Messages
Code | Message | Tips / Fixes
0x0d01 (3329) | Motion: motion invalid | The Motion parameters are incorrect. Recheck them.
0x0d02 (3330) | Motion: axis not found | The Axis number is invalid.
0x0d03 (3331) | Motion: axis count invalid | You may be commanding moves on Axes that don’t exist, or on zero Axes.
0x0d04 (3332) | Motion: type invalid | You may have called a motion type that doesn’t exist.
0x0d05 (3333) | Motion: attribute invalid | The value for a motion attribute is wrong.
0x0d06 (3334) | Motion: not ready | The motion controller is still executing the power-up sequence.
0x0d07 (3335) | Motion: MPIStateIDLE | No Motion was in progress when mpiMotionModify(...) was called. In order for mpiMotionModify(...) to work, there must be a motion in progress.
0x0d08 (3336) | Motion: MPIStateMOVING | You may have called mpiMotionStart(...) when a Motion was in progress.
0x0d09 (3337) | Motion: MPIStateSTOPPING | Indicates that a Stop event is in progress.
0x0d0a (3338) | Motion: MPIStateSTOPPING_ERROR | Indicates that an E-Stop event is in progress.
0x0d0b (3339) | Motion: MPIStateERROR | Indicates that an E-Stop or Abort event has occurred. Use mpiMotionAction(MPIActionRESET) to recover.
0x0d0c (3340) | Motion: auto-start | mpiMotionModify(...) was called with the MPIMotionAttrMaskAUTO_START attribute when the motion state was MPIStateIDLE. In this case, the motion profile is automatically started.
0x0d0d (3341) | Motion: profile error | The XMP couldn’t generate the next set of points. Check the motion parameters and attributes.

Return to Motion Objects page


Motion Attributes

Introduction | MPI Motion Attributes | MEI Motion Attributes

Introduction

This section details the use of various Motion Attributes, which are listed individually below. To use Motion Attributes, OR the attribute mask with the MPIMotionType value.

MPI Motion Attributes

MPIMotionAttrAPPEND

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskAPPEND attribute. This makes it possible to buffer several point-to-point motion profiles in the controller. Each successful call to mpiMotionStart(...) with the APPEND attribute will generate an MPIEventTypeMOTION_DONE from the controller when the motion is complete.

The MPIMotionAttrMaskID attribute is supported with MPIMotionAttrMaskAPPEND when calling mpiMotionStart(...). The XMP-Series controller firmware has been modified to buffer the ID values inside the axis' frames. Therefore, applications using the motion and axis event user data must be changed. Since the ID is stored in the controller's axis frames, the mpiMotionEventNotifySet(...) and mpiAxisEventNotifySet(...) must explicitly configure an appropriate axis memory location for the firmware to retrieve the ID. The sample programs motionID1.c and motionID2.c demonstrate this feature.

The MEIMotionAttrHOLD attribute is supported with MPIMotionAttrMaskAPPEND when calling mpiMotionStart(...).

Move Types: PT, PVT, Bessel, Bspline, Bspline2, S-Curve, Trapezoidal, Velocity, Frame
MPIMotionAttrAUTO_START

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskAUTO_START attribute. When AUTO_START is enabled, calls to mpiMotionModify(…) will automatically start a new motion if the previous motion is done. If AUTO_START is not enabled, and mpiMotionModify(...) is commanded after the initial motion has completed, the method will return an MPIMotionStateIDLE error.

Move Types: S-Curve, Trapezoidal, Velocity
MPIMotionAttrDELAY

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskDELAY attribute. This motion attribute will delay the move for a given number of seconds. MPIMotionParams.attributes.delay is a pointer to an array of doubles that assign delay times for each Axis.

Move Types: S-Curve, Trapezoidal, Velocity
MPIMotionAttrELEMENT_ID

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskELEMENT_ID attribute. Similar to the MPIMotionAttrMaskID, the ELEMENT_ID allows the application to set an identification value for each element of a path motion. The ID values are long values configured in the MPIMotionParams.attributes.elementId array. Each element in the array will be the ID value for that sequential portion of the motion.

In order to retrieve the ElementID, a pointer to the element ID is placed into the MEIEventNotifyData structure. This will cause the XMP to send the ElementID up to the MEIEventStatusInfo structure when an event occurs that causes an interrupt.

Move Types: PT, PVT, Bessel, Bspline, Bspline2, S-Curve, Trapezoidal, Velocity
MPIMotionAttrMaskID

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskID attribute. The ID attributes allows the application to assign an identification number to each motion. This number can be returned in the MPIEventStatus structure so the application will know which move has ended. This is particularly useful when multiple moves are buffered and the application needs to know which move is executing or has returned an event.

The MPIMotionParams.attributes.id value is a long that identifies the Motion. This ID value is passed to each Axis associated with the MS. In order to retrieve the MoveID, a pointer to the move ID is placed in the MEIEventNotifyData structure. This will cause the XMP to send the MoveID up to the MEIEventStatusInfo structure when an event occurs that causes an interrupt.

Move Types: PT, PVT, Spline, Bessel, Bspline, Bspline2, S-Curve, Trapezoidal, Velocity, Frame
MPIMotionAttrRELATIVE

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskRELATIVE attribute. When this mask is ANDed into the attribute mask, all position values will be used as relative motion distances instead of final absolute positions. For example, without the RELATIVE motion attribute, a move beginning at position 1000 with a position parameter value of 2000 will move to position 2000. If the RELATIVE attribute is turned on, the final move position will be 3000, a relative distance of 2000 counts from the starting value of 1000.

Move Types: PT, PVT, Spline, Bessel, Bspline, Bspline2, S-Curve, Trapezoidal, Velocity
MPIMotionAttrSYNC_END

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskSYNC_END attribute. SYNC_END is used for motions that include more than one axis. The SYNC_END attribute will generate trajectories for all axes appended to an MS that will end simultaneously. For all but the longest motion profile, wait frames will be added to the beginning of the moves. This will ensure that all axes end simultaneously.

Move Types: S-Curve, Trapezoidal
MPIMotionAttrSYNC_START

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskSYNC_START attribute. SYNC_START is used for Motions that include more than one Axis. All Axes will begin simultaneously. For those axes that finish first, a delay frame will be added to the end of the move.

Move Types: S-Curve, Trapezoidal

MEI Motion Attributes

MEIMotionAttrEVENT

The MPI has been extended to support mpiMotionStart(...) with the MEIMotionAttrMaskEVENT attribute. This mask allows the user to specify an MPIEventMask during a motion.
MEIMotionAttrFINAL_VEL

The MPI has been extended to support mpiMotionStart(...) with the MEIMotionAttrMaskFINAL_VEL attribute. This mask allows the user to specify a non-zero target velocity for point to point motion types.
MEIMotionAttrNO_REVERSAL

The MPI has been extended to support mpiMotionStart(...) with the MEIMotionAttrMaskNO_REVERSAL attribute. This mask prevents a motion profile from changing direction.
MEIMotionAttrHOLD

The MPI has been extended to support mpiMotionStart(...) with the MEIMotionAttrMaskHOLD attribute. The HOLD attribute prevents execution of a Motion. The HOLD attribute is applied at the beginning of the motion (one HOLD frame) before the execution of the point list. This prevents execution of the Motion until the HOLD frame is disabled.

The HOLD attribute is used to synchronize the start of motion with a host function call, XMP internal variable, or Motor Input state change. More than one Motion Supervisor may be synchronized. The type field of the MEIMotionAttrHold{} structure determines whether the synchronization comes from a host call (meiControlGateSet(), see below), internal variable (Axis Status, Position, etc.) or a Motor Input signal (transceiver, home input, user input, etc.).

Gated Moves: If the value of type is MEIMotionAttrHoldTypeGATE, the motion will be held until a call to mpiControlGateSet() is made with the closed parameter set to FALSE. When a MEIMotionAttrHoldTypeGATE is used, the source.gate field of MEIMotionAttrHold{} must be set to the gate number (0-31). The same gate number must be used for the gate parameter of meiControlGateSet().

Input Hold Moves: If the value of type is MEIMotionAttrHoldTypeINPUT, the motion will be held until then value of the internal Xmp variable specified (pointed to) by source.input bitwise anded with source.mask matches source.pattern.

Motor Input Hold Moves: If the value of type is MEIMotionAttrHoldTypeMOTOR, the motion will be held until the value of the internal dedicated input word (Motor[n].IO. DedicatedIN.IO) for the motor specified by source.motorNumber bitwise anded with source.mask matches source.pattern.

The timeout field of MEIMotionAttrHold{} will cause the motion to start after the specified timeout period (in seconds), even if the other hold criteria have not been satisfied. A value of zero for timeout causes the timeout feature to be disabled and forces the motion to wait for the hold criteria (gate open, or pattern match).

The MPI expects an array of hold attributes specifying separate attributes form each axis of a motion supervisor. All axes holding with the same hold attributes (same gate, same input, mask, and pattern) will start motion in the same sample even if the moves are specified using different motion supervisors.
MEIMotionAttrOUTPUT

The MPI has been extended to support mpiMotionStart(...) with the MPIMotionAttrMaskAPPEND attribute. This mask allows the user to set or clear bits during a motion. This motion attribute allows a Motion to change the state of a register in the controller memory. This configures a frame to toggle an output bit as a move begins.

Return to Motion Objects page


Returns for mpiMotionStart and mpiMotionModify

.

Returns for mpiMotionStart and mpiMotionModify

Both mpiMotionStart and mpiMotionModify use motion attributes, which are summarized in the table below.

Return Values - for both mpiMotionStart and MotionModify
MPIMotionMessageERROR | if MotionStart is called when the Motion Supervisor is in the error state.
MPIMotionMessageAXIS_COUNT | if the motion object has no axes.
MPIMotionMessagePROFILE_ERROR | if the Motion profile specified by the parameters cannot be calculated correctly.
MPIMotionMessageATTRIBUTE_INVALID | if the specified motion attribute mask is not valid with the motion type.
MPIMessagePARAM_INVALID | if the specified motion parameters are not valid with the Motion type.
MPIMessageARG_INVALID | if any of the MotionStart arguments are not valid.
MPIMessageUNSUPPORTED | if the motion type is not supported by the controller.

Return to mpiMotionStart or mpiMotionModify


Motor Objects

.

Motor Objects

Introduction

A Motor object manages a single motor on a controller. It represents the physical connections between the motor, drive, and associated I/O. The Motor object contains encoder data, limit switch, home sensor, amp fault and amp enable states, DAC outputs, and other status information.

For simple systems, there is a one-to-one relationship between the Axis, Filter and Motor objects.

For information about using absolute encoders with the MPI click here.

Methods

Create, Delete, Validate Methods
 | mpiMotorCreate | Create Motor object
 | mpiMotorDelete | Delete Motor object
 | mpiMotorValidate | Validate Motor object

Configuration and Information Methods
 | mpiMotorAmpEnableGet | Get state of amp enable output
 | mpiMotorAmpEnableSet | Set state of amp enable output
 | meiMotorAmpFault | Writes the amp fault buffer data of a motor.
 | meiMotorAmpFaultClear | Clears the amp fault buffer data of a motor.
 | meiMotorAmpWarning | Writes the amp warning buffer of the motor.
 | meiMotorAmpWarningClear | Clears the motor's amp wanring message buffer.
 | mpiMotorAxisMapGet | Get object map of axes
 | meiMotorCommutationModeGet | Gets the commutation mode of a motor.
 | meiMotorCommutationModeSet | Sets the commutation mode of a motor.
 | mpiMotorConfigGet | Get motor configuration
 | mpiMotorConfigSet | Set motor configuration
 | meiMotorConfigStepper | Configures a motor for stepper mode.
 | meiMotorDacConfigGet | Get a Motor's (motor) Dac configuration
 | meiMotorDacConfigSet | Set a Motor's (motor) Dac configuration
 | mpiMotorFeedback | Get feedback position
 | mpiMotorFlashConfigGet | Get flash config of motor
 | mpiMotorFlashConfigSet | Set flash config of motor
 | meiMotorInfo | Get information about the network, node, and drive interface
 | mpiMotorIoGet | Get dedicated I/O bits
 | mpiMotorIoSet | Set dedicated I/O bits
 | mpiMotorStatus / meiMotorStatus | Get motor status

Event Methods
 | mpiMotorEventConfigGet | Get motor’s event configuration
 | mpiMotorEventConfigSet | Set motor’s event configuration
 | mpiMotorEventNotifyGet | Get motor’s event mask for host notification.
 | mpiMotorEventNotifySet | Set motor’s event mask for host notification.
 | mpiMotorEventReset | Reset events specified in event mask
 | mpiMotorEventWait | Set the contents of the structure pointed to by status.

Memory Methods
 | mpiMotorMemory | Get address of motor memory
 | mpiMotorMemoryGet | Copy motor memory to application memory
 | mpiMotorMemorySet | Copy application memory to motor memory

Action Methods
 | meiMotorEncoderReset | Clears encoder faults.
 | meiMotorMultiTurnReset | Clears the SynqNet drive multi-turn data for absolute type encoders.

Relational Methods
 | mpiMotorControl | Get handle to associated Control object
 | mpiMotorFilterMapGet | Get object map of associated Filters
 | mpiMotorFilterMapSet | Set the Filters using object map
 | mpiMotorNumber | Get index number of motor (in Control list)

Other Methods
 | meiMotorCompareListGet |
 | meiMotorEncoderRatio | Get encoder ratio from the XMP.

Data Types

MEIMotorAmpFaults
MEIMotorAmpFaultMsg
MEIMotorAmpWarnings
MEIMotorAmpWarningMsg
MPIMotorBrake
MPIMotorBrakeMode
MPIMotorConfig / MEIMotorConfig
MEIMotorDacConfig
MEIMotorDacChannelConfig
MEIMotorDacChannelStatus
MEIMotorDacStatus
MEIMotorDedicatedIn
MEIMotorDedicatedOut
MEIMotorDisableAction
MPIMotorEncoder / MEIMotorEncoder
MPIMotorEncoderFault
MPIMotorEncoderFaultMask
MEIMotorEncoderRatio
MEIMotorEncoderReverseModulo
MEIMotorEncoderType
MPIMotorEventConfig / MEIMotorEventConfig
MPIMotorEventTrigger
MEIMotorFaultBit
MEIMotorFaultConfig
MEIMotorFaultMask
MPIMotorFeedback
MEIMotorInfo
MEIMotorInfoNodeType
MPIMotorIo
MEIMotorIoConfig
MEIMotorIoConfigIndex
MEIMotorIoMask
MEIMotorIoType
MPIMotorMessage / MEIMotorMessage
MEIMotorStatus
MEIMotorStatusOutput
MEIMotorStepper
MPIMotorType

Macros

mpiMotorEncoderFaultMaskBIT

Constants

MEIMotorAmpMsgMAX
MEIMotorAmpFaultsMAX
MEIMotorAmpWarningsMAX


MEIMotorAmpFaults

MEIMotorAmpFaults

typedef struct MEIMotorAmpFaults {
    long                 count;
    long                 code[MEIMotorAmpFaultsMAX];
    MEIMotorAmpFaultMsg  message[MEIMotorAmpFaultsMAX];
} MEIMotorAmpFaults;
Description

The MotorAmpFaults structure contains the amp fault information from a SynqNet drive. The amp fault messages are drive specific. Not all drives support amp fault messages. For details, please see the SqNodeLib header files and the drive manufacturer's documentation.

count | The number of amp faults in the buffer.
code | An array of drive specific amp fault coded values.
message | An array of drive specific amp fault message strings.

See Also | meiMotorAmpFault | meiMotorAmpFaultClear


MEIMotorAmpFaultsMAX

MEIMotorAmpFaultsMAX

#define	MEIMotorAmpFaultsMAX    (32) /* max faults per motor */

Description
 | MotorAmpFaultsMAX defines the maximum number of amp fault messages per motor.
See Also


MEIMotorAmpFaultMsg

MEIMotorAmpFaultMsg

typedef char   MEIMotorAmpFaultMsg[MEIMotorAmpMsgMAX];

Description
 | MotorAmpFaultMsg defines the amp fault message string definition.

See Also | MEIMotorAmpMsgMAX


MEIMotorAmpMsgMAX

MEIMotorAmpMsgMAX

#define	MEIMotorAmpMsgMAX    (200) /* max chars per motor */

Description
 | MotorAmpMsgMAX defines the maximum number of characters per amp fault message.
See Also


MEIMotorAmpWarnings

MEIMotorAmpWarnings

typedef struct MEIMotorAmpWarnings {
    long                    count;
    long                    code[MEIMotorAmpWarningsMAX];
    MEIMotorAmpWarningMsg   message[MEIMotorAmpWarningsMAX];
} MEIMotorAmpWarnings;
Description

The MotorAmpWarnings structure contains the amp warning information from a SynqNet drive. The amp warning messages are drive specific. Not all drives support amp warning messages. For details, please see the SqNodeLib header files and the drive manufacturer's documentation.

count | The number of amp faults in the buffer.
code | An array of drive specific amp fault coded values.
message | An array of drive specific amp fault message strings.

See Also | meiMotorAmpWarning | meiMotorAmpWarningClear


MEIMotorAmpWarningsMAX

MEIMotorAmpWarningsMAX

#define	MEIMotorAmpWarningsMAX    (32) /* max Warnings per motor */

Description
 | MotorAmpFaultsMAX defines the maximum number of amp warning messages per motor.
See Also


MEIMotorAmpWarningsMsg

MEIMotorAmpWarningsMsg

typedef  char  MEIMotorAmpWarningsMsg[MEIMotorAmpMsgMAX];

Description
 | MotorAmpWarningsMsg defines the maximum number of amp warning messages per motor.
See Also


MPIMotorBrake

MPIMotorBrake

typedef struct MPIMotorBrake {
    MPIMotorBrakeMode   mode;
    float               applyDelay;
    float               releaseDelay;
} MPIMotorBrake;
Description

The MotorBrake structure specifies the configuration for a motor's dedicated brake logic. Each motor object has a dedicated brake output. The controller enables/disables the brake depending on the amp enable state and the brake configuration. When the amp enable is disabled, the brake is set to an active state. When the amp enable is enabled, the brake is set to an inactive state.

See the diagrams below for the brake logic details:

mode | An enumerated brake mode. See MPIMotorBrakeMode.
applyDelay | The time between when the brake is active and the amp enable is disabled. The units are in seconds.
releaseDelay | The time between when the amp enable is enabled and the brake is inactive. The units are in seconds.

See Also | mpiMotorConfigGet | mpiMotorConfigSet | MPIMotorConfig | MEIMotorDedicatedOut


MPIMotorBrakeMode

MPIMotorBrakeMode

typedef enum{
    MPIMotorBrakeModeNONE,
    MPIMotorBrakeModeDELAY,

} MPIMotorBrakeMode;
Description

MotorBrakeMode is an enumeration of modes for the dedicated brake signal.

MPIMotorBrakeModeNONE | Brake feature is disabled.
MPIMotorBrakeModeDELAY | Brake is enabled/disabled with specified delays.

See Also | MPIMotorBrake | MPIMotorConfig


MPIMotorConfig / MEIMotorConfig

MPIMotorConfig

typedef struct MPIMotorConfig {
    MPIMotorType     type;

    /* Event configuration, ordered by MPIEventType */
    MPIMotorEventConfig    event[MPIEventTypeMOTOR_LAST];

    long            encoderPhase;          /* 0 => normal, else reversed */
    long            secondaryEncoderPhase; /* 0 => normal, else reversed */
    float           abortDelay;
    float           enableDelay;
    MPIMotorBrake   brake;

    MPIObjectMap    filterMap;

} MPIMotorConfig;

Description
 | event | Structure to configure various Motor Events. See MPIMotorEventConfig description.
 | encoderPhase | Configures encoder phasing. Normal (A rising, B rising, A falling, etc.) = 0 Reversed = non-zero This configuration is only valid for encoder type QUAD_AB. See MEIMotorEncoder.
 | secondaryEncoderPhase | Configures encoder phasing on the secondary encoder. Normal (A rising, B rising, A falling, etc.) = 0 Reversed = non-zero This configuration is only valid for encoder type QUAD_AB. See MEIMotorEncoder.
 | abortDelay | Sets time value, in seconds, to delay Abort action after Event has occured.
 | enableDelay | Sets time value, in seconds, to delay Enabling of the amplifier after commanded.
 | brake | Configures the dedicated brake logic. See MPIMotorBrake.
 | filterMap | Get/Set a map of Filter Objects to which the Motor is mapped. Default mapping is Filter 0 to Motor 0, Fitler 1 to Motor 1, etc. See also MPIObjectMap description in Object section.

MEIMotorConfig

typedef struct MEIMotorConfig {
    MEIMotorEncoder         Encoder[MEIXmpMotorEncoders];
    MEIMotorStatusOutput    StatusOutput;

    MEIMotorIoConfig        Io[MEIMotorIoConfigIndexLAST];

    MEIMotorFaultConfig     faultConfig;

    MEIMotorStepper         Stepper;
    MEIMotorDacConfig       Dac;

    long    pulseEnable;  /* 0 => normal, else pulse output */
    long    pulseWidth;   /* 0.1 to 25.5 microseconds */

    MEIXmpCommutationBlock  Commutation;
                              /* read-only from field Theta to end */

    MEIXmpLimitData         Limit[MEIXmpLimitLAST];

    MPIAction				nodeFailureAction;
    MPIAction               userFaultAction;
                              /* see MEISqNodeConfigUserFault{} structure */
    MEIMotorDisableAction   disableAction;

} MEIMotorConfig;

Description
 | Encoder | Structure to configure Motor Encoder type and parameters
 | StatusOutput | A structure to configure a motor's digital outputs to monitor axis status bits. Requires custom firmware.
 | Io | An array of motor I/O configuration structures.
 | faultConfig | A structure to configure a motor's fault bits. Support for motor fault bits is node/drive specific.
 | Stepper | Structure to configure Motor Stepper parameters. See MEIMotorStepper description.
 | Dac | Structure that includes Command and Auxiliary DAC configuration for each motor. See MEIMotorDacConfig description.
 | pulseEnable | Currently not supported.
 | pulseWidth | Currently not supported.
 | Commutation | A structure to configure controller sinusoidal commutation. This structure is controller specific. Please see the Sinusoidal Commutation Application Note for more details.
 | limit | Structure used to configure custom motor limits and events.
 | nodeFailureAction | Action applied to the motor when a Node failure occurs.
 | userFaultAction | Action applied to the motor when a User Fault occurs.
 | disableAction | Used to configure the controller to set the command position equal to the actual position while the motor is disabled.

See Also | mpiMotorConfigGet | mpiMotorConfigSet


MEIMotorDacConfig

MEIMotorDacConfig

typedef struct MEIMotorDacConfig {
    MEIXmpDACPhase             Phase;
    MEIMotorDacChannelConfig   Cmd;
    MEIMotorDacChannelConfig   Aux;
} MEIMotorDacConfig;
Description

MotorDacConfig is a structure that includes Command and Auxiliary DAC configuration for each motor.

See Also | meiMotorDacConfigGet | meiMotorDacConfigSet


MEIMotorDacChannelConfig

MEIMotorDacChannelConfig

typedef struct MEIMotorDacChannelConfig {
    float               Offset;	/* volts */
    float               Scale;
    MEIXmpDACInputType  InputType;
    MEIXmpGenericValue  *Input;
} MEIMotorDacChannelConfig;
Description

MotorDacChannelConfig is a structure used to configure the DAC settings.

Offset | Set DAC Offset value. Valid values range from -10 Volts to +10 Volts.
Scale | Multiplier for the Dac channel. Default value is 1.0.
InputType | An enumerated value to define whether the Dac channel input is a float or a long. The input type is reserved for special or custom configurations.
Input | A pointer to a MEIXmpGenericValue, which is a union of a long and float value. The input pointer is reserved for special or custom configurations.
See Also


MEIMotorDacChannelStatus

MEIMotorDacChannelStatus

typedef struct MEIMotorDacChannelStatus {
    float	level;	/* volts */
} MEIMotorDacChannelStatus;
Description

MotorDacChannelStatus is a structure that returns the DAC output value.

level | level reflects the DAC output value. Valid values range from -10 Volts to +10 Volts.
See Also


MEIMotorDacStatus

MEIMotorDacStatus

typedef struct MEIMotorDacStatus {
    MEIMotorDacChannelStatus	cmd;
    MEIMotorDacChannelStatus	aux;
} MEIMotorDacStatus;
Description

MotorDacStatus is a structure that returns the Status for both Command and Auxiliary DACs. It is used to read the cmd and aux DAC level (in volts) from the controller.
See Also


MEIMotorDedicatedIn

MEIMotorDedicatedIn

typedef enum {
    MEIMotorDedicatedInAMP_FAULT       =  MEIXmpMotorDedicatedFlagsMaskAMP_FAULT,  /* bit 0  */
    MEIMotorDedicatedInBRAKE_APPLIED   =  MEIXmpMotorDedicatedFlagsMaskBRAKE_ON,   /* bit 1  */
    MEIMotorDedicatedInHOME            =  MEIXmpMotorDedicatedFlagsMaskHOME,       /* bit 2  */
    MEIMotorDedicatedInLIMIT_HW_POS    =  MEIXmpMotorDedicatedFlagsMaskPOS_LIMIT,  /* bit 3  */
    MEIMotorDedicatedInLIMIT_HW_NEG    =  MEIXmpMotorDedicatedFlagsMaskNEG_LIMIT,  /* bit 4  */
    MEIMotorDedicatedInINDEX           =  MEIXmpMotorDedicatedFlagsMaskENC_INDEX,  /* bit 5  */
    MEIMotorDedicatedInFEEDBACK_FAULT  =  MEIXmpMotorDedicatedFlagsMaskENC_FAULT,  /* bit 6  */
    MEIMotorDedicatedInCAPTURED        =  MEIXmpMotorDedicatedFlagsMaskCAPTURED,   /* bit 7  */
    MEIMotorDedicatedInHALL_A          =  MEIXmpMotorDedicatedFlagsMaskHALL_A,     /* bit 8  */
    MEIMotorDedicatedInHALL_B          =  MEIXmpMotorDedicatedFlagsMaskHALL_B,     /* bit 9  */
    MEIMotorDedicatedInHALL_C          =  MEIXmpMotorDedicatedFlagsMaskHALL_C,     /* bit 10 */
    MEIMotorDedicatedInAMP_ACTIVE      =  MEIXmpMotorDedicatedFlagsMaskAMP_ACTIVE, /* bit 11 */
    MEIMotorDedicatedInWARNING         =  MEIXmpMotorDedicatedFlagsMaskWARNING,        /* bit 13 */
    MEIMotorDedicatedInDRIVE_STATUS_9  =  MEIXmpMotorDedicatedFlagsMaskDRIVE_STATUS9,  /* bit 14 */
    MEIMotorDedicatedInDRIVE_STATUS_10 =  MEIXmpMotorDedicatedFlagsMaskDRIVE_STATUS10, /* bit 15 */
} MEIMotorDedicatedIn;
Description

MotorDedicatedIn is an enumeration of bit masks for the motor's dedicated inputs. The support for dedicated inputs is node/drive specific. See the node/drive manufacturer's documentation for details.

MEIMotorDedicatedInAMP_FAULT | Generated by the masked motor fault bits. Active when one or more masked motor faults bits are active. See MEIMotorFaultConfig.
MEIMotorDedicatedInBRAKE_APPLIED | Mechanical brake state.
MEIMotorDedicatedInHOME | Position calibration sensor.
MEIMotorDedicatedInLIMIT_HW_POS | Hardware limit for the positive direction.
MEIMotorDedicatedInLIMIT_HW_NEG | Hardware limit for the negative direction.
MEIMotorDedicatedInINDEX | Encoder index signal.
MEIMotorDedicatedInFEEDBACK_FAULT | Position feedback status. TRUE when position feedback fails, FALSE when operating properly.
MEIMotorDedicatedInCAPTURED | Currently not supported.
MEIMotorDedicatedInHALL_A | Reflects the state of Hall Sensor A
MEIMotorDedicatedInHALL_B | Reflects the state of Hall Sensor B
MEIMotorDedicatedInHALL_C | Reflects the state of Hall Sensor C
MEIMotorDedicatedInAMP_ACTIVE | A bit set by the drive that indicates the amplifier's state. 1 = Amplifier is closing the current loop and the motor winding are energized. 0 = Amplifier is not closing the current loop and the motor windings are not energized. Support for this bit varies depending on the drive type.
MEIMotorDedicatedInWARNING | Drive warning state. 1 = drive warning status bit is active and warning message is available 0 = drive warning status bit is not active. Support for this bit varies depending on the drive type.
MEIMotorDedicatedInDRIVE_STATUS_9 | TBD
MEIMotorDedicatedInDRIVE_STATUS_10 | TBD

See Also | mpiMotorIoGet


MEIMotorDedicatedOut

MEIMotorDedicatedOut

typedef enum {
    MEIMotorDedicatedOutAMP_ENABLE     = MEIXmpMotorDedicatedFlagsMaskAMP_ENABLE,    /* bit 0 */
    MEIMotorDedicatedOutBRAKE_RELEASE  = MEIXmpMotorDedicatedFlagsMaskBRAKE_RELEASE, /* bit 1 */
} MEIMotorDedicatedOut;
Description

MotorDedicatedOut is an enumeration of bit masks for the motor's dedicated outputs. The support for dedicated outputs is node/drive specific. See the node/drive manufacturer's documentation for details.

MEIMotorDedicatedOutAMP_ENABLE | Enable/disable drive or amplifier. Drive is enabled when TRUE, disabled when FALSE.
MEIMotorDedicatedOutBRAKE_RELEASE | Enable/disable mechanical brake. Brake is released (motor shaft is free) when TRUE, engaged when FALSE.

See Also | mpiMotorIoGet | mpiMotorIoSet


MEIMotorDisableAction

MEIMotorDisableAction

typedef enum MEIMotorDisableAction {
    MEIMotorDisableActionNONE,
    MEIMotorDisableActionCMD_EQ_ACT,
} MEIMotorDisableAction;
Description

MotorDisableAction is an enumeration of controller actions to be applied when the Amp Enable is disabled. This feature can be configured by calling mpiMotorConfigSet(...) with the disableAction element in the MEIMotorConfig structure set to one of the values defined in the MEIMotorDisableAction enumeration.

The default configuration is MEIMotorDisableActionCMD_EQ_ACT. This configuration applies some safety features which eliminate motor jumps when the Amp Enable is enabled. This is the recommended configuration for all servo motor types.

The CMD_EQ_ACT action operates with ALL motor types (servo and stepper). If the motor is configured for stepper, make sure to use the Amp Enable. If the motor type is stepper and the Amp Enable is not used, make sure to set the disable action to NONE. The pulse output is based on the command position, so if the controller sets the command position equal to the actual position during motion, it will cause very unusual motion profiles.

MEIMotorDisableActionNONE

No action. When the Amp Enable is disabled (or enabled), the controller continues to calculate and apply the torque demand output value.
MEIMotorDisableActionCMD_EQ_ACT

Command position equals actual position action (default). When the Amp Enable is disabled, the controller will:

1) Disable the servo loop output (except for the offset).

2) Set the command position equal to the actual position every sample.

3) Clear the integrator error.

When the Amp Enable is enabled, the controller will operate the servo loop normally.

See Also | mpiMotorConfigSet | MEIMotorConfig | MEIMotorDisableAction


MPIMotorEncoder / MEIMotorEncoder

MPIMotorEncoder

typedef enum {
    MPIMotorEncoderPRIMARY,
    MPIMotorEncoderSECONDARY,
} MPIMotorEncoder;
Description

MotorEncoder is an enumeration of encoder feedback inputs for a motor.

MPIMotorEncoderPRIMARY | The first encoder feedback for a motor.
MPIMotorEncoderSECONDARY | The second encoder feedback for a motor.
See Also

MEIMotorEncoder

typedef struct MEIMotorEncoder {
    MEIMotorEncoderType             type;
    long                            countsPerRev;
    MEIMotorEncoderRatio            ratio;
    MEIMotorEncoderReverseModulo    reverseModulo;
} MEIMotorEncoder;

Description
 | type | The type of feedback being used by the motor.
 | countsPerRev | The number of encoder counts per one revolution of the motor's shaft.
 | ratio | Custom firmware required. Encoder feedback ratio for scaling.
 | reverseModulo | Custom firmware required. Reverse modulo value for the encoder to handle rollover.

See Also | mpiMotorCreate


MPIMotorEncoderFault

MPIMotorEncoderFault

typedef enum {
    MPIMotorEncoderFaultPRIMARY,
    MPIMotorEncoderFaultSECONDARY,
    MPIMotorEncoderFaultPRIMARY_OR_SECONDARY,
} MPIMotorEncoderFault;
Description

MotorEncoderFault is an enumeration of encoder fault sources for motor encoder fault events. Each motor object supports a primary and secondary encoder. The hardware may or may not support a secondary encoder.

MPIMotorEncoderFaultPRIMARY | Sets the Motor Event (Encoder Fault) to trigger from the primary encoder.
MPIMotorEncoderFaultSECONDARY | Sets the Motor Event (Encoder Fault) to trigger from the secondary encoder.
MPIMotorEncoderFaultPRIMARY_OR_SECONDARY | Sets the Motor Event (Encoder Fault) to trigger from either the primary or secondary encoder.

See Also | MPIMotorEventConfig | MPIMotorEventTrigger


MPIMotorEncoderFaultMask

MPIMotorEncoderFaultMask

typedef enum {
     MPIMotorEncoderFaultMaskNONE,
     MPIMotorEncoderFaultMaskBW_DET,
     MPIMotorEncoderFaultMaskILL_DET,
     MPIMotorEncoderFaultMaskABS_ERR,
     MPIMotorEncoderFaultMaskALL
} MPIMotorEncoderFaultMask;
Description

MotorEncoderFaultMask is an enumeration to mask bits from MPIMotorEncoderFault register.

MPIMotorEncoderFaultMaskBW_DET | Mask for Broken Wire detection
MPIMotorEncoderFaultMaskILL_DET | Mask for Illegal State detection
MPIMotorEncoderFaultMaskABS_ERR | Mask for Absolute Encoder Error
See Also


MEIMotorEncoderReverseModulo

MEIMotorEncoderReverseModulo

typedef struct MEIMotorEncoderReverseModulo {
    long    *Ptr;   /* XMP Address */
    long    Rollover;
} MEIMotorEncoderReverseModulo;
Description

MotorEncoderReverseModulo is used to program the firmware to calculate a 32-bit encoder position based off of the data that is pointed to by *Ptr. Each sample, the firmware calculates a delta from the data that is pointed to by *Ptr and the Rollover value. This delta is added to a 32-bit counter to create a 32-bit position.

NOTE: Custom Firmware is required to support this data type.

*Ptr | a pointer to the XMP address.
Rollover | the value is the resolution of the incoming data pointed to by *Ptr.
See Also


MEIMotorEncoderRatio

MEIMotorEncoderRatio

typedef struct MEIMotorEncoderRatio {
    long    A;    /* denominator */
    long    B;    /* numerator */
} MEIMotorEncoderRatio;
Description

MotorEncoderRatio is used to set the Encoder ratio. Ratio is programmed into the firmware via a denominator (A) and a numberator (B). A/B = ratio.

NOTE: Custom Firmware is required to support this data type.

A | the denominator.
B | the numerator.
See Also


MEIMotorEncoderType

MEIMotorEncoderType

typedef enum MEIMotorEncoderType{
    MEIMotorEncoderTypeQUAD_AB,
    MEIMotorEncoderTypeDRIVE,
    MEIMotorEncoderTypeSSI,
} MEIMotorEncoderType;
Description

MotorEncoderType is the type of encoder being used for feedback. The encoder type is drive specific. Therefore, an appropriate default value should be set by the MPI.

MEIMotorEncoderTypeQUAD_AB | Quadrature encoder feedback.
MEIMotorEncoderTypeDRIVE | Drive memory interface feedback. This includes all feedback types supported by the drive.
MEIMotorEncoderTypeSSI | Synchronous Serial Interface (SSI) absolute encoder feedback.
See Also


MPIMotorEventConfig / MEIMotorEventConfig

MPIMotorEventConfig

typedef struct MPIMotorEventConfig {
    MPIAction		  action;
    MPIMotorEventTrigger  trigger;
    long		  direction;
    float		  duration;	/* seconds */
} MPIMotorEventConfig;
Description

MotorEventConfig is a structure used to configure Motor Events.

direction | for Hardware and Software limits, enabling "direction" requires the direction of motion to be in direction of Limit.
duration | time that Limit (e.g. Home, Pos. and Neg. Limits, User Limit) must be asserted before Event is generated. Value in seconds.

MEIMotorEventConfig

typedef MEIXmpLimitData	MEIMotorEventConfig;
typedef struct {
    MEIXmpLimitCondition    Condition[MEIXmpLimitConditions];
    MEIXmpStatus            Status;
    MEIXmpLogic             Logic;
    MEIXmpLimitOutput       Output;
    long                    Count;
    long                    State;
} MEIXmpLimitData;
Description
condition | is a structure that configures the conditioanl statements evaluated to generate a Limit Event. Each limit may have up to two conditions (MEIXmpLimitConditions = 2). This structure is described in further detail in App Note 215.
status | an enum that defines what actions the XMP will take when a user limit evaluates TRUE. Always set Status to at least MEIXmpStatusLIMIT to notify the motor object that a limit has occurred. Valid Status values are listed in the "Values of Status" table below.
logic | an enum that sets the logic applied between the two condition block outputs, Condition[0] and Condition[1]. Valid Logic values are listed in the "Values of Status" table below.
output | is a structure that allows specific action to be taken when the Limit Event is generated. In addition to generatign a Motion Action, a Limit can write to any other valid XMP Firmware register defined in the *OutputPtr with value described by AndMask and OrMask. This structure is described in further detail in App Note 215.
count | For internal use only. The MPI method, mpiMotorEventConfigSet(...) will not write these values.
state | For internal use only. The MPI method, mpiMotorEventConfigSet(...) will not write these values.

Value of Status | Action to be taken
MEIXmpStatusLIMIT | None
MEIXmpStatusLIMIT | MEIXmpStatusPAUSE | Axes attached to the motor will be Paused
MEIXmpStatusLIMIT | MEIXmpStatusSTOP | Axes attached to the motor will be Stopped
MEIXmpStatusLIMIT | MEIXmpStatusABORT | Axes attached to the motor will be Aborted
MEIXmpStatusLIMIT | MEIXmpStatusESTOP | Axes attached to the motor will be E-Stopped
MEIXmpStatusLIMIT | MEIXmpStatusESTOP_ABORT | Axes attached to the motor will be E-Stopped and Aborted

Value of Logic | Evaluates | Motor object notified that a limit has occurred if...
MEIXmpLogicNEVER | Nothing | No event is generated
MEIXmpLogicSINGLE | Condition[0] | Condition[0] = = TRUE
MEIXmpLogicOR | Condition[0], Condition[1] | (Condition[0] || Condition[1]) = = TRUE
MEIXmpLogicAND | Condition[0], Condition[1] | (Condition[0] && Condition[1]) = = TRUE
other MEIXmpLogic enums | For internal use only. |
See Also | Special Note: MPIMotorEventConfig and Motor Limit Configuration See App Note 215 for a more in-depth breakdown of this structure. mpiMotorEventConfigGet | mpiMotorEventConfigSet | MPIEncoderFault


MPIMotorEventTrigger

MPIMotorEventTrigger

typedef union {
    long    polarity;  /* 0 => active low, else active high */
    long    position;  /* MPIEventTypeLIMIT_SW_[POS|NEG] */
    float   error;     /* MPIEventTypeLIMIT_ERROR */
    long    encoder;   /* MPIEventTypeENCODER_FAULT */
} MPIMotorEventTrigger;

Description
 | polarity | Configures the polarity for the motor event trigger. If polarity = 0 (FALSE), the event will trigger on an active low signal. If polarity = 1 (TRUE), the event will trigger on an active high signal.
 | position | Configures the positive and negative software position limits. The controller monitors the actual position and compares it to the positive and negative software position limits. If the positive limit is exceeded the controller will generate a MPIEventTypeLIMIT_SW_POS event. If the negative limit is exceeded the controller will generate a MPIEventTypeLIMIT_SW_NEG event.
 | error | Configures the position error limit. The controller calculates the position error each sample period: (command position - actual position) = position error. If the position error exceeds the range of the specified error limit, the controller will generate a MPIEventTypeLIMIT_ERROR.
 | encoder | Configures the controller to monitor the primary or secondary for faults. The encoder should be set to one of the values defined by the MPIMotorEncoderFault{...} enumeration. When configured, if the primary, secondary, or either encoder generates a fault, the controller will generate the MPIEventTypeENCODER_FAULT.

See Also | MPIMotorEventConfig | MPIMotorEncoderFault | MPIEventType | MEIEventType


MPIMotorFeedback

MPIMotorFeedback

typedef double MPIMotorFeedback[MPIMotorEncoderLAST];
Description

MotorFeedback is an array of doubles used to store motor feedback (both primary and secondary).

See Also | MPIMotorEncoder | mpiMotorFeedback


MEIMotorFaultBit

MEIMotorFaultBit

typedef enum MEIMotorFaultBit {
    MEIMotorFaultBitINVALID,
    MEIMotorFaultBitAMP_FAULT,
    MEIMotorFaultBitDRIVE_FAULT,
    MEIMotorFaultBitWATCHDOG_FAULT,
    MEIMotorFaultBitCHECKSUM_ERROR,
    MEIMotorFaultBitFEEDBACK_FAULT,
    MEIMotorFaultBitAMP_NOT_POWERED,
    MEIMotorFaultBitDRIVE_NOT_READY,
} MEIMotorFaultBit;
Description

MotorFaultBit is an enumeration of motor fault bits for the SynqNet node drive interface. The support for motor fault bits is node/drive specific. Please see the node\drive manufacturer's documentation for details.

MEIMotorFaultBitAMP_FAULT | External amp fault input pin. Indicates a fault condition in the amplifier.
MEIMotorFaultBitDRIVE_FAULT | Bit in the drive interface status register. Indicates a fault condition in the drive.
MEIMotorFaultBitWATCHDOG_FAULT | Bit in the drive interface status register. Indicates a drive failure due to a watchdog timeout. The node alternately sets/clears the watchdog each sample, the drive's processor then clears/sets the watchdog. If the drive's processor does not respond, the watchdog fault bit is set.
MEIMotorFaultBitCHECKSUM_ERROR | Bit in the drive interface status register. Indicates the data transfer (via serial or parallel memory interface) between the failed SynqNet node FPGA and drive with a checksum error.
MEIMotorFaultBitFEEDBACK_FAULT | Bit in the drive interface status register. Active when one or more of the feedback status bits is triggered. Indicates that the drive/motor position feedback system has failed.
MEIMotorFaultBitAMP_NOT_POWERED | Bit in the drive interface status register. The SynqNet drive amplifier power stage does not have sufficient voltage. The motor windings cannot be energized properly until this bit is clear.
MEIMotorFaultBitDRIVE_NOT_READY | Bit in the drive interface status register. The SynqNet drive is not ready to receive commands or servo motors. This fault indicates the drive has not completed its processor initialization or there is some other serious drive processor problem.

See Also | MEIMotorFaultMask | MEIMotorFaultConfig | meiMotorStatus


MEIMotorFaultConfig

MEIMotorFaultConfig

typedef struct MEIMotorFaultConfig {
    MEIMotorFaultMask   faultMask; /* sets the
                                     MEIMotorDedicatedInAMP_FAULT state */
} MEIMotorFaultConfig;
Description

The MotorFaultConfig structure specifies the motor fault bit configuration.

faultMask | A mask of motor fault bits. The masked motor fault bits will be monitored by the controller's motor object. If any masked motor fault bit is active (TRUE), the motor's dedicated amp fault input (MEIMotorDedicatedInAMP_FAULT) is set active (TRUE). The support for motor fault bits is node/drive specific. During SynqNet network initialization, the SqNodeLib automatically configures the faultMask based on the node type. See the node/drive manufacturer's documentation for details.

See Also | MEIMotorFaultBit | MEIMotorFaultMask | meiMotorStatus


MEIMotorFaultMask

MEIMotorFaultMask

  typedef enum MEIMotorFaultMask {
      MEIMotorFaultMaskAMP             = (1<< MEIMotorFaultBitAMP_FAULT),
      MEIMotorFaultMaskDRIVE           = (1<< MEIMotorFaultBitDRIVE_FAULT),
      MEIMotorFaultMaskWATCHDOG        = (1<< MEIMotorFaultBitWATCHDOG_FAULT),
      MEIMotorFaultMaskCHECKSUM        = (1<< MEIMotorFaultBitCHECKSUM_ERROR),
      MEIMotorFaultMaskFEEDBACK        = (1<< MEIMotorFaultBitFEEDBACK_FAULT),
      MEIMotorFaultMaskAMP_NOT_POWERED = (1<< MEIMotorFaultBitAMP_NOT_POWERED),
      MEIMotorFaultMaskDRIVE_NOT_READY = (1<< MEIMotorFaultBitDRIVE_NOT_READY),
  } MEIMotorFaultMask;
Description

MotorFaultMask is an enumeration of motor fault bit masks for the SynqNet node drive interface. The support for motor fault bits is node/drive specific. Please see the node\drive manufacturer's documentation for details.

MEIMotorFaultMaskAMP | External amp fault input pin. Indicates a fault condition in the amplifier.
MEIMotorFaultMaskDRIVE | Bit in the drive interface status register. Indicates a fault condition in the drive.
MEIMotorFaultMaskWATCHDOG | Bit in the drive interface status register. Indicates a drive failure due to a watchdog timeout. The node alternately sets/clears the watchdog each sample, the drive's processor then clears/sets the watchdog. If the drive's processor does not respond, the watchdog fault bit is set.
MEIMotorFaultMaskCHECKSUM | Bit in the drive interface status register. Indicates the data transfer (via serial or parallel memory interface) between the failed SynqNet node FPGA and drive with a checksum error.
MEIMotorFaultMaskFEEDBACK | Bit in the drive interface status register. Active when one or more of the feedback status bits is triggered. Indicates that the drive/motor position feedback system has failed.
MEIMotorFaultMaskAMP_NOT_POWERED | Bit in the drive interface status register. The SynqNet drive amplifier power stage does not have sufficient voltage. The motor windings cannot be energized properly until this bit is clear.
MEIMotorFaultMaskDRIVE_NOT_READY | Bit in the drive interface status register. The SynqNet drive is not ready to receive commands or servo motors. This fault indicates the drive has not completed its processor initialization or there is some other serious drive processor problem.

See Also | MEIMotorFaultBit | MEIMotorFaultConfig | meiMotorStatus


MEIMotorInfo

MEIMotorInfo

typedef struct MEIMotorInfo {
    MEIMotorInfoNodeType   nodeType;
    struct {
        long    networkNumber;
        long    nodeNumber;
        long    driveIndex;
    } sqNode;

    long    captureCount;
    long    encoderCount;

} MEIMotorInfo;
Description

The MotorInfo structure contains static data determined during network initialization. It identifies the network, node, and drive interface associated with the motor object.

nodeType | Identifies the type of node. See MEIMotorInfoNodeType.
networkNumber | An index to the SynqNet network (0, 1, 2 etc.).
nodeNumber | An index to the node (0, 1, 2, etc.).
driveIndex | An index to the drive interface (0, 1, 2, etc.).
captureCount | Counts the number of captures for the motor.
encoderCount | Counts the number of encoders for the motor.

See Also | meiMotorInfo


MEIMotorInfoNodeType

MEIMotorInfoNodeType

typedef enum MEIMotorInfoNodeType {
    MEIMotorInfoNodeTypeNONE,
    MEIMotorInfoNodeTypeSQNODE,
} MEIMotorInfoNodeType;
Description

MotorInfoNodeType is an enumeration of node types. It specifies the node type associated with the motor.

MEIMotorInfoNodeTypeNONE | Not a network node. The node is local to the controller.
MEIMotorInfoNodeTypeSQNODE | A SynqNet node type.

See Also | MEIMotorInfo


MPIMotorIo

MPIMotorIo

typedef struct MPIMotorIo {
    unsigned long	input;
    unsigned long	output;
} MPIMotorIo;
Description

MotorIo is a structure used to read the Motor input and set Motor output values.

input | The input value reflects the 32 bits of general and dedicated input values. The dedicated input values (bits 0-15) are specified by MEIMotorDedicatedIn. The general purpose input values (bits 16-31) can be specified by MEIMotorIoMask.
output | The output value reflects the 32 bits of general and dedicated output values. The dedicated output values (bits 0-15) are specified by MEIMotorDedicatedOut. The general purpose output values (bits 16-31) can be specified by MEIMotorIoMask.

See Also | MEIMotorDedicatedIn | MEIMotorDedicatedOut | MEIMotorIoMask


MEIMotorIoConfig

MEIMotorIoConfig

typedef struct MEIMotorIoConfig {
    MEIMotorIoType     Type;
} MEIMotorIoConfig;
Description

The MotorIoConfig structure specifies the configuration for the motor's digital I/O.

Type | The I/O bit function. See MEIMotorIoType.

See Also | mpiMotorConfigGet | mpiMotorConfigSet


MEIMotorIoConfigIndex

MEIMotorIoConfigIndex

typedef enum MEIMotorIoConfigIndex {
    MEIMotorIoConfigIndex0,
    MEIMotorIoConfigIndex1,
    MEIMotorIoConfigIndex2,
    MEIMotorIoConfigIndex3,
    MEIMotorIoConfigIndex4,
    MEIMotorIoConfigIndex5,
    MEIMotorIoConfigIndex6,
    MEIMotorIoConfigIndex7,
    MEIMotorIoConfigIndex8,
    MEIMotorIoConfigIndex9,
    MEIMotorIoConfigIndex10,
    MEIMotorIoConfigIndex11,
    MEIMotorIoConfigIndex12,
    MEIMotorIoConfigIndex13,
    MEIMotorIoConfigIndex14,
    MEIMotorIoConfigIndex15,
} MEIMotorIoConfigIndex;
Description

MotorIoConfigIndex is an enumeration of configurable motor I/O, indexed by a number.

MEIMotorIoConfigIndex0 | motor I/O number 0
MEIMotorIoConfigIndex1 | motor I/O number 1
MEIMotorIoConfigIndex2 | motor I/O number 2
MEIMotorIoConfigIndex3 | motor I/O number 3
MEIMotorIoConfigIndex4 | motor I/O number 4
MEIMotorIoConfigIndex5 | motor I/O number 5
MEIMotorIoConfigIndex6 | motor I/O number 6
MEIMotorIoConfigIndex7 | motor I/O number 7
MEIMotorIoConfigIndex8 | motor I/O number 8
MEIMotorIoConfigIndex9 | motor I/O number 9
MEIMotorIoConfigIndex10 | motor I/O number 10
MEIMotorIoConfigIndex11 | motor I/O number 11
MEIMotorIoConfigIndex12 | motor I/O number 12
MEIMotorIoConfigIndex13 | motor I/O number 13
MEIMotorIoConfigIndex14 | motor I/O number 14
MEIMotorIoConfigIndex15 | motor I/O number 15

See Also | MEIMotorIoConfig


MEIMotorIoMask

MEIMotorIoMask

typedef enum {
    MEIMotorIoMask0  =  MEIXmpMotorIOMaskConfigurable0,  /* bit 16 */
    MEIMotorIoMask1  =  MEIXmpMotorIOMaskConfigurable1,  /* bit 17 */
    MEIMotorIoMask2  =  MEIXmpMotorIOMaskConfigurable2,  /* bit 18 */
    MEIMotorIoMask3  =  MEIXmpMotorIOMaskConfigurable3,  /* bit 19 */
    MEIMotorIoMask4  =  MEIXmpMotorIOMaskConfigurable4,  /* bit 20 */
    MEIMotorIoMask5  =  MEIXmpMotorIOMaskConfigurable5,  /* bit 21 */
    MEIMotorIoMask6  =  MEIXmpMotorIOMaskConfigurable6,  /* bit 22 */
    MEIMotorIoMask7  =  MEIXmpMotorIOMaskConfigurable7,  /* bit 23 */
    MEIMotorIoMask8  =  MEIXmpMotorIOMaskConfigurable8,  /* bit 24 */
    MEIMotorIoMask9  =  MEIXmpMotorIOMaskConfigurable9,  /* bit 25 */
    MEIMotorIoMask10 =  MEIXmpMotorIOMaskConfigurable10, /* bit 26 */
    MEIMotorIoMask11 =  MEIXmpMotorIOMaskConfigurable11, /* bit 27 */
    MEIMotorIoMask12 =  MEIXmpMotorIOMaskConfigurable12, /* bit 28 */
    MEIMotorIoMask13 =  MEIXmpMotorIOMaskConfigurable13, /* bit 29 */
    MEIMotorIoMask14 =  MEIXmpMotorIOMaskConfigurable14, /* bit 30 */
    MEIMotorIoMask15 =  MEIXmpMotorIOMaskConfigurable15, /* bit 31 */
} MEIMotorIoMask;
Description

MotorIoMask is an enumeration of bit masks for the motor's configurable I/O. The support for configurable I/O is node/drive specific. See the node/drive manufacturer's documentation for details.

MEIMotorIoMask0 | motor I/O mask for bit number 0
MEIMotorIoMask1 | motor I/O mask for bit number 1
MEIMotorIoMask2 | motor I/O mask for bit number 2
MEIMotorIoMask3 | motor I/O mask for bit number 3
MEIMotorIoMask4 | motor I/O mask for bit number 4
MEIMotorIoMask5 | motor I/O mask for bit number 5
MEIMotorIoMask6 | motor I/O mask for bit number 6
MEIMotorIoMask7 | motor I/O mask for bit number 7
MEIMotorIoMask8 | motor I/O mask for bit number 8
MEIMotorIoMask9 | motor I/O mask for bit number 9
MEIMotorIoMask10 | motor I/O mask for bit number 10
MEIMotorIoMask11 | motor I/O mask for bit number 11
MEIMotorIoMask12 | motor I/O mask for bit number 12
MEIMotorIoMask13 | motor I/O mask for bit number 13
MEIMotorIoMask14 | motor I/O mask for bit number 14
MEIMotorIoMask15 | motor I/O mask for bit number 15

See Also | mpiMotorIoGet | mpiMotorIoSet | MEIMotorIoType


MEIMotorIoType

MEIMotorIoType

typedef enum MEIMotorIoType {
    MEIMotorIoTypeOUTPUT,
    MEIMotorIoTypeSOURCE1,
    MEIMotorIoTypeSOURCE2,
    MEIMotorIoTypeSOURCE3,
    MEIMotorIoTypeSOURCE4,
    MEIMotorIoTypeSOURCE5,
    MEIMotorIoTypeSOURCE6,
    MEIMotorIoTypeSOURCE7,
    MEIMotorIoTypeSOURCE8,
    MEIMotorIoTypeSOURCE9,
    MEIMotorIoTypeSOURCE10,
    MEIMotorIoTypeSOURCE11,
    MEIMotorIoTypeSOURCE12,
    MEIMotorIoTypeSOURCE13,
    MEIMotorIoTypeSOURCE14,
    MEIMotorIoTypeSOURCE15,

    MEIMotorIoTypeINPUT =  0x10,
} MEIMotorIoType;
Description

MotorIoType is an enumeration of motor I/O functions. A SynqNet node's motor I/O may support one or more features depending on the node hardware and FPGA. MotorIoType contains the generic enumerations for all nodes. For the node specific enumerations, please see the individual SqNode modules for details.

MEIMotorIoTypeOUTPUT | discrete digital output
MEIMotorIoTypeSOURCE1 | motor I/O source number 1 for node-specific feature.
MEIMotorIoTypeSOURCE2 | motor I/O source number 2 for node-specific feature.
MEIMotorIoTypeSOURCE3 | motor I/O source number 3 for node-specific feature.
MEIMotorIoTypeSOURCE4 | motor I/O source number 4 for node-specific feature.
MEIMotorIoTypeSOURCE5 | motor I/O source number 5 for node-specific feature.
MEIMotorIoTypeSOURCE6 | motor I/O source number 6 for node-specific feature.
MEIMotorIoTypeSOURCE7 | motor I/O source number 7 for node-specific feature.
MEIMotorIoTypeSOURCE8 | motor I/O source number 8 for node-specific feature.
MEIMotorIoTypeSOURCE9 | motor I/O source number 9 for node-specific feature.
MEIMotorIoTypeSOURCE10 | motor I/O source number 10 for node-specific feature.
MEIMotorIoTypeSOURCE11 | motor I/O source number 11 for node-specific feature.
MEIMotorIoTypeSOURCE12 | motor I/O source number 12 for node-specific feature.
MEIMotorIoTypeSOURCE13 | motor I/O source number 13 for node-specific feature.
MEIMotorIoTypeSOURCE14 | motor I/O source number 14 for node-specific feature.
MEIMotorIoTypeSOURCE15 | motor I/O source number 15 for node-specific feature.
MEIMotorIoTypeINPUT | discrete digital input

See Also | mpiMotorConfigGet | mpiMotorConfigSet


MPIMotorMessage / MEIMotorMessage

MPIMotorMessage

typedef enum {
     MPIMotorMessageMOTOR_INVALID,
} MPIMotorMessage;
Description

MotorMessage is an enumeration of Motor error messages that can be returned by the MPI library.
MPIMotorMessageMOTOR_INVALID The motor number is out of range. This message code is returned by mpiMotorCreate(…) if the motor number is less than zero or greater than or equal to MEIXmpMAX_Motors.

MEIMotorMessage

typedef enum {
    MEIMotorMessageMOTOR_NOT_ENABLED,
    MEIMotorMessageSECONDARY_ENCODER_NA,
    MEIMotorMessageHARDWARE_NOT_FOUND,
    MEIMotorMessageSTEPPER_INVALID,
    MEIMotorMessageDISABLE_ACTION_INVALID,
} MEIMotorMessage;
Description

MotorMessage is an enumeration of Motor error messages that can be returned by the MPI library.

MEIMotorMessageMOTOR_NOT_ENABLED
 | The motor number is not active in the controller. This message code is returned by mpiMotorEventConfig(…) if the specified motor is not enabled in the controller. To correct the problem, use mpiControlConfigSet(…) to enable the motor object, by setting the motorCount to greater than the motor number. For example, to enable motor 0 to 3, set motorCount to 4.
MEIMotorMessageSECONDARY_ENCODER_NA
 | The motor's secondary encoder is not available. This message code is returned by mpiMotorConfigSet(…) or mpiMotorEventConfigSet(…) if the encoder fault trigger is configured for a secondary encoder when the hardware does not support a secondary encoder. To correct the problem, do not select the secondary encoder when configuring the encoder fault conditions.
MEIMotorMessageHARDWARE_NOT_FOUND
 | The motor object's hardware resource is not available. This message code is returned by mpiMotorConfigGet(…) or mpiMotorConfigSet(…) if the node hardware for the motor is not found. During controller and network initialization the nodes and motor count for each node is discovered and mapped to the controller's motor objects. An application should not configure a motor object if there is no mapped hardware to receive the service commands. To correct this problem, verify that all expected nodes were found. Use meiSqNodeInfo(…) to determine the node topology and motor count per node. Check the node hardware power and network connections.
MEIMotorMessageSTEPPER_INVALID
 | The motor object stepper configuration is not valid. These message codes are returned by mpiMotorConfigGet(…) or mpiMotorConfigSet(…) if the motor type is configured for stepper while the disable action is configured for command position equals actual position. The disable action feature sets the command position equal to the actual position when the amp enable signal is set to disable. Stepper motor types are driven by a digital pulse, which is triggered by the controller's command position. Do not use disable action set to command equals actual with stepper motor types.
MEIMotorMessageDISABLE_ACTION_INVALID
 | The motor object stepper configuration is not valid. These message codes are returned by mpiMotorConfigGet(…) or mpiMotorConfigSet(…) if the motor type is configured for stepper while the disable action is configured for command position equals actual position. The disable action feature sets the command position equal to the actual position when the amp enable signal is set to disable. Stepper motor types are driven by a digital pulse, which is triggered by the controller's command position. Do not use disable action set to command equals actual with stepper motor types.

See Also | mpiMotorCreate


MEIMotorStepper

MEIMotorStepper

typedef struct MEIMotorStepper {
    float   PulseWidth; /* output pulse width  (sec) */
    long    Loopback;   /* TRUE = count step pulses in encoder reg. */
} MEIMotorStepper;
Description

MotorStepper is a structure used to configure Stepper Motor parameters.

PulseWidth | sets width of Step pulse. Valid values range from a minimum width of 0.1 usec to maximum width of 25.5 usec.
LoopBack | enables Step Loopback feature. When enabled, step output pulses counted to generate Actual Position. When disabled, external feedback device is required to generate actual position.
See Also


MEIMotorStatus

MEIMotorStatus

typedef struct MEIMotorStatus {
    MEIMotorDacStatus  dac;
    MEIMotorFaultMask  faultMask;
} MEIMotorStatus;
Description

MotorStatus is a structure that returns XMP specific Motor Status registers.

dac | Structure containing the DAC level (in volts) of the Command and Auxilury DACs.
faultMask | a value containing the states of the motor fault bits.

See Also | MEIMotorFaultConfig


MEIMotorStatusOutput

MEIMotorStatusOutput

typedef struct MEIMotorStatusOutput {
    long           *outPtr;
    MEIXmpIOMask   ioMask[MEIXmpMotorStatusOutputs];
} MEIMotorStatusOutput;
Description

The MotorStatusOutput structure specifies which motor outputs to follow the motor status bits. This feature requires custom controller firmware.

*outPtr | a pointer to controller memory.
ioMask | a bit mask to select the motor output signals.

See Also | mpiMotorConfigGet | mpiMotorConfigSet


MPIMotorType

MPIMotorType

typedef enum {
    MPIMotorTypeINVALID,

    MPIMotorTypeSERVO,
    MPIMotorTypeSTEPPER,

} MPIMotorType;
Description

MotorType is an enumeration of valid Motor Types.

MPIMotorTypeSERVO | Motor configured as Servo
MPIMotorTypeSTEPPER | Motor configured as Stepper
See Also


mpiMotorAmpEnableGet

Declaration
long mpiMotorAmpEnableGet(MPIMotor  motor,
                          long      *ampEnable)
Required Header stdmpi.h
Description

MotorAmpEnableGet gets the state of the amp enable output for a Motor (motor) and writes it in the location pointed to by ampEnable. Note that the actual state of amp enable output also depends upon the actual wiring and the polarity chosen in the instance of the MPIMotorConfig structure.

If "ampEnable" is | Then
FALSE (0) | the amp is disabled
TRUE (1) | the amp is enabled
Return Values
MPIMessageOK if MotorAmpEnableGet successfully writes the Motor’s amp enable output state to the location
See Also | MPIMotorConfig | mpiMotorAmpEnableSet


mpiMotorAmpEnableSet

Declaration
long mpiMotorAmpEnableSet(MPIMotor  motor,
                          long      ampEnable)
Required Header stdmpi.h
Description

MotorAmpEnableSet sets the state of the amp enable output for a Motor (motor) to ampEnable. Note that the actual state of amp enable output also depends upon the actual wiring and the polarity chosen in the instance of the MPIMotorConfig structure.

If "ampEnable" is | Then
FALSE (0) | the amp will be disabled
TRUE (1) | the amp will be enabled
Return Values
MPIMessageOK if MotorAmpEnableSet successfully sets the Motor’s amp enable output state to ampEnable
See Also | MPIMotorConfig | mpiMotorAmpEnableGet


meiMotorAmpFault

Declaration
long meiMotorAmpFault(MPIMotor           motor,
                      MEIMotorAmpFaults  *fault);
Required Header stdmei.h
Description

MotorAmpFault reads the amp fault buffer from a motor and writes the data into a structure pointed to by fault.

motor | a handle to the Motor object
*fault | a pointer to a structure containing the number of amp faults, their coded values and message strings. See MEIMotorAmpFaults.
Return Values
MPIMessageOK if MotorAmpFault writes the amp fault buffer data
See Also | meiMotorAmpFaultClear | meiMotorAmpWarning | meiMotorWarningClear


meiMotorAmpFaultClear

Declaration
long meiMotorAmpFaultClear(MPIMotor    motor);
Required Header stdmei.h
Description

MotorAmpFaultClear flushes the motor's amp fault message buffer. The number of amp faults is set to zero, the coded values are set to zero, and the messages are cleared.

motor | a handle to the Motor object
Return Values
MPIMessageOK if MotorAmpFaultClear successfully flushes the Motor’s amp fault message buffer.
See Also | meiMotorAmpFault | meiMotorAmpWarning | meiMotorWarningClear


meiMotorAmpWarning

Declaration
long meiMotorAmpWarning(MPIMotor             motor,
                        MEIMotorAmpWarnings  *warning);
Required Header stdmei.h
Description

MotorAmpWarning reads the amp warning buffer from a motor and writes the data into a structure pointed to by warning.

motor | a handle to the Motor object
*warning | a pointer to a structure containing the number of amp warnings, their coded values and message strings. See MEIMotorAmpWarnings.
Return Values
MPIMessageOK if MotorAmpWarning successfully writes the amp warning buffer data
See Also | meiMotorAmpWarningClear | meiMotorAmpFault | meiMotorAmpFaultClear


meiMotorAmpWarningClear

Declaration
long meiMotorAmpWarningClear(MPIMotor    motor);
Required Header stdmei.h
Description

MotorAmpWarningClear flushes the motor's amp warning message buffer. The number of amp warnings is set to zero, the coded values are set to zero, and the messages are cleared.

motor | a handle to the Motor object
Return Values
MPIMessageOK if MotorAmpWarningClear successfully ...
See Also | meiMotorAmpWarning | meiMotorAmpFault | meiMotorAmpFaultClear


mpiMotorAxisMapGet

Declaration
long mpiMotorAxisMapGet(MPIMotor      motor,
                        MPIObjectMap  *axismap)
Required Header stdmpi.h
Description

MotorAxisMapGet gets the object map of the Axes associated with a Motor (motor) and writes it into the structure pointed to by axismap.
Return Values
MPIMessageOK if MotorAxisMapGet successfully writes the Motor’s object map of Axes to the structure
See Also


mpiMotorConfigGet

Declaration
long mpiMotorConfigGet(MPIMotor       motor,
                       MPIMotorConfig *config,
                       void           *external)
Required Header stdmpi.h
Description

MotorConfigGet gets a Motor’s (motor) configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIMotorConfig{} or is NULL.

Return Values
MPIMessageOK if MotorConfigGet successfully writes the Motor’s configuration to the structure(s)
See Also | MEIMotorConfig | mpiMotorConfigSet


mpiMotorConfigSet

Declaration
long mpiMotorConfigSet(MPIMotor       motor,
                       MPIMotorConfig *config,
                       void           *external)
Required Header stdmpi.h
Description

MotorConfigSet sets a Motor’s (motor) configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The configuration information in external is in addition to the configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIMotorConfig{} or is NULL.
Return Values
MPIMessageOK if MotorConfigSet successfully sets the Motor’s configuration using data from the structure(s)
See Also | mpiMotorConfigGet | MEIMotorConfig Special Note: Using mpiMotorConfigSet with Absolute Encoders


meiMotorConfigStepper

Declaration
long meiMotorConfigStepper(MPIMotor       motor,
                           MEIMotorConfig *config,
                           long           stepperNumber)
Required Header stdmei.h
Description

MotorConfigStepper modifies the motor configuration structure pointed to by config, to use a step engine (stepperNumber) from another motor. By default, each motor uses its own step engine. Do NOT use more than one motor per step engine. Use the methods mpiMotorConfigGet/Set(…) to read/write the motor configuration from/to the controller.

motor | a handle to the Motion object
*config | a pointer to the motion frame buffer status structure returned by the method
stepperNumber | index to a step engine
Return Values
MPIMessageOK if MotorConfigStepper successfully modifies the motor configuration structure pointed to by config
See Also | mpiMotorConfigGet | mpiMotorConfigSet


meiMotorCommutationModeGet

Declaration
long meiMotorCommutationModeGet(MPIMotor       motor,
                                MEIXmpCommMode *mode)
Required Header stdmei.h
Description

MotorCommutationModeGet gets the commutation mode of a Motor (motor) and writes it to the location pointed to by mode.

Return Values
MPIMessageOK if MotorCommutationModeGet successfully gets the commutation mode of a Motor and writes it to the location
See Also | meiMotorCommutationModeSet


meiMotorCommutationModeSet

Declaration
long meiMotorCommutationModeSet(MPIMotor       motor,
                                MEIXmpCommMode mode)
Required Header stdmei.h
Description

MotorCommutationModeSet sets the commutation mode of a Motor (motor) to mode.

Return Values
MPIMessageOK if MotorCommutationModeSet successfully sets the commutation mode of a Motor to mode
See Also | meiMotorCommutationModeGet


mpiMotorControl

Declaration
const MPIControl mpiMotorControl(MPIMotor motor)
Required Header stdmpi.h
Description

MotorControl returns a handle to the Control object with which the motor is associated.

motor | a handle to the Motor object

Return Values
MPIControl | handle to a Control object
MPIHandleVOID | if motor is invalid

See Also | mpiMotorCreate | mpiControlCreate


meiMotorCompareListGet

Declaration
long meiMotorCompareListGet(MPIMotor motor,
                            long	  *compareCount,
                            long	  *compareList);
Required Header stdmei.h
Description

MotorCompareListGet sets compareCount to the number of compares that motor has. It sets compareList to the number of the compare object for each compare.

Return Values
MPIMessageOK if motor is a valid MPIMotor object.
See Also


mpiMotorCreate

Declaration
const MPIMotor mpiMotorCreate(MPIControl control,
                              long       number)
Required Header stdmpi.h
Description

MotorCreate creates a Motor object associated with the motor identified by number, and located on the motion controller (control). MotorCreate is the equivalent of a C++ constructor.

Return Values
handle | to a Motor object
MPIHandleVOID | if the Motor object could not be created

See Also | mpiMotorDelete | mpiMotorValidate


meiMotorDacConfigGet

Declaration
long meiMotorDacConfigGet(MPIMotor          motor,
                          MEIMotorDacConfig *dacConfig,
                          MEIFlash          flash);
Required Header stdmei.h
Description

MotorDacConfigGet gets a Motor's (motor) Dac configuration and writes it to the structure pointed to by dacConfig. The dac configuration located in flash is retrieved if the flash structure is not NULL.

Return Values
MPIMessageOK if MotorDacConfigGet successfully writes the Motor's Dac configuration to the config structure
See Also | meiMotorDacConfigSet | MEIMotorDacConfig


meiMotorDacConfigSet

Declaration
long meiMotorDacConfigSet(MPIMotor          motor,
                          MEIMotorDacConfig *dacConfig,
                          MEIFlash          flash);
Required Header stdmei.h
Description

MotorDacConfigSet configures a Motor's (motor) Dac using data from the structure pointed to by dacConfig. The dac configuration located in flash is set if the flash structure is not NULL.

Return Values
MPIMessageOK if MotorDacConfigSet successfully writes the Motor's Dac configuration to the controller
See Also | meiMotorDacConfigGet | MEIMotorDacConfig


mpiMotorDelete

Declaration
long mpiMotorDelete(MPIMotor motor)
Required Header stdmpi.h
Description

MotorDelete deletes a Motor object and invalidates its handle (motor). MotorDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if MotorDelete successfully deletes a Motor object and invalidates its handle
See Also | mpiMotorCreate | mpiMotorValidate


mpiMotorEncoderFaultMaskBIT

Declaration

#define	mpiMotorEncoderFaultMaskBIT(fault)	(0x1 << (fault))
Required Header stdmpi.h
Description

MotorEncoderFaultMaskBIT converts the motor encoder fault into the motor encoder fault mask.

See Also | MPIMotorEncoderFault | MPIMotorEncoderFaultMask


meiMotorEncoderReset

Declaration
long meiMotorEncoderReset(MPIMotor motor)
Required Header stdmei.h
Description

MotorEncoderReset clears the encoder fault status registers for the primary and secondary encoder associated with the motor object.

Return Values
MPIMessageOK if MotorEncoderReset(...) successfully resets the motor’s encoder value.
See Also


meiMotorEncoderRatio

Declaration
long meiMotorEncoderRatio(MPIControl           control,
                          long                 motorNumber,
                          long                 encoderNumber,
                          MEIMotorEncoderRatio *ratio)
Required Header stdmei.h
Description

MotorEncoderRatio gets encoder ratio from the XMP.

WARNING: This is a customer-specific method that is only supported with custom firmware. To inquire about using this method, please contact an MEI Applications Engineer.

Return Values
MPIMessageOK | if meiMotorEncoderRatio successfully gets encoder ration from the XMP.
MPIMessageARG_INVALID | if arguments are not valid
See Also


mpiMotorEventConfigGet

Declaration
long mpiMotorEventConfigGet(MPIMotor            motor,
                            MPIEventType        eventType,
                            MPIMotorEventConfig *eventConfig,
                            void                *external)
Required Header stdmpi.h
Description

MotorEventConfigGet gets the Motor’s (motor) configuration for the event specified by eventType and writes it into the structure pointed to by eventConfig, and also writes it to the implementation-specific structure pointed to by external (if external is not NULL).

The event configuration information in external is in addition to the event configuration information in eventConfig, i.e, the event configuration information in eventConfig and in external is not the same information. Note: Set eventConfig or external to NULL. One must be NULL, the other must be passed a pointer.
XMP Only

external either points to a structure of type MEIMotorEventConfig{} or is NULL.

Return Values
MPIMessageOK if MotorEventConfigGet successfully writes the Motor’s configuration for the event to the structure(s)
See Also | MEIMotorEventConfig | mpiMotorEventConfigSet


mpiMotorEventConfigSet

Declaration
long mpiMotorEventConfigSet(MPIMotor            motor,
                            MPIEventType        eventType,
                            MPIMotorEventConfig *eventConfig,
                            void                *external)
Required Header stdmpi.h
Description

MotorEventConfigSet

XMP Only

external either points to a structure of type MEIMotorEventConfig{} or is NULL.

Return Values
MPIMessageOK if MotorEventConfigGet successfully writes the Motor’s configuration for the event to the structure(s)
See Also | MEIMotorEventConfig | mpiMotorEventConfigGet


mpiMotorEventNotifyGet

Declaration
long mpiMotorEventNotifyGet(MPIMotor     motor,
                            MPIEventMask *eventMask,
                            void         *external)
Required Header stdmpi.h
Description

MotorEventNotifyGet writes the event mask (that specifies the event type(s) for which host notification has been requested) to the location pointed to by eventMask, and also writes it into the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventmask, i.e, the event notification information in eventmask and in external is not the same information. Note that eventmask or external can be NULL (but not both NULL).

Event notification is enabled for event types specified in eventmask, which is a bit mask of MPIEventMask bits associated with the desired MPIEventType values. Event notification is disabled for event types not specified in eventmask. The MPIEventMask bits must be set of cleared using the MPIEventMask macros.
XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL. The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).
Return Values
MPIMessageOK if MotorEventNotifyGet successfully writes the event mask to the location(s)
See Also | MPIEventType | MEIEventNotifyData | MEIEventStatusInfo mpiMotorEventNotifySet


mpiMotorEventNotifySet

Declaration
long mpiMotorEventNotifySet(MPIMotor     motor,
                            MPIEventMask eventMask,
                            void         *external)
Required Header stdmpi.h
Description

MotorEventNotifySet requests host notification of the event(s) that are generated by motor and specified by eventMask, and also specified by the implementation-specific location pointed to by external (if external is not NULL).

The event notification information in external is in addition to the event notification information in eventmask, i.e, the event notification information in eventmask and in external is not the same information. Note that eventmask or external can be NULL (but not both NULL).

Event notification is enabled for event types specified in eventMask, a bit mask of MPIEventMask bits associated with the desired MPIEventType values. Event notification is disabled for event types that are not specified in eventMask. The MPIEventMask bits must be set of cleared using the MPIEventMask macros.

The mask of event types generated by a Motor object consists of bits from MPIEventMaskMOTION and MPIEventMaskAXIS.
XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL. The MEIEventNotifyData{} structure is an array of firmware addresses, whose contents are placed into the MEIEventStatusInfo{} structure (of all events generated by this object).

To | Then
enable host notification of all events | set eventmask to MPIEventMaskALL
disable host notification of all events | set eventmask to MPIEventTypeNONE
Return Values
MPIMessageOK if MotorEventNotifySet successfully requests host notification of the event(s) that are specified by eventMask and generated by motor
See Also | MPIEventType | MEIEventNotifyData | MEIEventStatusInfo mpiMotorEventNotifyGet


mpiMotorEventReset

Declaration
long mpiMotorEventReset(MPIMotor     motor,
                        MPIEventMask eventMask)
Required Header stdmpi.h
Description

MotorEventReset resets the event(s) that are specified in eventMask and generated by motor.
Your application must call MotorEventReset only after one or more latchable events have occurred.
Return Values
MPIMessageOK if MotorEventReset successfully resets the event(s) that are specified in eventMask and generated by motor
See Also


mpiMotorEventWait

Declaration
long mpiNotifyEventWait(MPINotify      notify,
                        MPIEventStatus *status,
                        MPIWait        timeout)
Required Header stdmpi.h
Description

NotifyEventWait sets the contents of the structure pointed to by status, using the status of the first event in the internal FIFO event queue (maintained by a Notify object (notify)), and then removes the first event from the queue. If no event is available in the internal FIFO event queue, NotifyEventWait will wait for timeout milliseconds.

If "timeout" is | Then
MPIWaitPOLL (0) | NotifyEventWait will not wait for an event to arrive
MPIWaitFOREVER (-1) | NotifyEventWait will wait forever for an event to arrive

Return Values
MPIMessageOK | if NotifyEventWait successfully sets the contents of the structure pointed to by status, and then removes the first event from the queue
MPIMessageTIMEOUT | if no event is present and the contents of status are undefined
See Also


mpiMotorFeedback

Declaration
long mpiMotorFeedback(MPIMotor           motor,
                      MPIMotorFeedback   *feedback)
Required Header stdmpi.h
Description

MotorFeedback gets the feedback position of a Motor (motor) and writes it into the location pointed to by feedback.

Return Values
MPIMessageOK if MotorFeedback successfully writes the feedback position into the location.
See Also | mpiMotorFeedbackConfigSet


mpiMotorFlashConfigGet

Declaration
long mpiMotorFlashConfigGet(MPIMotor       motor,
                            void           *flash,
                            MPIMotorConfig *config,
                            void           *external)
Required Header stdmpi.h
Description

MotorFlashConfigGet gets a Motor’s (motor) flash configuration and writes it in the structure pointed to by config, and also writes it in the implementation-specific structure pointed to by external (if external is not NULL).

The Motor’s flash configuration information in external is in addition to the Motor’s flash configuration information in config, i.e, the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEIMotorConfig{} or is NULL.

Return Values
MPIMessageOK if MotorFlashConfigGet successfully writes the Motor’s flash configuration to the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIMotorConfig | MEIFlash | mpiMotorFlashConfigSet


mpiMotorFlashConfigSet

Declaration
long mpiMotorFlashConfigSet(MPIMotor       motor,
                            void           *flash,
                            MPIMotorConfig *config,
                            void           *external)
Required Header stdmpi.h
Description

MotorFlashConfigSet sets a Motor’s (motor) flash configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Motor’s flash configuration information in external is in addition to the Motor’s flash configuration information in config, i.e, the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).
XMP Only

external either points to a structure of type MEIMotorConfig{} or is NULL.
Return Values
MPIMessageOK if MotorFlashConfigSet successfully sets the Motor’s flash configuration using data from the structure(s)
flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
See Also | MEIMotorConfig | MEIFlash | mpiMotorFlashConfigGet


mpiMotorFilterMapGet

Declaration
long mpiMotorFilterMapGet(MPIMotor     motor,
                          MPIObjectMap *filtermap)
Required Header stdmpi.h
Description

MotorFilterMapGet gets the object map of the Filters [that are associated with a Motor (motor)] and writes it into the structure pointed to by filtermap.
Return Values
MPIMessageOK if MotorFilterMapGet successfully writes the Filter’s object map (associated with a Motor) to the structure
See Also | mpiMotorFilterMapSet


mpiMotorFilterMapSet

Declaration
long mpiMotorFilterMapSet(MPIMotor     motor,
                          MPIObjectMap filtermap)
Required Header stdmpi.h
Description

MotorFilterMapSet sets the Filters [that are associated with a Motor (motor)], using data from the object map specified by filtermap.

Return Values
MPIMessageOK if MotorFilterMapSet successfully sets the Filters using data from the object map
See Also | mpiMotorFilterMapGet


meiMotorInfo

Declaration
long meiMotorInfo(MPIMotor      motor,
                  MEIMotorInfo  *info);
Required Header stdmei.h
Description

MotorInfo reads the static information about the network, node, and drive interface associated with the motor object, and writes it into the structure pointed to by info.

motor | a handle to the Motor object
*info | a pointer to a motor information structure
Return Values
MPIMessageOK if MotorInfo successfully writes the network and node/drive interface information into the Motor structure.
See Also | meiMotorStatus


mpiMotorIoGet

Declaration
long mpiMotorIoGet(MPIMotor    motor,
                   MPIMotorIo  *io)
Required Header stdmpi.h
Description

MotorIoGet gets a Motor’s (motor) dedicated I/O bits and writes them into the structure pointed to by io.
Return Values
MPIMessageOK if MotorIoGet successfully writes the Motor’s dedicated I/O bits to the structure
See Also | mpiMotorIoSet


mpiMotorIoSet

Declaration
long mpiMotorIoSet(MPIMotor    motor,
                   MPIMotorIo  *io)
Required Header stdmpi.h
Description

MotorIoSet sets a Motor’s (motor) dedicated I/O bits using data from the structure pointed to by io.

Return Values
MPIMessageOK if MotorIoSet successfully sets the Motor’s dedicated I/O bits using data from the structure
See Also | mpiMotorIoGet


mpiMotorMemory

Declaration
long mpiMotorMemory(MPIMotor  motor,
                    void      **memory)
Required Header stdmpi.h
Description

MotorMemory writes an address [which can be used to access a Motor’s (motor) memory] to the contents of memory. This address, or an address calculated from it, can be passed as the src parameter to MPIMotorMemoryGet(...) and as the dst parameter to MPIMotorMemorySet(...).

Return Values
MPIMessageOK MotorMemory successfully writes the Motor’s address to the contents of memory
See Also | MPIMotorMemoryGet | MPIMotorMemorySet


mpiMotorMemoryGet

Declaration
long mpiMotorMemoryGet(MPIMotor motor,
                       void     *dst,
                       void     *src,
                       long     count)
Required Header stdmpi.h
Description

MotorMemoryGet copies count bytes of a Motor’s (motor) memory (starting at address src) to application memory (starting at address dst).
Return Values
MPIMessageOK if MotorMemoryGet successfully copies data from Motor memory to application memory
See Also | mpiMotorMemorySet | mpiMotorMemory


mpiMotorMemorySet

Declaration
long mpiMotorMemorySet(MPIMotor motor,
                       void     *dst,
                       void     *src,
                       long     count)
Required Header stdmpi.h
Description

MotorMemorySet copies count bytes of application memory (starting at address src) to a Motor’s (motor) memory (starting at address dst).

Return Values
MPIMessageOK if MotorMemorySet successfully copies data from application memory to Motor memory
See Also | mpiMotorMemoryGet | mpiMotorMemory


meiMotorMultiTurnReset

Declaration
long meiMotorMultiTurnReset(MPIMotor    motor);
Required Header stdmei.h
Description

MotorMultiTurnReset clears the SynqNet drive multi-turn data for absolute type encoders. This is only needed when configuring the zero location for an absolute encoder or when the absolute encoder's battery is replaced. meiMotorMultiTurnReset is an offline operation. Make sure all motors (amp enables) are disabled before executing a multi-turn reset. The SynqNet network may be shutdown (dropped from SYNQ mode) due to specific drive limitations.

Not all SynqNet drives support or require this feature. Please see the drive manufacturer's documentation for details.

motor | a handle to the Motor object
Return Values
MPIMessageOK if MotorMultiTurnReset successfully ...
See Also


mpiMotorNumber

Declaration
long mpiMotorNumber(MPIMotor motor,
                    long     *number)
Required Header stdmpi.h
Description

MotorNumber writes the index of a Motor (motor, on the motion controller that motor is associated with) to the contents of number.

Return Values
MPIMessageOK if MotorNumber successfully writes the Motor’s index to the contents of number
See Also


mpiMotorStatus / meiMotorStatus

mpiMotorStatus
Declaration
long mpiMotorStatus(MPIMotor    motor,
                    MPIStatus   *status,
                    void        *external)
Required Header stdmpi.h
Description

MotorStatus writes a Motor’s (motor) status into the structure pointed to by status, and also into the implementation-specific structure pointed to by external (if external is not NULL).

The motor’s status information in external is in addition to the motor’s status information in status, i.e, the status configuration information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).

motor | a handle to the Motor object
*status | a pointer to the motor status structure returned by the method
*external | external either points to a structure of type MEIMotorStatus{…} or is NULL
Return Values
MPIMessageOK if MotorStatus successfully gets the status of a Motor object.
See Also | MPIStatus | MEIMotorStatus

meiMotorStatus
Declaration
long meiMotorStatus(MPIControl   control,
                    long         motorNumber
                    MPIStatus    *status,
                    void         *external)
Required Header stdmei.h
Description

MotorStatus gets a Motor's status and writes it to the structure pointed to by status, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

control | a handle to the Control object
motorNumber | index to the motor
*status | a pointer to the motor status structure returned by the method
*external | external either points to a structure of type MEIMotorStatus{…} or is NULL
Return Values
MPIMessageOK if MotorStatus successfully gets the status of a Motor object.
See Also | MPIStatus | MEIMotorStatus


mpiMotorValidate

Declaration
long mpiMotorValidate(MPIMotor motor)
Required Header stdmpi.h
Description

MotorValidate validates a Motor object and its handle (motor).
Return Values
MPIMessageOK if Motor is a handle to a valid object.
See Also | mpiMotorCreate | mpiMotorDelete


Working with Absolute Encoders

.

Working with Absolute Encoders

Currently, only absolute motor encoders of Yaskawa SGDM Sigma Series II Servopacks are supported by the MPI. Custom firmware is needed in order to use these absolute encoders. Contact MEI for more information.

The encoders are automatically interrogated at power-up or after a controller reset. Axis Origin and Command Positions are set to correctly reflect the absolute position of the motor with no position error initially. The absolute position is the position within a single revolution.

The encoder interrogation is controlled by a SEN signal (to the drive) which must be connected to a configured XMP Transceiver or User Out signal. There are no restrictions as to which XMP signal is used except that current drive limitations may limit the number of drives connected to the same XMP signal.

The MEIMotorEncoder{} structure has been added to the MEIMotorConfig{} object:

typedef struct MEIMotorEncoder {
    MEIXmpEncoderType     type;
    long                  countsPerRev;
} MEIMotorEncoder;

typedef struct MEIMotorConfig {
    MEIMotorEncoder    Encoder[MEIXmpMotorEncoders];
    MEIXmpIO           StatusOutput[MEIXmpMotorStatusOutputs];

    MEIMotorTransceiver     Transceiver[MEIXmpMotorTransceivers];
    long                    UserOutInvert;     /* Opto Polarity */
    MEIMotorStepper         Stepper;
    long                    EncoderTermination;

    /* Commutation is read-only from field Theta to end*/
    MEIXmpCommutationBlock     Commutation;

    MEIXmpLimitData     Limit[MEIXmpLimitLAST];

    MEIMotorFilterInput     FilterInput[MEIXmpMotorFilterInputs];
} MEIMotorConfig;

Return to Motor Objects page


Special Note: Using mpiMotorConfigSet with Absolute Encoders

All absolute encoder configuration through the MPI is made using mpiMotorConfigSet() calls. The below sample code demonstrates the correct way to configure the XMP for Yaskawa absolute encoders.

When using a motor's User Output:

returnValue =
    mpiMotorFlashConfigGet(motor,
                   NULL,
                   &motorConfig,
                   &motorConfigMEI);

    motorConfig.encoderPhase = TRUE; /* Reverse */

    /* Config User Output for SEN line */
    motorConfigMEI.UserOutInvert = TRUE;

    motorConfigMEI.Encoder[0].type = MEIXmpEncoderTypeABS_0; /* Yaskawa encoder */
    motorConfigMEI.Encoder[0].countsPerRev = 65536;		 /* 65536 for 16-bit
                            encoders,131072 for 17-bit */

    returnValue =
        mpiMotorFlashConfigSet(motor,
                       NULL,
                       &motorConfig,
                       &motorConfigMEI);
    msgCHECK(returnValue);

    returnValue =
        mpiMotorConfigSet(motor,
                  &motorConfig,
                  &motorConfigMEI);
    msgCHECK(returnValue);

When using a motor's Transceiver Output:

returnValue =
        mpiMotorFlashConfigGet(motor,
                       NULL,
                       &motorConfig,
                       &motorConfigMEI);

    motorConfig.encoderPhase = TRUE; /* Reverse */

    /* Config transceiver for SEN line */
    motorConfigMEI.Transceiver[0].Config = MEIMotorTransceiverConfigOUTPUT;
    motorConfigMEI.Transceiver[0].Invert = TRUE;

    motorConfigMEI.Encoder[0].type = MEIXmpEncoderTypeABS_0; /* Yaskawa encoder */
    motorConfigMEI.Encoder[0].countsPerRev = 65536;		 /* 65536 for 16-bit
                            encoders,  131072 for 17-bit */
returnValue =
        mpiMotorFlashConfigSet(motor,
                       NULL,
                       &motorConfig,
                       &motorConfigMEI);
    msgCHECK(returnValue);

    returnValue =
        mpiMotorConfigSet(motor,
                      &motorConfig,
                      &motorConfigMEI);

In the above sample code, the steps for configuration are:
  1. Choose a transceiver, or User Opto, to be used for the encoders SEN line. The only restriction is that this transceiver must be on the same controller as the absolute encoder (not necessarily the same Motion Block).
  2. Get the current motor configuration from flash memory.
  3. Configure the encoder phase for the absolute encoder to Reverse.
  4. For a User Opto, configure UserOutInvert to be TRUE. When using a transceiver, configure for Output, and Inverted.
  5. Configure the encoder type and counts per revolution.
  6. Save the current motor configuration from flash memory.
Once configured, the initialization of all axes associated with the motors having absolute encoders is automatic at power up or reset. The SEN line is toggled and the origin and command position are calculated and set from the absolute data sent by the drive.
IMPORTANT NOTE:
The drive must be powered but should not be enabled.

Determining the countPerRev Parameter

The magnitude countsPerRev parameter is detemined by the number of encoder counts (after quadrature) for one revolution of the motor. The sign of the countsPerRev is derimined by the direction for positive rotation for the motor. For Yaskawa drives this is determined by the drive parameter P000.0. P000.0 = 0 (“Standard Rotation”, factory default setting) will cause the motor to move in a counter-clockwise (CCW) direction for positive increases in encoder counts. For Standard Rotation (Pn000.0 = 0) the countPerRev parameter should be positive.

P000.0 = 1 (“Reverse Rotation”) will cause the motor to move in a clockwise (CCW) direction for positive increases in encoder counts. For Reverse Rotation the countsPerRev parameter should be negative.

For example the following code would be used for a drive congfigured for Standard Rotation where the number of counts for one revolution of the motor shaft is 8,192:

motorConfigMEI.Encoder[0].countsPerRev = 8192;

If the same drive were configured for Reverse Rotation the code would be:

motorConfigMEI.Encoder[0].countsPerRev = -8192;

For both Standard and Reverse Rotation the encoderPhase parameter should be TRUE (encoder reversed).

Return to mpiMotorConfigSet


Special Note: MPIMotorEventConfig and Motor Limit Configuration

.

Special Note: MPIMotorEventConfig and Motor Limit Configuration

Two fields, directionFlag and duration, are built into the MPIMotorEventConfig{} structure. From motor.h:

typedef enum {
    MPIMotorEncoderFaultMaskNONE     = 0x0,

    MPIMotorEncoderFaultMaskBW_DET   = mpiMotorEncoderFaultMaskBIT(MPIMotorEncoderFaultBW_DET),
    MPIMotorEncoderFaultMaskILL_DET  = mpiMotorEncoderFaultMaskBIT(MPIMotorEncoderFaultILL_DET),
    MPIMotorEncoderFaultMaskABS_ERR  = mpiMotorEncoderFaultMaskBIT(MPIMotorEncoderFaultABS_ERR),

    MPIMotorEncoderFaultMaskALL      = (mpiMotorEncoderFaultMaskBIT(MPIMotorEncoderFaultLAST) - 1)
} MPIMotorEncoderFaultMask;

typedef union {
    long	polarity;	/* 0 => active low, else active high */
    long	position;	/* MPIEventTypeLIMIT_SW_[POS|NEG] */
    float	error;		/* MPIEventTypeLIMIT_ERROR */
    long	mask;		/* MPIEventTypeENCODER_FAULT */
} MPIMotorEventTrigger;

typedef struct MPIMotorEventConfig {
    MPIAction               action;
    MPIMotorEventTrigger    trigger;
    long                    direction;
    float                   duration;     /* seconds */
} MPIMotorEventConfig;

The directionFlag field is used to configure MPIEventTypeLIMIT_HW_NEG, MPIEventTypeLIMIT_HW_POS, MPIEventTypeLIMIT_SW_NEG, and MPIEventTypeLIMIT_SW_POS. A value of TRUE for this field will force the command direction for motion to be used by the Xmp controller to qualify these limit events. A value of FALSE for this field will cause the limit event to depend on the state of the limit. If the limit has been exceeded (actual position > software positive limit, actual position < software negative limit, positive or negative hardware overtravel is TRUE) the limit event will be based direction of commanded motion, in exactly the same way as for directionFlag = TRUE. If the limit has not been exceeded the limit event and status will be based solely on the limit input (hardware limits) or actual position (software limits), ignoring the direction of commanded motion. The default status of durationFlag is FALSE (ignore direction). The directionFlag is ignored (returned FALSE from “get” methods) for case MPIEventTypeAMP_FAULT, MPIEventTypeHOME, and MPIEventTypeLIMIT_ERROR.

The duration field may used in the configuration of all MPI Motor Events. A positive value for this field will require the limit condition to exist for duration seconds before an event will occur. This field is useful in overriding noisy limit inputs. For example, an overtravel limit with infrequent short (< 1msec) noise spikes on the limit input will ignore the noise of the limit is configured with a duration of 0.05. A spike whose duration was at least 0.05 seconds (50 milliseconds) would be required before an overtravel event would occur. The default value for duration is 0.0.

Return to MPIMotorEventConfig


Notify Objects

.

Notify Objects

Introduction

A thread uses a Notify object to wait for event notification. For each thread intended to wait for events from an object (or objects), your application must create a Notify object. The source of firmware events are Motion, Sequence, and Recorder objects.

When it is desired to wait for event notifications from a single source, that source (i.e., object handle) can be passed as the second argument to mpiNotifyCreate(...). After a Notify object is appended to the EventMgr list of Notify objects, make a call to mpiNotifyEventWait(...) to instruct the Notify object to wait for event notification.

Methods

Create, Delete, Validate Methods
 | mpiNotifyCreate | Create a Notify object
 | mpiNotifyDelete | Delete a Notify object
 | mpiNotifyValidate | Validate a Notify object

Event Methods
 | mpiNotifyEvent | Check to see if events have occurred
 | mpiNotifyEventFlush | Flush pending events from event queue
 | mpiNotifyEventMaskGet | Get event mask
 | mpiNotifyEventMaskSet | Set event mask
 | mpiNotifyEventWait | Get next event from queue or wait timeout msec for it to arrive
 | mpiNotifyEventWake | Wake up thread waiting for notify object

Relational Methods
 | List Methods for Event Sources
 | mpiNotifySource | Get the indexth event source in list
 | mpiNotifySourceAppend | Append an event source to list
 | mpiNotifySourceCount | Count number of event sources in list
 | mpiNotifySourceFirst | Get first event source in list
 | mpiNotifySourceIndex | Get index value for event source in list
 | mpiNotifySourceInsert | Place event source after source in list
 | mpiNotifySourceLast | Get last event source in list
 | mpiNotifySourceListGet | Get list of event sources
 | mpiNotifySourceListSet | Create a list of event sources
 | mpiNotifySourceNext | Get next event source after source in list
 | mpiNotifySourcePrevious | Get the event source before source in list
 | mpiNotifySourceRemove | Remove event source from list

Data Types

MPINotifyMessage
MEINotifyTrace


MPINotifyMessage

MPINotifyMessage

typedef enum {

    MPINotifyMessageNOTIFY_INVALID,
    MPINotifyMessageWAIT_IN_PROGRESS,
} MPINotifyMessage;

Description
MPINotifyMessageNOTIFY_INVALID
 | The notify object is not valid. This message code is returned by a notify method if the notify object handle is not valid. This problem can be caused by failed mpiNotifyCreate(…). To prevent this problem, check your notify objects after creation by using mpiNotifyValidate(…).
MPINotifyMessageWAIT_IN_PROGRESS
 | The notify object is waiting for an event. This message code is returned by mpiNotifyEventWait(…) if the notify object is already waiting for an event in another thread. To prevent this problem, make sure a thread does not share notify objects with other threads.
Sample Code
MPIControl    control;
MPINotify      notify;
long              returnValue;
…

notify =
    mpiNotifyCreate(control);
returnValue =
    mpiNotifyValidate(notify);

See Also | MPINotify | mpiNotifyCreate | mpiNotifyValidate


MEINotifyTrace

MEINotifyTrace

typedef enum {

    MEINotifyTraceTHREAD,
} MEINotifyTrace;
Description
MEINotifyTraceTHREAD will display trace information when notify objects are set to wait, are finished waiting, and when they are signaled to wake.
See Also


mpiNotifyCreate

Declaration
MPINotify mpiNotifyCreate(MPIEventMask mask,
                          void         *source)
Required Header stdmpi.h
Description

NotifyCreate creates a Notify object that will accept event notifications for the events that are specified in mask. The source argument specifies the initial element in the list of event sources, from which event notification will be accepted. If source is NULL, then event notification will be accepted from all event sources. NotifyCreate is the equivalent of a C++ constructor.

Return Values
handle | to a Notify object
MPIHandleVOID | if the object could not be created

See Also | mpiNotifyDelete | mpiNotifyValidate


mpiNotifyDelete

Declaration
long mpiNotifyDelete(MPINotify notify)
Required Header stdmpi.h
Description

NotifyDelete deletes a Notify object and invalidates its handle (notify). NotifyDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if NotifyDelete successfully deletes a Notify object and invalidates its handle
See Also | mpiNotifyCreate | mpiNotifyValidate


mpiNotifyEvent

Declaration
long mpiNotifyEvent(MPINotify      notify,
                    MPIEventStatus *status)
Required Header stdmpi.h
Description

NotifyEvent first checks to see if the type field of status matches a bit in the event mask maintained by a Notify object (notify).

IF
the type field of status matches a bit in the event mask,

AND
the event source list maintained by the Notify object (notify) is empty or the source field of status matches a source in the event source list,

THEN
a Notify object (notify) will place the event in a FIFO event queue and signal that an event has been received.

If a thread is waiting for event notification (after having called mpiNotifyEventWait(notify)), the signal will awaken it. Otherwise, the next call to mpiNotifyEventWait(notify) will return immediately with status.

Return Values
MPIMessageOK if the Notify object (notify) successfully places the event in a FIFO event queue and signals that an event has been received
See Also | mpiNotifyEventWait


mpiNotifyEventFlush

Declaration
long mpiNotifyEventFlush(MPINotify   notify)

Required Header

 stdmpi.h
Description

NotifyEventFlush flushes any pending events from the internal FIFO event queue maintained by a Notify object (notify).

Return Values
MPIMessageOK if NotifyEventFlush successfully flushes the pending events from the internal FIFO event queue maintained by the Notify object
See Also


mpiNotifyEventMaskGet

Declaration

long mpiNotifyEventMaskGet(MPINotify    notify,
                           MPIEventMask *mask)
Required Header stdmpi.h
Description

NotifyEventMaskGet writes an event mask (that specifies the event type(s) for which event notification is accepted by a Notify object (notify)) to the location pointed to by mask.
Return Values
MPIMessageOK if NotifyEventMaskGet successfully writes the event mask to the location pointed to by mask
See Also | mpiNotifyEventMaskSet


mpiNotifyEventMaskSet

Declaration
long mpiNotifyEventMaskSet(MPINotify    notify,
                           MPIEventMask mask)
Required Header stdmpi.h
Description

NotifyEventMaskSet sets the event type(s) for which notification will be accepted by a Notify object (notify), as specified by mask.

Event notification is accepted for event types specified in mask, a bit mask of MPIEventMask bits (associated with the desired MPIEventType values). The MPIEventMask bits must be set or cleared using the MPIEventMask macros. Event notification is denied for event types not specified in mask.

Return Values
MPIMessageOK if NotifyEventMaskSet successfully sets the event type(s) for which notification will be accepted by a Notify object
See Also | MPIEventType | mpiNotifyEventMaskGet


mpiNotifyEventWake

Declaration
long mpiNotifyEventWake(MPINotify      notify,
                        MPIEventStatus *status)
Required Header stdmpi.h
Description

NotifyEventWake wakes a thread that is waiting for an event notification from a Notify object (notify). The awakened thread will return from its call to mpiNotifyEventWait(notify, status, timeout) with the contents of status set to the contents of status. If status is NULL, status will indicate an event of type MPIEventTypeNONE.

NotifyEventWake is different from NotifyEvent, because event notification is not accepted based on the event type or source (NotifyEvent); instead event notification is always accepted (NotifyEventWake).

Return Values
MPIMessageOK if NotifyEventWake successfully wakes a thread that is waiting for an event notification from a Notify object
See Also | mpiNotifyEventWait | MPIEventType


mpiNotifyEventWait

Declaration
long mpiNotifyEventWait(MPINotify      notify,
                        MPIEventStatus *status,
                        MPIWait        timeout)
Required Header stdmpi.h
Description

NotifyEventWait sets the contents of the structure pointed to by status, using the status of the first event in the internal FIFO event queue (maintained by a Notify object (notify)), and then removes the first event from the queue. If no event is available in the internal FIFO event queue, NotifyEventWait will wait for timeout milliseconds.

If "timeout" is | Then
MPIWaitPOLL (0) | NotifyEventWait will not wait for an event to arrive
MPIWaitFOREVER (-1) | NotifyEventWait will wait forever for an event to arrive

Return Values
MPIMessageOK | if NotifyEventWait successfully sets the contents of the structure pointed to by status, and then removes the first event from the queue
MPIMessageTIMEOUT | if no event is present and the contents of status are undefined

See Also | mpiNotifyEventWake


mpiNotifySource

Declaration
void* mpiNotifySource(MPINotify notify,
                      long      index)
Required Header stdmpi.h
Description

NotifySource returns the element at the position on the list indicated by index.

notify | a handle to the Notify object.
index | a position in the list.

Return Values
indexth event source | in the event source list maintained by a Notify object (notify)
NULL | if notify is invalid if index is less than 0 if index is greater than or equal to mpiNotifySourceCount(notify)
MPIMessageARG_INVALID | if index is a negative number.
MEIListMessageELEMENT_NOT_FOUND | if index is greater than or equal to the number of elements in the list.
MPIMessageHANDLE_INVALID | if notify is an invalid handle.
See Also


mpiNotifySourceAppend

Declaration
long mpiNotifySourceAppend(MPINotify notify,
                           void      *source)
Required Header stdmpi.h
Description

NotifySourceAppend appends an event source (source) to the list of event sources maintained by a Notify object (notify).

notify | a handle to the Notify object.
source | a pointer with an arbitrary (but non-NULL) value.

Return Values
MPIMessageOK | if NotifySourceAppend successfully appends source to the list of event sources maintained by a Notify object
MPIMessageHANDLE_INVALID | Either source is NULL or notify is an invalid handle.
MPIMessageNO_MEMORY | Not enough memory was available.
See Also


mpiNotifySourceCount

Declaration
long mpiNotifySourceCount(MPINotify notify)
Required Header stdmpi.h
Description

NotifySourceCount returns the number of elements on the list.

notify | a handle to the Notify object.

Return Values
number of event sources | in the event source list maintained by a Notify object (notify)
-1 | if notify is invalid
0 | if the event source list is empty
See Also


mpiNotifySourceFirst

Declaration
void* mpiNotifySourceFirst(MPINotify notify)
Required Header stdmpi.h
Description

NotifySourceFirst returns the first element in the list. This function can be used in conjuntion with mpiNotifySourceNext() in order to iterate through the list.

notify | a handle to the Notify object.

Return Values
first event source | in the event source list maintained by a Notify object (notify)
NULL | if notify is invalid or if the event source list is empty
MPIMessageHANDLE_INVALID | if notify is an invalid handle.

See Also | mpiNotifySourceNext | mpiNotifySourceLast


mpiNotifySourceInsert

Declaration
long mpiNotifySourceInsert(MPINotify notify,
                           void      *source,
                           void      *insert)
Required Header stdmpi.h
Description

NotifySourceInsert places the event source (pointed to by insert) after a specified event source (source), in the list of event sources that are maintained by a Notify object (notify).
Return Values
MPIMessageOK if NotifySourceInsert successfully places the event source after the specified event source, in the list of event sources that are maintained by a Notify object
See Also


mpiNotifySourceIndex

Declaration
long mpiNotifySourceIndex(MPINotify notify,
                          void      *source)
Required Header stdmpi.h
Description

NotifySourceIndex returns the position of source on the list.

notify | a handle to the Notify object.
source | a pointer with an arbitrary (but non-NULL) value.

Return Values
index of source | in the event source list maintained by a Notify object (notify)
-1 | if notify is invalid if the event source (source) was not found in the event source list
See Also


mpiNotifySourceLast

Declaration
void* mpiNotifySourceLast(MPINotify notify)
Required Header stdmpi.h
Description

NotifySourceLast returns the last element in the list. This function can be used in conjuntion with mpiNotifySourcePrevious() in order to iterate through the list backwards.

notify | a handle to the Notify object.

Return Values
last event source | in the list maintained by a Notify object (notify)
NULL | if notify is invalid if the event source list is empty

See Also | mpiNotifySourcePrevious | mpiNotifySourceFirst


mpiNotifySourceListGet

Declaration
long mpiNotifySourceListGet(MPINotify notify,
                            long      *sourceCount,
                            void      **sourceList)
Required Header stdmpi.h
Description

NotifySourceListGet returns the event source list for a Notify object (notify). NotifySourceListGet writes the number of event sources in the event source list to the location (pointed to by sourceCount), and also writes an array of sourceCount event source pointers to the location (pointed to by sourceList).

Return Values
MPIMessageOK if NotifySourceListGet successfully returns the event source list for a Notify object
See Also | mpiNotifySourceListSet | NotifySourceAppend | NotifySourceInsert | mpiNotifyCreate


mpiNotifySourceListSet

Declaration
long mpiNotifySourceListSet(MPINotify notify,
                            long      sourceCount,
                            void      **sourceList)
Required Header stdmpi.h
Description

NotifySourceListSet creates an event source list of length sourceCount, using the source pointers specified by sourceList. The sourceList argument is the address of an array of sourceCount event source pointers, or is NULL (if sourceCount = 0). Any existing event source list is completely replaced after using NotifySourceListSet.

You can also create an event source list incrementally (i.e., created one source at a time) by using NotifySourceAppend/Insert methods. To specify the first event source of a list, use the source argument of mpiNotifyCreate(...). Use the NotifySourceList methods to examine and manipulate an event source list, regardless of how you created it.
Return Values
MPIMessageOK if NotifySourceListSet successfully creates an event source list using the source pointers specified by sourceList
See Also | NotifySourceAppend | NotifySourceInsert | mpiNotifyCreate | mpiNotifySourceListGet


mpiNotifySourceNext

Declaration
void * mpiNotifySourceNext(MPINotify  notify,
                           void       *source)
Required Header stdmpi.h
Description

NotifySourceNext returns the next element following "source" on the list. This function can be used in conjuntion with mpiNotifySourceFirst() in order to iterate through the list.

notify | a handle to the Notify object.
source | a pointer with an arbitrary (but non-NULL) value.

Return Values
event source | before the event source (source) in the event source list maintained by a Notify object (notify)
NULL | if notify is invalid if the event source (source) is the first event source in the event source list
MPIMessageHANDLE_INVALID | Either source is NULL or notify is an invalid handle.

See Also | mpiNotifySourcePrevious


mpiNotifySourcePrevious

Declaration
void * mpiNotifySourcePrevious(MPINotify notify,
                               void      *source)
Required Header stdmpi.h
Description

NotifySourcePrevious returns the previous element prior to "source" on the list. This function can be used in conjuntion with mpiNotifySourceLast() in order to iterate through the list backwards.

notify | a handle to the Notify object.
source | a pointer with an arbitrary (but non-NULL) value.

Return Values
event source | before the event source (source) in the event source list maintained by a Notify object (notify)
NULL | if notify is invalid if the event source (source) is the first event source in the event source list
MPIMessageHANDLE_INVALID | Either source is NULL or notify is an invalid handle.

See Also | mpiNotifySourceNext


mpiNotifySourceRemove

Declaration
long mpiNotifySourceRemove(MPINotify notify,
                           void      *source)
Required Header stdmpi.h
Description

NotifySourceRemove removes an event source (source) from the list of event sources maintained by a Notify object (notify).

Return Values
MPIMessageOK if NotifySourceRemove successfully removes the event source (source) from the list of event sources maintained by a Notify object
See Also


mpiNotifyValidate

Declaration
long mpiNotifyValidate(MPINotify notify)
Required Header stdmpi.h
Description

NotifyValidate validates a Notify object and its handle (notify).
Return Values
MPIMessageOK if Notify is a handle to a valid object.
See Also | mpiNotifyCreate | mpiNotifyDelete


Object Objects

.

Object Objects

Introduction

Each Object shares some common functionality with other objects. The Object module encapsulates the common object methods and macros into a single module. This makes object handling consistent and more efficient.

Methods

Create, Delete, Validate Methods
mpiObjectValidate

Configuration and Information Methods
 | mpiObjectModuleId
 | mpiObjectTimeoutGet
 | mpiObjectTimeoutSet
 | meiObjectTraceGet
 | meiObjectTraceSet

Data Types

MPIObjectMap

Macros

mpiObjectMapAND_ASSIGN
mpiObjectMapASSIGN
mpiObjectMapBitCountMAX
mpiObjectMapBitGET
mpiObjectMapBitSET
mpiObjectMapCLEAR
mpiObjectMapCOMPLEMENT
mpiObjectMapIS_CLEAR
mpiObjectMapIS_EQUAL
mpiObjectMapIS_VALID
mpiObjectMapMAX
mpiObjectMapOR_ASSIGN
meiObjectTraceGET
meiObjectTraceSET


MPIObjectMap

MPIObjectMap

typedef unsigned long	MPIObjectMap;
Description
MPIObjectMap A map of MPI objects. An ObjectMap is a bitmap, where each numbered bit represents the presence or absence of the correspondingly numbered object. Valid maps are Axis/Filter and Filter/Motor. The Axis/Filter map can also be read, but setting this map must be done through the corresponding Filter objects.
See Also


mpiObjectMapAND_ASSIGN

Declaration

#define	  mpiObjectMapAND_ASSIGN(dst,src)	((dst) &= (src))
Required Header stdmpi.h
Description

Bitwise ANDs the dst object map with the src object map and assigns the result to dst.

See Also | mpiObjectMapASSIGN


mpiObjectMapASSIGN

Declaration

#define	   mpiObjectMapASSIGN(dst,src)	 ((dst) = (src))
Required Header stdmpi.h
Description

ObjectMapASSIGN assigns src object map to the dst object map.

See Also | mpiObjectMapAND_ASSIGN


mpiObjectMapBitCountMAX

Declaration
#define   mpiObjectMapBitCountMAX(objectMap)
                                 (sizeof(objectMap) * 8)
Required Header stdmpi.h
Description

ObjectMapBitCountMAX calculates the maximum bit count for the specified object objectMap.
See Also


mpiObjectMapBitGET

Declaration

#define mpiObjectMapBitGET(objectMap,bit)(((objectMap) &  (0x1 << (bit))) ? 1 : 0)
Required Header stdmpi.h
Description

ObjectMapBitGET gets the bit number's state for the specified object map.

See Also | mpiObjectMapBitSET


mpiObjectMapBitSET

Declaration
#define  mpiObjectMapBitSET(objectMap,bit,value) \
            (((value) == 0) \
                 ? ((objectMap) &= ~(0x1 << (bit))) \
                 : ((objectMap) |=  (0x1 << (bit))))
Required Header stdmpi.h
Description

ObjectMapBitSET sets object map's specified bit number to the specified value.

See Also | mpiObjectMapBitGET


mpiObjectMapCLEAR

Declaration
#define mpiObjectMapCLEAR(objectMap)  ((objectmap) = 0x0)
Required Header stdmpi.h
Description

ObjectMapCLEAR sets the object map to zero.
See Also


mpiObjectMapCOMPLEMENT

Declaration
#define mpiObjectMapCOMPLEMENT(objectMap)
                             ((objectMap) = ~(objecMap))
Required Header stdmpi.h
Description

ObjectMapCOMPLEMENT performs bitwise complement to the object map and assigns the result to objectMap.
See Also


mpiObjectMapIS_CLEAR

Declaration
#define mpiObjectMapIS_CLEAR(objectMap) ((objectMap) == 0x0)
Required Header stdmpi.h
Description

ObjectMapIS_CLEAR compares the map to 0x0. If the map is zero, it returns a non-zero value.
See Also


mpiObjectMapIS_EQUAL

Declaration

#define	  mpiObjectMapIS_EQUAL(map1,map2)	((map1) == (map2))
Required Header stdmpi.h
Description

ObjectMapIS_EQUAL compares map1 to map2. If the maps are equal, it returns a non-zero value.
See Also


mpiObjectMapIS_VALID

Declaration
#define  mpiObjectMapIS_VALID(objectMap,count) \
        (((count) >= (sizeof(objectMap) * 8)) || \
        (((~((0x1 << (count)) - 1)) & (objectMap)) == 0))
Required Header stdmpi.h
Description

ObjectMapIS_VALID checks if the map is within the count range. If the map is valid, it returns a non-zero value.
See Also


mpiObjectMapMAX

Declaration

#define mpiObjectMapMAX(objectMap,count)
                      ((objectMap) = (0x1 << (count)) - 1)
Required Header stdmpi.h
Description

ObjectMapMAX calculates the maximum object objectMap with the specified count.
See Also


mpiObjectMapOR_ASSIGN

Declaration
#define    mpiObjectMapOR_ASSIGN(dst,src)    ((dst) |= (src))
Required Header stdmpi.h
Description

Bitwise ORs the dst object map with the src object map and assigns the result to dst.

See Also | mpiObjectMapASSIGN


mpiObjectModuleId

Declaration
long mpiObjectModuleId(MPIHandle    handle,
                       MPIModuleId  *moduleId)
Required Header stdmpi.h
Description

The ObjectModuleId function writes the MPIModuleId of the object (handle) to the location pointed to by moduleId.
Return Values
MPIMessageOK if ObjectModuleId successfully writes the MPIModuleId to the location
See Also


mpiObjectTimeoutGet

Declaration
long mpiObjectTimeoutGet(MPIHandle handle,
                         MPIWait   *timeout)
Required Header stdmpi.h
Description

The ObjectTimeoutGet method gets the timeout value for the object (handle), and writes it to the location pointed to by timeout.
Return Values
MPIMessageOK if ObjectTimeoutGet successfully writes the timeout value to the location
See Also | mpiObjectTimeoutSet


mpiObjectTimeoutSet

Declaration
long mpiObjectTimeoutSet(MPIHandle handle,
                         MPIWait   timeout)
Required Header stdmpi.h
Description

ObjectTimeoutSet sets the timeout value for an object (handle) to timeout.

The timeout value is used in a multi-threaded environment when an MPI function must block to wait for a shared resource to become available. The default timeout value is MPIWaitFOREVER.

If "timeout" is | Then
MPIWaitFOREVER | ObjectTimeoutSet will wait until the resource becomes available
MPIWaitPOLL | ObjectTimeoutSet will not wait for the resource to become available. If the shared resource is not available, a timeout will be considered to have occurred.
a value | ObjectTimeoutSet will wait timeout milliseconds for the resource to become available

Return Values
MPIMessageOK | if ObjectTimeoutSet successfully sets the timeout value of the object
MPIMessageTIMEOUT | if a timeout occurs before the shared resource becomes available

See Also | mpiObjectTimeoutGet


meiObjectTraceGet and meiObjectTraceGET

.

meiObjectTraceGet / meiObjectTraceGET

meiObjectTraceGet
Declaration
long meiObjectTraceGet(MPIHandle    handle,
                       MEITraceMask *traceMask)
Required Header stdmei.h
Description

ObjectTraceGet gets an Object's trace mask and writes it to the value pointed to by traceMask.

handle | a handle to an object
*traceMask | a pointer to the value of an object's trace mask
Return Values
MPIMessageOK if ObjectTraceGet successfully gets the trace mask for an object.

meiObjectTraceGET
Declaration

#define  meiObjectTraceGET(object)	(((MEIObject)(object))->trace)
Required Header stdmei.h
Description

ObjectTraceGET gets the object's global trace mask.

See Also | meiObjectTraceSET | meiObjectTraceSet


meiObjectTraceSet and meiObjectTraceSET

.

meiObjectTraceSet / meiObjectTraceSET

meiObjectTraceSet
Declaration
long meiObjectTraceSet(MPIHandle    handle,
                       MEITraceMask traceMask)
Required Header stdmei.h
Description

ObjectTraceSet sets an Object's trace mask to the value specified by traceMask.

handle | a handle to an object
traceMask | the value of an object's trace mask
Return Values
MPIMessageOK if ObjectTraceSet successfully sets the trace mask for an object.

meiObjectTraceSET
Declaration

#define  meiObjectTraceSET(object,mask)
                                (((MEIObject)(object))->trace = (mask))
Required Header stdmei.h
Description

ObjectTraceSET sets the object's global trace mask.

See Also | meiObjectTraceGET | meiObjectTraceGet


mpiObjectValidate

Declaration
long mpiObjectValidate(MPIHandle   handle,
                       MPIModuleId moduleId)
Required Header stdmpi.h
Description

The ObjectValidate method verifies that the object (handle) is of the type moduleId.

Return Values
MPIMessageOK if handle is a handle to a valid object of type moduleId.
See Also


Path Objects

.

Path Objects

Introduction

A Path object manages coordinated multi-axis motion profiles. It is used when the motion profiles in an N-Dimensional space are required to follow a specific coordinated trajectory. Motion paths are constructed with high level linear and arc segments and downloaded to the controller. The controller calculates the real-time individual axis profiles.

Generally, Path motion is used when the trajectory through space is more important than the final target position. Several different algorithms can be applied to convert the linear and arc segment path into an interpolated trajectory.

Path trajectory generation is now supported by PT, PVT, SPLINE, BESSEL, BSPLINE, and BSPLINE2 algorithms. Blending of the corners is only available for the 2 bspline algorithms. Blending of a corner is when the path does not hit the corner but goes through a smooth arc.

Methods

Create, Delete, Validate Methods
 | mpiPathCreate | Create a Path object
 | mpiPathDelete | Delete a Path object
 | mpiPathValidate | Validate a Path object

Configuration and Information Methods
 | mpiPathParamsGet
 | mpiPathParamsSet

Relational Methods
mpiPathAppend

Action Methods
mpiPathMotionParamsGenerate

Data Types

MPIPathArc
MPIPathArcCenter
MPIPathArcEndPoint
MPIPathAttr
MPIPathDirection
MPIPathElement
MPIPathElementAttributes
MPIPathElementAttrMask
MPIPathElementType
MPIPathLine
MPIPathMessage
MPIPathParams
MPIPathPoint

Macros

mpiPathElementTYPE
mpiPathElementAttrMaskBIT
mpiPathElementATTR

Constants

MPIPathPointDIMENSION_MAX


MPIPathArc

MPIPathArc

typedef struct MPIPathArc {
    struct {
        double	start;
        double	included;
    } angle;
    double	radius;
} MPIPathArc;
Description

PathArc specifies the parameters for an arc path element. It supports 2 dimensional arcs only. All arcs start at the end position for the last path element added to the path or the present command position if the arc is the first element in the path.

start | This value defines the arc's starting angle. Units are in degrees.
included | This value defines the relative travel angle. Units are in degrees. Positive values specify counter-clockwise motion and negative values specify clockwise motion.
radius | This value defines the distance from the center to the arc edge. Units are in counts.

See Also | MPIPathElement | MPIPathParams | MPIPathArcCenter


MPIPathArcCenter

MPIPathArcCenter

typedef struct MPIPathArcCenter {
    MPIPathPoint	center;
    double			angle;
} MPIPathArcCenter;
Description

PathArcCenter specifies the parameters for an arc path element. It supports 2 dimensional arcs only. All arcs start at the end position for the last path element added to the path or the present command position if the arc is the first element in the path.

center | This structure defines the coordinates for the center point of the arc. Please see MPIPathPoint data type documentation for more information.
angle | This value defines the relative travel angle. Units are in degrees. Positive values specify counter-clockwise motion and negative values specify clockwise motion.

See Also | MPIPathElement | MPIPathParams | MPIPathArc


MPIPathArcEndPoint

MPIPathArcEndPoint

typedef struct MPIPathArcEndPoint {
    MPIPathPoint		center;
    MPIPathPoint		endPoint;
    MPIPathDirection	direction;
} MPIPathArcEndPoint;
Description

PathArcEndPoint specifies the parameters for an arc path element. It supports 2 dimensional arcs only. All arcs start at the end position for the last path element added to the path or the present command position if the arc is the first element in the path.

center | This structure defines the coordinates for the center point of the arc. Please see MPIPathPoint data type documentation for more information.
endPoint | This structure defines the coordinates for the final point of the arc. Please see MPIPathPoint data type documentation for more information.
direction | This value defines the travel direction, counter-clockwise or clockwise. Please see MPIPathDirection data type documentation for more information.

See Also | MPIPathElement | MPIPathParams | MPIPathDirection


MPIPathAttr

MPIPathAttr

typedef enum {
    MPIPathElementAttrINVALID    = -1,

    MPIPathElementAttrRELATIVE   = MPIPathElementAttrLAST - 1,
    MPIPathElementAttrID         = MPIPathElementAttrLAST - 2,
    MPIPathElementAttrVELOCITY   = MPIPathElementAttrLAST - 3,
    MPIPathElementAttrACCEL      = MPIPathElementAttrLAST - 4,
    MPIPathElementAttrTIMESLICE  = MPIPathElementAttrLAST - 5,
    MPIPathElementAttrCOUNT      = MPIPathElementAttrLAST - MPIPathElementAttrFIRST,
} MPIPathAttr;
Description

In PathAttr, the path attributes are used to generate the path attribute masks to enable features with mpiPathAppend(…). Please see MPIPathElementAttrMask data type for more information.

See Also | mpiPathAppend


MPIPathDirection

MPIPathDirection

typedef enum {
    MPIPathDirectionCW  = -1,
    MPIPathDirectionCCW = 1,
} MPIPathDirection;

Description
 | MPIPathDirectionCW | This value defines the clockwise direction.
 | MPIPathDirectionCCW | This value defines the counter-clockwise direction.

See Also | MPIPathArcEndPoint


MPIPathElement

MPIPathElement

typedef	struct MPIPathElement {
    MPIPathElementType		type;
    long				blending;
    union {
        MPIPathArc		arc;
        MPIPathArcCenter	arcCenter;
        MPIPathArcEndPoint	arcEndPoint;
        MPIPathLine		line;
    } params;

    MPIPathElementAttributes	attributes;
} MPIPathElement;

Description
 | type | This value defines the type of path element. Please see MPIPathElementType{…} data type documentation for more information.
 | blending | This value determines whether the corners of the path are rounded or sharp. When set to TRUE, blending is enabled, causing rounded corners. When set to FALSE, blending is disabled, causing sharp corners.
 | arc | This structure defines the arc's start angle, included angle, and radius. This structure is used when the type is MPIPathElementTypeARC. Please see MPIPathArc data type documentation for more information.
 | arcCenter | This structure defines the arc's center and angle. This structure is used when the type is MPIPathElementTypeARC_CENTER. Please see MPIPathArcCenter data type documentation for more information.
 | arcEndPoint | This structure defines the arc's center, end point, and direction. This structure is used when the type is MPIPathElementTypeARC_END_POINT. Please see MPIPathArcEndPoint data type documentation for more information.
 | line | This structure defines the coordinates for a linear element. This structure is used when the type is MPIPathElementTypeLINE. Please see MPIPathLine data type documentation for more information.
 | attributes | This structure defines the attributes for a path element. Please see MPIPathElementAttributes data type documentation for more information.

See Also | mpiPathAppend


MPIPathElementAttrMask

MPIPathElementAttrMask

typedef	enum {
    MPIPathElementAttrMaskRELATIVE,   = mpiPathElementAttrMaskBIT(MPIPathElementAttrRELATIVE),
    MPIPathElementAttrMaskID,         = mpiPathElementAttrMaskBIT(MPIPathElementAttrID),
    MPIPathElementAttrMaskVELOCITY,   = mpiPathElementAttrMaskBIT(MPIPathElementAttrVELOCITY),
    MPIPathElementAttrMaskACCEL,      = mpiPathElementAttrMaskBIT(MPIPathElementAttrACCEL),
    MPIPathElementAttrMaskTIMESLICE,  = mpiPathElementAttrMaskBIT(MPIPathElementAttrTIMESLICE),

    MPIPathElementAttrMaskALL         = -1 << MPIPathElementAttrFIRST,
} MPIPathElementAttrMask;
Description

In PathElementAttrMask, the path attribute masks are used to enable features with mpiPathAppend(…). The masks are ORed with the MPIPathElementType to enable each feature.

MPIPathElementAttrMaskRELATIVE | This mask enables relative coordinates for path motion. This feature is not supported and is reserved for future use.
MPIPathElementAttrMaskID | This mask enables an identification tag to be stored in the path. Each element can have a unique identification. Please see MPIPathElementAttributes{…} data type documentation for more information.
MPIPathElementAttrMaskVELOCITY | This mask enables a path velocity to be specified for each element. Please see MPIPathElementAttributes{…} data type documentation for more information.
MPIPathElementAttrMaskACCEL | This mask enables a path acceleration to be specified for each element. Please see MPIPathElementAttributes{…} data type documentation for more information.

See Also | MPIPathElementType | mpiPathAppend


MPIPathElementAttributes

MPIPathElementAttributes

typedef struct MPIPathElementAttributes {
    long	id;					/* MPIPathAttrID			*/
    double	velocity;			/* MPIPathAttrVELOCITY		*/
    double	acceleration;		/* MPIPathAttrACCELERATION	*/
    double	timeSlice;			/* MPIPathAttrTIMESLICE		*/
} MPIPathElementAttributes;
Description

In PathElementAttributes, the path attributes define the parameters to be used when specific features are enabled with the path element attribute masks. When using these attributes, be sure to enable the feature with the appropriate MPIPathElementAttrMask{…}.

id | This value defines an identification number to be stored in the path element. During path profile execution, at the start of each element the controller loads the id into the axis' ElementID field. The application can query the controller's axis memory to monitor the path element execution.
velocity | This value defines the velocity for the path element.
acceleration | This value defines the acceleration for the path element.
timeSlice | This value defines the time between interpolation points for the path element. The practical range for the time slice is from 10 msec (.01) to 100 msec (.1). Larger time slice values produce smoother (lower acceleration), less accurate paths. Smaller time slice values produce more accurate (both position and velocity) paths with higher peak accelerations.

See Also | MPIPathElementAttrMask


MPIPathElementType

MPIPathElementType

typedef enum {
    MPIPathElementTypeINVALID,

    MPIPathElementTypeARC,  /* only 2D */
    MPIPathElementTypeARC_CENTER,  /* only 2D */
    MPIPathElementTypeARC_END_POINT, /* both 2D and 3D */
    MPIPathElementTypeHELIX, /* not currently supported */
    MPIPathElementTypeIO, /* not currently supported */
    MPIPathElementTypeLINE, /* both 2D and 3D */

    MPIPathElementTypeMASK,
} MPIPathElementType;

Description
 | MPIPathElementTypeARC | This type generates an arc specified by the arc's start angle, included angle, and radius.
 | MPIPathElementTypeARC_CENTER | This type generates an arc specified by the arc's center and angle.
 | MPIPathElementTypeARC_END_POINT | This type generates an arc specified by the arc's center, end point, and direction.
 | MPIPathElementTypeLINE | This type generates a line specified by the position coordinates.

See Also | MPIPathArc | MPIPathLine


MPIPathLine

MPIPathLine

typedef struct MPIPathLine {
    MPIPathPoint	point;
} MPIPathLine;
Description

PathLine specifies the parameters for a linear path element. It supports up to MPIPathPointDIMENSION_MAX dimensions. All lines start at the end position for the last path element added to the path or the present command position if the line is the first element in the path.

point | This structure defines the end point coordinates for the linear segment.

See Also | MPIPathElement | MPIPathParams | MPIPathPointDIMENSION_MAX


MPIPathMessage

MPIPathMessage

typedef enum {

    MPIPathMessagePATH_INVALID,
    MPIPathMessageILLEGAL_DIMENSION,
    MPIPathMessageILLEGAL_ELEMENT,
    MPIPathMessageARC_ILLEGAL_DIMENSION,
    MPIPathMessageHELIX_ILLEGAL_DIMENSION,
    MPIPathMessageILLEGAL_RADIUS,
    MPIPathMessagePATH_TOO_LONG,
    MPIPathMessageILLEGAL_VELOCITY,
    MPIPathMessageILLEGAL_ACCELERATION,
    MPIPathMessageILLEGAL_TIMESLICE,
    MPIPathMessageINVALID_BLENDING,
} MPIPathMessage;

Description
MPIPathMessagePATH_INVALID
 | The path object is not valid. This message code is returned by a path method if the path object handle is not valid. This problem can be caused by a failed mpiPathCreate(…). To prevent this problem, check your path objects after creation by using mpiPathValidate(…).
MPIPathMessageILLEGAL_DIMENSION
 | The path dimensions are not valid. This message code is returned by mpiPathParamsSet(…) or mpiPathMotionParamsGenerate(…) if the path dimension is less than one or greater than or equal to MPIPathPointDIMENSION_MAX. Also, this message code is returned if specific path element types have dimension restrictions. For example, the ARC type is limited to 2 dimensions and the ARC_END_POINT type is limited to 3 dimensions. To correct this problem, select an appropriate dimension for the path element type.
MPIPathMessageILLEGAL_ELEMENT
 | The path element type is not valid. This message code is returned by mpiPathAppend(…) if the specified path element type is not a member of the MPIPathElementType enumeration.
MPIPathMessageARC_ILLEGAL_DIMENSION
 | The path element arc dimension is not valid. This message code is returned by mpiPathAppend(…) if the ARC or ARC_CENTER element is not 2 dimensions. To correct this problem, set the path dimension to 2.
MPIPathMessageHELIX_ILLEGAL_DIMENSION
 | Not supported.
MPIPathMessageILLEGAL_RADIUS
 | The path element arc radius is not valid. This message code is returned by mpiPathAppend(…) if the ARC element radius is less than or equal to zero. To correct this problem, set the arc radius to a value greater than zero.
MPIPathMessagePATH_TOO_LONG
 | The path length is not valid. This message code is returned by mpiPathMotionParamsGenerate(…) if the path length is greater than MAX_PATH_POINTS. To correct the problem, specify a path with fewer points than MAX_PATH_POINTS.
MPIPathMessageILLEGAL_VELOCITY
 | The path element velocity is not valid. This message code is returned by mpiPathAppend(…) if the specified velocity is less than or equal to zero. To correct this problem, set the element velocity to a value greater than zero.
MPIPathMessageILLEGAL_ACCELERATION
 | The path element velocity is not valid. This message code is returned by mpiPathAppend(…) if the specified velocity is less than or equal to zero. To correct this problem, set the element velocity to a value greater than zero.
MPIPathMessageILLEGAL_TIMESLICE
 | The path element time slice is not valid. This message code is returned by mpiPathAppend(…) if the specified time slice is less than or equal to zero. To correct this problem, set the element time slice to a value greater than zero.
MPIPathMessageINVALID_BLENDING
 | The path element blending is not valid. This message code is returned by mpiPathMotionParamsGenerate(…) if the element blending is set to TRUE and the motion type does not support blending. To correct this problem, either set the element blending to FALSE or select a different motion type.
See Also


MPIPathParams

MPIPathParams

typedef struct MPIPathParams {
    long		dimension;
    MPIPathPoint	start;
    double		velocity;
    double		acceleration;
    double		deceleration;
    MPIMotionType	interpolation;
    double		timeSlice;
    double		conversion
                   [MPIPathPointDIMENSION_MAX][MPIPathPointDIMENSION_MAX];
} MPIPathParams;

Description
 | dimension | This value defines the number of axes to coordinate. Please see MPIPathPoint data type documentation for more information.
 | start | This structure defines the initial point for the path.
 | velocity | This value defines the speed along the path. The units are in counts per second.
 | acceleration | This value defines the rate of change of speed to reach the velocity along the path. The units are in counts per second * second.
 | deceleration | This value defines the rate of change of speed to reach zero velocity along the path. The units are in counts per second * second.
 | interpolation | This value specifies the motion algorithm to generate the path. Please see MPIMotionType data type documentation for more information.

See Also | mpiPathParamsGet | mpiPathParmsSet | mpiPathMotionParamsGenerate | MPIPathPointDIMENSION_MAX


MPIPathPoint

MPIPathPoint

typedef struct MPIPathPoint {
    double	position[MPIPathPointDIMENSION_MAX];
} MPIPathPoint;

Description
 | position | This array defines the axis command positions for a path point. There must be one position value for each dimension.

See Also | MPIPathParams | mpiPathParamsGet | mpiPathParmsSet | mpiPathPointDIMENSION_MAX


MPIPathPointDIMENSION_MAX

MPIPathPointDIMENSION_MAX

#define MPIPathPointDIMENSION_MAX	(16)
Description

PathPointDIMENSION_MAX defines the maximum dimensions for path objects.

See Also | MPIPathParams | MPIPathPoint


mpiPathAppend

Declaration
long mpiPathAppend(MPIPath        path,
                   MPIPathElement *element);
Required Header stdmpi.h
Description

PathAppend adds an array of path elements pointed to by element to the end of the path stored in the Path object.
Return Values
MPIMessageOK if PathAppend successfully adds the elements to the path.
See Also | mpiPathCreate | mpiPathMotionParamsGenerate


mpiPathCreate

Declaration
MPIPath mpiPathCreate();
Required Header stdmpi.h
Description

PathCreate creates a Path object.

Return Values
handle | to a Path object
MPIHandleVOID | if the object could not be created

See Also | mpiPathDelete | mpiPathValidate


mpiPathDelete

Declaration
long mpiPathDelete(MPIPath path);
Required Header stdmpi.h
Description

PathDelete deletes a Path object and invalidates its handle (path). PathDelete is the equivalent of a C++ destructor.

Return Values
MPIMessageOK if PathDelete successfully deletes the Path object and invalidates its handle
See Also | mpiPathCreate | mpiPathValidate


mpiPathElementATTR

mpiPathElementATTR

#define mpiPathElementATTR(type,attr)
                          ((type) |= mpiPathElementAttrMaskBIT(attr))
Description

PathElementATTR is a macro that turns on the specified path element attribute mask bits in the path element type.

See Also | MPIPathAttr | MPIPathElementAttrMask


mpiPathElementAttrMaskBIT

mpiPathElementAttrMaskBIT

#define mpiPathElementAttrMaskBIT(attr) (0x1 << (attr))
Description

PathElementAttrMaskBIT is a macro that converts the path element attribute into the path element attribute mask.

See Also | MPIPathElementAttrs | MPIPathElementAttrMask


mpiPathElementTYPE

mpiPathElementTYPE

#define mpiPathElementTYPE(type) ((type) & MPIPathElementTypeMASK)
Description

PathElementTYPE is a macro that masks off all other bits in type, leaving the path element type.

See Also | MPIPathElementType


mpiPathMotionParamsGenerate

Declaration
long mpiPathMotionParamsGenerate(MPIPath          path,
                                 MPIMotionParams  *params);
Required Header stdmpi.h
Description

PathMotionParamsGenerate
Return Values
See Also


mpiPathParamsGet

Declaration
long mpiPathParamsGet(MPIPath        path,
                      MPIPathParams  *params,
                      void           *external),
Required Header stdmpi.h
Description

PathParamsGet reads the parameters for a path object and writes them into the structure pointed to by params, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL)

path | a handle to a Path object
*params | a pointer to a MPIPathParams structure
*external | a pointer to a void or NULL
Return Values
MPIMessageOK if PathParamsGet successfully reads the path parameters.
See Also | mpiPathParamsSet


mpiPathParamsSet

Declaration
long mpiPathParamsSet(MPIPath        path,
                      MPIPathParams  *params,
                      void           *external),
Required Header stdmpi.h
Description

PathParamsSet writes the parameters from the structure pointed to by params into the Path object. Also, it writes the implementation-specific structure pointed to by external (if external is not NULL) into the Path object.

path | a handle to a Path object
*params | a pointer to a MPIPathParams structure
*external | a pointer to a void or NULL
Return Values
MPIMessageOK if PathParamsSet successfully writes the path parameters.
See Also | mpiPathParamsGet


mpiPathValidate

Declaration
long mpiPathValidate(MPIPath path);
Required Header stdmpi.h
Description

PathValidate validates the Path object and its handle (command)
Return Values
MPIMessageOK if the Path object and its handle are valid
See Also | mpiPathCreate | mpiPathDelete


Platform Objects

.

Platform Objects

Introduction

The Platform module provides a common interface to platform-specific functionality, such as memory allocation, resource locking, interrupts, signalling, and others.

The Platform object provides low-level platform-specific functionality and depends upon the combination of the operating system and the C compiler used for development. The Platform module was written to provide platform-independent access functions for use by the MPI. Unless your application needs to be written for compatibility with different platforms, MEI encourages the use of OS-specific functions. If an MEIPlatform object handle is required, one should obtain this handle from the MPIControl method meiControlPlatform().

WARNING!
Do NOT attempt to use the (intentionally undocumented) method, meiPlatformCreate(). Using this method will interfere with the inner workings of the MPI.

The meiObjectGive/Take(...) methods all use the meiPlatformLockGive/Take(...) methods. When you take a lock, you take exclusive access to the resource (i.e., the section of XMP firmware memory associated with that Object). When you give a lock, you release (give up) that exclusive access. Think of it as TakeAccessOf and GiveUpAccess.

Methods

meiPlatformAlloc | Allocate system memory.
meiPlatformAssertSet | Set an assertion handling function to be used by the MPI library.
meiPlatformAtof | Convert a numeric string to a double.
meiPlatformAtol | Convert a numeric string to a long.
meiPlatformFileClose | Close a file handle.
meiPlatformFileOpen | Open a file handle.
meiPlatformFileRead | Read data from a file handle created by meiPlatformFileOpen.
meiPlatformFileWrite | Writes data to a file whose handle was created by meiPlatformFileOpen.
meiPlatformFree | Free system memory.
meiPlatformKey | Return an input character if an input character is available.
meiPlatformMemoryToFirmware | Convert a host memory address to a controller memory address.
meiPlatformMemoryToHost | Covert a controller memory address to a host memory address.
meiPlatformSleep | Put the current thread to sleep for the number of milliseconds specified.
meiPlatformProcessId | Return the process identification number of the current process.
meiPlatformTimerCount | Write to ticks the current timer count.
meiPlatformTimerFrequency | Write to frequency the timer frequency of the current platform.
meiPlatformTrace | Display printf(...)-style trace information
meiPlatformTraceEol | Set the end-of-line (eol) to be used by meiPlatformTrace(...).
meiPlatformTraceFile | Redirect trace output.
meiPlatformTraceFunction | Display the trace output.

Data Types

MEIPlatformFileMode
MEIPlatformMessage


MEIPlatformFileMode

MEIPlatformFileMode

typedef enum {
    MEIPlatformFileModeREAD,	/* default */
    MEIPlatformFileModeWRITE,
    MEIPlatformFileModeTEXT,	/* default */
    MEIPlatformFileModeBINARY,
    MEIPlatformFileModeTRUNC,
    MEIPlatformFileModeAPPEND,
} MEIPlatformFileMode;
Description

PlatformFileMode is an enumeration that is used as an argument for methods that open files.

MEIPlatformFileModeREAD | Open a file for read access
MEIPlatformFileModeWRITE | Open a file for write access
MEIPlatformFileModeTEXT | Open a file as text format
MEIPlatformFileModeBINARY | Open a file as binary format
MEIPlatformFileModeTRUNC |
MEIPlatformFileModeAPPEND |
See Also | meiPlatformFileOpen


MEIPlatformMessage

MEIPlatformMessage

typedef enum {

    MEIPlatformMessagePLATFORM_INVALID,
    MEIPlatformMessageDEVICE_INVALID,
    MEIPlatformMessageDEVICE_ERROR,
    MEIPlatformMessageDEVICE_MAP_ERROR,
} MEIPlatformMessage;

Description
MEIPlatformMessagePLATFORM_INVALID
 | The platform object is not valid. This message code is returned by a platform method if the platform object handle is not valid. Most applications do not use the platform module. The MPI library uses the platform module internally. If an application needs a platform handle, use meiControlPlatform(…). Do NOT create your own platform object with meiPlatformCreate(…).
MEIPlatformMessageDEVICE_INVALID
 | The platform device driver is not valid. This message code is returned by mpiControlInit(…) or mpiControlReset(…) if the platform device handle is not valid. This message code comes from the lower level routines, meiPlatformInit(…) or meiPlatformDeviceClose(…). To correct the problem, make sure the device driver is installed and operational.
MEIPlatformMessageDEVICE_ERROR
 | The platform device failed. This message code is returned by the platform methods that fail to access a controller via a device driver. It occurs if the specified board type is not a member of the MEIPlatformBoardType enumeration. It also occurs if the device driver fails to read/write controller memory or there is an interrupt handling failure. To correct the problem, verify the platform has support for your controller and the device drive is installed and operational. Check for any resource conflicts (memory range, I/O port range, and interrupts) with other devices.
MEIPlatformMessageDEVICE_MAP_ERROR
 | The platform device memory mapping failed. This message code is returned by mpiControlInit(…) or mpiControlReset(…) if the controller memory could not be mapped to the operating system's memory space. To correct this problem, verify there are no memory resource conflicts. Also, make sure the host computer and operating system have enough free memory for the controller (XMP-Series requires 8 Mbytes).
See Also


meiPlatformAlloc

Declaration
void meiPlatformAlloc(long   size)
Required Header stdmei.h
Description

PlatformAlloc allocates system memory. meiPlatformAlloc will return NULL upon failure to allocate memory.

size | the number of bytes to allocate.

See Also | meiPlatformFree


meiPlatformAssertSet

Declaration
void meiPlatformAssertSet(void (MPI_DECL2 *func)
                        (const char *file, long line));
Required Header stdmei.h
Description

PlatformAssertSet sets an assertion handling function to be used by the MPI library.

When an assertion occurs, the filename and line number where that assertion happened will be passed to the assertion handling function. If no assertion handling function is set, information about the assertion will be reported to stdout and the C function, exit() will be called with an argument of 1.

An MPI library assertion should never occur. If it does, please contact MEI's technical support at Tech Email.

NOTE: meiPlatformAssertSet is only fully implemented for Windows operating systems.

platform | the handle to the controller's platform object. This should be obtained from meiControlPlatform().
firmware | the controller memory address to be converted.
host | the location where the host memory address will be written.
See Also


meiPlatformAtof

Declaration
double meiPlatformAtof(const char *ascii)
Required Header stdmei.h
Description

PlatformAtof converts a numeric string to a double. This function returns the converted value as a double.

*ascii | string to be converted

Returns

 converted the numeric text string ascii to a long and returned it
See Also | meiPlatformAtol


meiPlatformAtol

Declaration
long meiPlatformAtol(const char *ascii)
Required Header stdmei.h
Description

PlatformAtol converts a numeric string to a long. This function returns the converted value as a long.

*ascii | string to be converted

Returns

 converted the numeric text string ascii to a long and returned it
See Also | meiPlatformAtof


meiPlatformFileClose

Declaration
long meiPlatformFileClose(long   file)
Required Header stdmei.h
Description

PlatformFileClose closes a file handle. meiPlatformFileClose is a platform independent replacement for the C function fclose().

file | the file handle to be closed.

See Also | meiPlatformFileOpen


meiPlatformFileOpen

Declaration
long meiPlatformFileOpen(const  char           *fileName,
                         MEIPlatformFileMode   mode)
Required Header stdmei.h
Description

PlatformFileOpen opens a file handle. meiPlatformFileOpen is a platform independent replacement for the C function fopen().

fileName | the name of the file to open.
mode | the access mode used to open the file. Different MEIPlatformFileMode values may be or'ed together to produce the desired mode. For example: MEIPlatformFileModeREAD | MEIPlatformFileModeBINARY)

Returns

 meiPlatformFileOpen returns the newly created file handle.
See Also | meiPlatformFileClose | meiPlatformFileRead | meiPlatformFileWrite | MEIPlatformFileMode


meiPlatformFileRead

Declaration
long meiPlatformFileRead(long   file,
                         char   *buffer,
                         long   byteCount)
Required Header stdmei.h
Description

PlatformFileRead reads data from a file handle created by meiPlatformFileOpen. meiPlatformFileRead is a platform independent replacement for the C function fread().

file | the handle of the file from which data will be read.
buffer | the storage location where data from the file will be written to.
byteCount | the number of bytes to read from the file.

See Also | meiPlatformFileOpen | meiPlatformFileWrite


meiPlatformFileWrite

Declaration
long meiPlatformFileWrite(long          file,
                          const  char   *buffer,
                          long          byteCount)
Required Header stdmei.h
Description

PlatformFileWrite writes data to a file whose handle was created by meiPlatformFileOpen. meiPlatformFileWrite is a platform independent replacement for hte C function fwrite().

file | the handle of the file to which data will be written.
buffer | the location of the data to be written to the file.
byteCount | the number of bytes to be written to the file.

See Also | meiPlatformFileOpen | meiPlatformFileRead


meiPlatformFree

Declaration
long meiPlatformFree(void   *alloc,
                     long   size)
Required Header stdmei.h
Description

PlatformFree frees system memory.

alloc | the address of the memory to free.
size | the number of bytes to free. This must match the size specified for meiPlatformAlloc when alloc was allocated.

See Also | meiPlatformAlloc


meiPlatformKey

Declaration
long meiPlatformKey(MPIWait wait)
Required Header stdmei.h
Description

PlatformKey returns an input character (typically a keystroke) if an input character is available.
If an input charater is not available, PlatformKey waits wait milliseconds for an input character to become available.

NOTE:
meiPlatformKey is not fully implemented for all operating sytems. For example, in VentureCom's RTX Windows Extensions, a keystroke will be simulated after 10 seconds.

If "wait" is | Then
MPIWaitFOREVER (-1) | PlatformKey will wait for an input character forever
MPIWaitPOLL (0) | PlatformKey will return immediately
a value (not -1 or 0) | PlatformKey will wait for an input character for wait milliseconds

Return Values
-1 | if no input character was available
0 | PlatformKey has read a non-zero character (typically a function key or other non-ASCII value), and meiPlatformKey(...) should be called AGAIN immediately to receive that non-zero character
a value (not -1 or 0) (an ASCII character) | (typically a keystroke) if an input character is available
See Also


meiPlatformMemoryToFirmware

Declaration
long meiPlatformMemoryToFirmware(MEIPlatform   platform,
                                 void          *host,
                                 void          **milliseconds)
Required Header stdmei.h
Description

PlatformMemoryToFirmware converts a host memory address to a controller memory address.

platform | the handle to the controller's platform object. This should be obtained from meiControlPlatform().
host | the host memory address to be converted.
address | the location where the controller's memory address will be written.

See Also | meiPlatformMemoryToHost | meiControlPlatform


meiPlatformMemoryToHost

Declaration
long meiPlatformMemoryToHost(MEIPlatform   platform,
                             void          *firmware,
                             void          **host)
Required Header stdmei.h
Description

PlatformMemoryToHost coverts a controller memory address to a host memory address.

platform | the handle to the controller's platform object. This should be obtained from meiControlPlatform().
firmware | the controller memory address to be converted.
host | the location where the host memory address will be written.

See Also | meiPlatformMemoryToFirmware | meiControlPlatform


meiPlatformProcessId

Declaration
long meiPlatformProcessId(void)
Required Header stdmei.h
Description

PlatformProcessId returns the process identification number of the current process.

See Also


meiPlatformSleep

Declaration
void meiPlatformSleep(long   milliseconds)
Required Header stdmei.h
Description

PlatformSleep puts the current thread to sleep for the number of milliseconds specified.

NOTE:
Different platforms have different time slice "quanta" (minimum sleep resolution) for threads. For example, Windows NT, 2000, and XP have a quanta of 10ms. For example, even if meiPlatformSleep(2) is specified, the actual sleep period will essentially be equivalent to meiPlatformSleep(10).

milliseconds | the number of milliseconds for which to put the current thread to sleep

Returns

 converted the numeric text string ascii to a long and returned it
See Also


meiPlatformTimerCount

Declaration
long meiPlatformCount(long  *ticks)
Required Header stdmei.h
Description

PlatformTimerCount writes to ticks the current timer count.

ticks | the address where the current timer count will be written.

See Also | meiPlatformTimerFrequency


meiPlatformTimerFrequency

Declaration
long meiPlatformTimerFrequency(long  *frequency)
Required Header stdmei.h
Description

PlatformTimerFrequency writes to frequency the timer frequency of the current platform.

frequency | the address where the timer frequency will be written.

See Also | meiPlatformTimerCount


meiPlatformTrace

Declaration
long meiPlatformTrace(const char *format, ...)
Required Header stdmei.h
Description

PlatformTrace displays printf(...)-style trace information. An end-of-line character will be appended to the output, newline by default.

Library modules call meiTrace#(...), a macro which can be conditionally compiled to call meiPlatformTrace(...) (by defining the symbol MEI_TRACE when building the library).
Otherwise, calls to meiTrace#(...) are removed by the C preprocessor.

Return Values
MPIMessageOK if PlatformTrace successfully executes
See Also


meiPlatformTraceEol

Declaration
char meiPlatformTraceEol(char eol)
Required Header stdmei.h
Description

The PlatformTraceEol function sets the end-of-line (eol) character that will be used by meiPlatformTrace(...).

Returns

 the previous end-of-line character used by meiPlatformTrace(...)
See Also | meiPlatformTrace


meiPlatformTraceFile

Declaration
long meiPlatformTraceFile(const char *fileName)
Required Header stdmei.h
Description

PlatformTraceFile redirects trace output to fileName, after first closing any previously opened trace file. If no trace file has been explicitly opened, trace output will go to standard output.

Return Values
MPIMessageOK if PlatformTraceFile successfully closes any previously opened trace file and redirects trace output to fileName
See Also | meiPlatformTrace


meiPlatformTraceFunction

Declaration

     MEITraceFunction meiPlatformTraceFunction(MEITraceFunction traceFunction)
Required Header stdmei.h
Description

PlatformTraceFunction displays the trace output using traceFunction, and replaces the internal function that was called by meiPlatformTrace(...) to display the trace output. Use PlatformTraceFunction to enable your application to take control of the display of trace output.

Return Values
the previous traceFunction | if there is a previous function
NULL | if no traceFunction has been specified (the default trace function is used)

See Also | meiPlatformTrace


Recorder Objects

.

Recorder Objects

Introduction

The Recorder object provides a mechanism to collect and buffer data from the controller. Only one Recorder object per controller is supported. After the Recorder is configured and started, the controller copies the data from the specified fields to a local buffer every "N" samples. The host can collect the data from the Recorder object using polling or interrupt-based techniques.

| Buffer Size |

Methods

Create, Delete, Validate Methods
 | mpiRecorderCreate | Create Recorder object
 | mpiRecorderDelete | Delete Recorder object
 | mpiRecorderValidate | Validate Recorder object

Configuration and Information Methods
 | mpiRecorderConfigGet | Get Recorder’s configuration
 | mpiRecorderConfigSet | Set Recorder’s configuration
 | mpiRecorderRecordConfig | Configure type of data record that Recorder will capture
 | mpiRecorderStatus | Get status of Recorder

Event Methods
 | mpiRecorderEventNotifyGet | Get event mask of events for which host notification has been requested
 | mpiRecorderEventNotifySet | Set event mask of events for which host notification will be requested
 | mpiRecorderEventReset | Reset the events specified in event mask that are generated by Recorder

Action Methods
 | mpiRecorderRecordGet | Get data records from Recorder
 | mpiRecorderStart | Start recording data records using Recorder
 | mpiRecorderStop | Stop recording data records using Recorder

Memory Methods
 | mpiRecorderMemory | Get address to Recorder’s memory
 | mpiRecorderMemoryGet | Copy data from Recorder memory to application memory
 | mpiRecorderMemorySet | Copy data from application memory to Recorder memory

Relational Methods
mpiRecorderControl Return handle of Control object associated with Recorder

Data Types

MPIRecorderConfig
MPIRecorderMessage
MPIRecorderRecord / MEIRecorderRecord
MEIRecorderRecordAxis
MEIRecorderRecordFilter
MPIRecorderRecordPoint
MPIRecorderRecordType / MEIRecorderRecordType
MPIRecorderStatus
MEIRecorderTrace

Constants

MPIRecorderADDRESS_COUNT_MAX


MPIRecorderADDRESS_COUNT_MAX

MPIRecorderADDRESS_COUNT_MAX

#define	MPIRecorderADDRESS_COUNT_MAX	(128)

Description
 | RecorderADDRESS_COUNT_MAX defines the maximum number of addresses the Recorder object supports.

See Also | MPIRecorderConfig


MPIRecorderConfig

MPIRecorderConfig

typedef struct MPIRecorderConfig {
    long	period;		/* collect 1 record every `period` milliseconds */
    long	fullCount;	/* >0 => record count to trigger full buffer */

    long	addressCount;	/* number of data point addresses in address[] */
    void	*address[MPIRecorderADDRESS_COUNT_MAX];
} MPIRecorderConfig;

Description
 | period | The number of milliseconds between successive recordings. A value of zero means the recorder will record data every sample.
 | fullCount | If fullCount>0, then the recorder will generate a "recorder full" event when this fullCount number or records are in the recorder buffer.
 | addressCount | The number of XMP memory addresses in address[].
 | *address[] | An array of XMP memory addresses the recorder will record.


MPIRecorderMessage

MPIRecorderMessage

typedef enum {

    MPIRecorderMessageRECORDER_INVALID,
    MPIRecorderMessageSTARTED,
    MPIRecorderMessageSTOPPED,
    MPIRecorderMessageNOT_CONFIGURED,
} MPIRecorderMessage;

Description
MPIRecorderMessageRECORDER_INVALID
 | The recorder object is not valid. This message code is returned by a recorder method if the recorder object handle is not valid. This problem can be caused by a failed mpiRecorderCreate(…). To prevent this problem, check your recorder objects after creation by using mpiRecorderValidate(…).
MPIRecorderMessageSTARTED
 | The data recorder is already running. This message code is returned by mpiRecorderStart(…) if the data recorder has already been started. If this is a problem, call mpiRecorderStop(…) to stop the data recorder or wait for the recorder to collect the number of specified records and stop.
MPIRecorderMessageSTOPPED
 | The data recorder is not running. This message code is returned by mpiRecorderStop(…) if the data recorder has already been stopped. If this is a problem, call mpiRecorderStart(…) to start the data recorder.
MPIRecorderMessageNOT_CONFIGURED
 | The data recorder has not been configured. This message code is returned by mpiRecorderRecordGet(…) if the data address count has not been configured. To correct this problem, configure the data recorder with mpiRecorderConfigSet(…).
Sample Code
MPIControl      control;
MPIRecorder   recorder;
long                returnValue;
…

recorder =
    mpRecorderCreate(control);
returnValue =
    mpiRecorderValidate(recorder);

See Also | mpiRecorderCreate | mpiRecorderValidate


MPIRecorderRecord / MEIRecorderRecord

MPIRecorderRecord

typedef union {
    MPIRecorderRecordPoint	point[MPIRecorderADDRESS_COUNT_MAX];
} MPIRecorderRecord;
Description
point An array of recorded values corresponding to the XMP addresses stored in MPIRecorderConfig.address[].

MEIRecorderRecord

 typedef union {
    MEIRecorderRecordAxis	axis[MEIXmpMAX_Axes];
    MEIRecorderRecordFilter	filter[MEIXmpMAX_Filters];
    MPIRecorderRecord		dummy;	/* ensure proper sizing */
} MEIRecorderRecord;

Description
 | axis | An array of MEIRecorderRecordAxis records.
 | filter | An array of MEIRecorderRecordFilter records.
 | dummy | A dummy structure that ensures that MEIRecorderRecord has the proper size.
See Also


MEIRecorderRecordAxis

MEIRecorderRecordAxis

typedef struct MEIRecorderRecordAxis {
    long    sample;	    /* sample number */
    long    command;        /* command position */
    long    actual;	    /* actual position */
    float   dac;	    /* voltage */
} MEIRecorderRecordAxis;

Description
 | sample | The XMP sample number in which the following values were recorded.
 | command | The command position of the axis.
 | actual | The actual position of the axis.
 | dac | The output of the primary DAC of the motor associated with the axis.
See Also


MEIRecorderRecordFilter

MEIRecorderRecordFilter

typedef struct MEIRecorderRecordFilter {
    long	sample;		/* sample number */
    long	command;	/* command position */
    long	actual;		/* actual position */
    float	dac;		/* voltage */
} MEIRecorderRecordFilter;

Description
 | sample | The XMP sample number in which the following values were recorded
 | command | The command position the filter uses to calculate the filter output.
 | actual | The actual position (of an axis) the filter uses to calculate the filter output.
 | dac | The output of the filter that gets sent to a motor's primary DAC.
See Also


MPIRecorderRecordPoint

MPIRecorderRecordPoint

typedef long MPIRecorderRecordPoint;
Description
MPIRecorderRecordPoint represents one recorder record. This will correspond to the value of one XMP address.
See Also


MPIRecorderType / MEIRecorderType

.

MPIRecorderRecordType / MEIRecorderRecordType

MPIRecorderRecordType

typedef enum {
    MPIRecorderRecordTypeINVALID,
    MPIRecorderRecordTypePOINT,

} MPIRecorderRecordType;

Description
 | MPIRecorderRecordTypeINVALID | specifies to the data recorder that MPIRecorderRecordPoint records (copies of controller memory locations) are being recorded.
 | MPIRecorderRecordTypePOINT | an invalid record type.

MEIRecorderRecordType

typedef enum {
    MEIRecorderRecordTypeAXIS,
    MEIRecorderRecordTypeFILTER,
} MPIRecorderRecordType;

Description
 | MEIRecorderRecordTypeAXIS | specifies to the data recorder that MEIRecorderRecordAxis records are being recorded.
 | MEIRecorderRecordTypeFILTER | specifies to the data recorder that MEIRecorderRecordFilter records are being recorded.

Remarks
 | Predefined types for setting up the type of data an MPIRecorder object will record. This is used by the mpiRecorderRecordConfig() method.

See Also | MPIRecorder | MEIRecorderRecordAxis | MEIRecorderRecordFilter | mpiRecorderRecordConfig


MPIRecorderStatus

MPIRecorderStatus

typedef struct MPIRecorderStatus {
    long    enabled;
    long    full;
    long    recordCount;
    long    recordCountMax;
} MPIRecorderStatus;

Description
 | enabled | If the recorder is enabled (recording) then enabled will equal TRUE, otherwise enabled will equal FALSE.
 | full | If the recorder is full (the number of stored records >= MPIRecorderConfig.fullCount) then full will equal TRUE, otherwise full will equal FALSE.
 | recordCount | The number of stored records in the recorder.
 | recordCountMax | The maximum number of records the recorder can store.

See Also | mpiRecorderStatus


MEIRecorderRecordTrace

MEIRecorderRecordTrace

typedef enum {

    MEIRecorderTraceRECORD_GET,
    MEIRecorderTraceSTATUS,
    MEIRecorderTraceOVERFLOW,
} MEIRecorderTrace;

Description
 | MEIRecorderTraceRECORD_GET | will display trace information when the data recorder retrieves records.
 | MEIRecorderTraceSTATUS | will display trace information when the MPI retrieves the data recorder status.
 | MEIRecorderTraceOVERFLOW | will display trace information when the data recorder overflows.
See Also


mpiRecorderConfigGet

Declaration
long mpiRecorderConfigGet(MPIRecorder       recorder,
                          MPIRecorderConfig *config,
                          void              *external)
Required Header stdmpi.h
Description

RecorderConfigGet gets a Recorder’s (recorder) configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Recorder’s configuration information in external is in addition to the Recorder’s configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIRecorderConfig{} or is NULL.

Return Values
MPIMessageOK if RecorderConfigGet successfully writes the Recorder’s configuration to the structure(s)
See Also | MPIRecorderConfig | mpiRecorderConfigSet


mpiRecorderConfigSet

Declaration
long mpiRecorderConfigSet(MPIRecorder       recorder,
                          MPIRecorderConfig *config,
                          void              *external)
Required Header stdmpi.h
Description

RecorderConfigSet sets a Recorder’s (recorder) configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Recorder’s configuration information in external is in addition to the Recorder’s configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIRecorderConfig{} or is NULL.
Return Values
MPIMessageOK if RecorderConfigSet successfully sets the Recorder’s configuration using data from the structure(s)
See Also | MEIRecorderConfig | mpiRecorderConfigGet


mpiRecorderControl

Declaration
MPIControl mpiRecorderControl(MPIRecorder recorder)
Required Header stdmpi.h
Description

RecorderControl returns a handle to the motion controller (Control object) that a Recorder (recorder) is associated with.

Return Values
handle | to a Control object that a Recorder is associated with
MPIHandleVOID | if the Recorder object is invalid
See Also


mpiRecorderCreate

Declaration
MPIRecorder mpiRecorderCreate(MPIControl control)
Required Header stdmpi.h
Description

RecorderCreate creates a Recorder object associated with a Control object (control). RecorderCreate is the equivalent of a C++ constructor.

Return Values
handle | to a Recorder object
MPIHandleVOID | if the Recorder object could not be created

See Also | mpiRecorderDelete | mpiRecorderValidate


mpiRecorderDelete

Declaration
long mpiRecorderDelete(MPIRecorder recorder)
Required Header stdmpi.h
Description

RecorderDelete deletes a Recorder object and invalidates its handle (recorder). RecorderDelete is the equivalent of a C++ destructor.
Return Values
MPIMessageOK if RecordeDelete successfully deletes a Recorder object and invalidates its handle
See Also | mpiRecorderCreate | mpiRecorderValidate


mpiRecorderEventNotifyGet

Declaration
long mpiRecorderEventNotifyGet(MPIRecorder  recorder,
                               MPIEventMask *eventMask,
                               void         *external)
Required Header stdmpi.h
Description

RecorderEventNotifyGet writes the event mask into the structure pointed to by eventMask, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL). (The event mask specifies the event type(s) generated by a Recorder (recorder), for which host notification has been requested.)

The event mask information in external is in addition to the event mask information in eventMask, i.e, the mask information in eventMask and in external is not the same mask information. Note that eventMask or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL. An MEIEventNotifyData{} structure is an array of firmware addresses. The contents of these firmware addresses are placed into the MEIEventStatusInfo{} structure (which contains all events generated by this Recorder object).
Return Values
MPIMessageOK if RecorderEventNotifyGet successfully writes the event mask to the structure(s)
See Also | MEIEventNotifyData | MEIEventStatusInfo | mpiRecorderEventNotifySet


mpiRecorderEventNotifySet

Declaration
long mpiRecorderEventNotifySet(MPIRecorder   recorder,
                               MPIEventMask  eventMask,
                               void          *external)
Required Header stdmpi.h
Description

RecorderEventNotifySet requests host notification of the event(s) specified by eventMask and generated by a Recorder (recorder), and also generated by the implementation-specific structure pointed to by external (if external is not NULL).

The events in external are in addition to the events in recorder, i.e, the events in recorder and in external are not necessarily the same events. Note that recorder or external can be NULL (but not both NULL).

Event notification is enabled for the event types specified in eventMask. eventMask is a bit mask generated by the logical OR of the MPIEventMask bits that are associated with the desired MPIEventType values. Event notification is disabled for event types not specified in eventMask.

The mask of event types (generated by a Recorder object) consists of MEIEventMaskRECORDER_FULL and MEIEventMaskRECORDER_DONE.

To | Use "eventMask"
Enable host notification of all Recorder events | MPIEventMaskALL
Disable host notification of all Recorder events | MPIEventTypeNONE
XMP Only

external either points to a structure of type MEIEventNotifyData{} or is NULL. An MEIEventNotifyData{} structure is an array of firmware addresses. The contents of these firmware addresses are placed into the MEIEventStatusInfo{} structure (which contains all events generated by this Recorder object).

Return Values
MPIMessageOK if RecorderEventNotifySet successfully requests host notification of the event(s) as specified by the structure(s)
See Also | MEIEventMaskRECORDER | MEIEventNotifyData | MEIEventStatusInfo mpiRecorderEventNotifyGet


mpiRecorderEventReset

Declaration
long mpiRecorderEventReset(MPIRecorder  recorder,
                           MPIEventMask eventMask)
Required Header stdmpi.h
Description

RecorderEventReset resets the event(s) specified in eventMask and generated by a Recorder (recorder). Your application should call RecorderEventReset only after one or more latchable events have occurred.
Return Values
MPIMessageOK if RecorderEventReset successfully resets the event(s) that are specified in eventMask and generated by a Recorder
See Also


mpiRecorderMemory

Declaration
long mpiRecorderMemory(MPIRecorder recorder,
                       void        **memory)
Required Header stdmpi.h
Description

RecorderMemory writes an address to the contents of memory. An address can be used to access a Recorder’s (recorder) memory. An address calculated from it can be passed as the src argument to mpiRecorderMemoryGet(...) and as the dst argument to mpiRecorderMemorySet(...).

Return Values
MPIMessageOK if RecorderMemory successfully writes the Recorder’s memory address to the contents of memory
See Also | mpiRecorderMemoryGet | mpiRecorderMemorySet


mpiRecorderMemoryGet

Declaration
long mpiRecorderMemoryGet(MPIRecorder recorder,
                          void        *dst,
                          void        *src,
                          long        count)
Required Header stdmpi.h
Description

RecorderMemoryGet copies count bytes of a Recorder’s (recorder) memory (starting at address src) to application memory (starting at address dst).

Return Values
MPIMessageOK if RecorderMemoryGet successfully copies data from Recorder memory to application memory
See Also | mpiRecorderMemory | mpiRecorderMemorySet


mpiRecorderMemorySet

Declaration
long mpiRecorderMemorySet(MPIRecorder recorder,
                          void        *dst,
                          void        *src,
                          long        count)
Required Header stdmpi.h
Description

RecorderMemorySet copies count bytes of application memory (starting at address src) to a Recorder’s (recorder) memory (starting at address dst).
Return Values
MPIMessageOK if RecorderMemorySet successfully copies data from application memory to Recorder memory
See Also | mpiRecorderMemory | mpiRecorderMemoryGet


mpiRecorderRecordConfig

Declaration
long mpiRecorderRecordConfig(MPIRecorder           recorder,
                             MPIRecorderRecordType type,
                             long                  count,
                             void                  *handle)
Required Header stdmpi.h
Description

RecorderRecordConfig configures the type (type) of record that a Recorder (recorder) will capture.

If "type" is | Then
MPIRecorderRecordTypePOINT | count data points will be recorded, and handle points to an array of count controller addresses
MEIRecorderRecordTypeAXIS | count records of type MPIRecorderRecordAxis{} will be recorded, and handle points to an array of count Axis handles
MEIRecorderRecordTypeFILTER | count records of type MPIRecorderRecordFilter{} will be recorded, and handle points to an array of count Filter handles
Return Values
MPIMessageOK if RecorderRecordConfig successfully configures the type of record that the Recorder will capture
See Also | MPIRecorderRecordAxis | MPIRecorderRecordFilter


mpiRecorderRecordGet

Declaration
long mpiRecorderRecordGet(MPIRecorder       recorder,
                          long              countMax,
                          MPIRecorderRecord *record,
                          long              *count)
Required Header stdmpi.h
Description

RecorderRecordGet obtains a Recorder’s (recorder) data records. The record type must have been configured previously, by a prior call to mpiRecorderRecordConfig(...).

RecorderRecordGet gets a maximum of countMax records and writes them into the location pointed to by record (the location must be large enough to hold them). RecorderRecordGet also writes the actual number of records that were obtained to the location pointed to by count.

If the recorder data buffer is full and recording is enabled, recording will be temporarily disabled while either all or countMax records are obtained, whichever is less. Any records not obtained will be lost.

Return Values
MPIMessageOK if RecorderRecordGet successfully gets the data records
See Also | mpiRecorderRecordConfig


mpiRecorderStop

Declaration
long mpiRecorderStop(MPIRecorder recorder)
Required Header stdmpi.h
Description

RecorderStop instructs a Recorder (recorder) to stop recording data records.
Return Values
MPIMessageOK if RecorderStop successfully stops recording data records
See Also | mpiRecorderStart


mpiRecorderStart

Declaration
long mpiRecorderStart(MPIRecorder  recorder,
                      long         count,
                      long         period,
                      long         fullCount)
Required Header stdmpi.h
Description

RecorderStart instructs a Recorder (recorder) to begin recording data records. The record type must have been configured previously, by a prior call to mpiRecorderRecordConfig(...).

An event of type MPIEventRECORDER_DONE will be generated when the Recorder has finished collecting data records.

count ( for count > 0) | specifies the total number of data records to record
if count = -1 | then recording is continuous, and uncollected records may be overwritten
period if period = 0 | frequency of recording in milliseconds then data will be recorded as quickly as possible (on every sample)
if fullCount > 0 | then an event of type MPIEventRECORDER_COUNT will be generated when the Recorder’s data buffer contains fullCount data records
Return Values
MPIMessageOK if RecorderStart successfully instructs a Recorder to begin recording data records
See Also | mpiRecorderRecordConfig | mpiRecorderStop


mpiRecorderStatus

Declaration
long mpiRecorderStatus(MPIRecorder       recorder,
                       MPIRecorderStatus *status,
                       void              *external)
Required Header stdmpi.h
Description

RecorderStatus gets the status of the Recorder (recorder) and writes it into the structure pointed to by status, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Recorder’s status information in external is in addition to the Recorder’s status information in status, i.e., the status information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).
XMP Only

external should be NULL.
Return Values
MPIMessageOK if RecorderStatus successfully gets the Recorder’s status and writes it into the structure(s)
See Also | MPIRecorderStatus


mpiRecorderValidate

Declaration
long mpiRecorderValidate(MPIRecorder recorder)
Required Header stdmpi.h
Description

RecorderValidate validates the Recorder object and its handle (recorder).

Return Values
MPIMessageOK if Recorder is a handle to a valid object.
See Also | mpiRecorderCreate | mpiRecorderDelete


Recorder Buffer Size

.

Recorder Buffer Size

The Data Recorder buffer size can be dynamically allocated. The MPIControlConfig{...} structure has a new element, called recordCount. This element allows the application to change the size of the recorder object's data buffer using the mpiControlConfigGet/Set(...) methods. The Record buffer size (the default is 3064 records) is defined within the MEIXmpDefaultEnabled_Records structure (xmp.h). Each record is the size of one memory word. Using a larger data buffer size can improve the performance of MotionScope running on a slow host or running in Client/Server mode over a congested network.

A new method, meiControlExtMemAvail(...), has been added which will return the size of external memory available for allocation. This value can be added to the current recordCount to expand the record buffer to the maximum possible size.

For more information, see the Special Note on Dynamic Allocation of External Memory Buffers.

Return to Recorder Object's page


Sequence Objects

.

Sequence Objects

Introduction

A Sequence object manages a set of Commands. The sequence is constructed on the host from a list of commands, then downloaded and executed in the controller. Typically, applications only use Sequences for very small or simple autonomous tasks that require execution in the controller. Due to their embedded execution, debugging can be difficult. It is best to use the host application to execute MPI methods directly for optimum flexibility and performance.

If you are considering using a program Sequencer or Command objects, please contact an MEI Applications Engineer. We recommend that you do NOT implement complex Sequences on your own.

Methods

Create, Delete, Validate Methods
 | mpiSequenceCreate | Create Sequence object
 | mpiSequenceDelete | Delete Sequence object
 | mpiSequenceValidate | Validate Sequence object

Configuration and Information Methods
 | mpiSequenceConfigGet | Get sequence config
 | mpiSequenceConfigSet | Set sequence config
 | mpiSequenceFlashConfigGet | Get sequence flash config
 | mpiSequenceFlashConfigSet | Set sequence flash config
 | mpiSequencePageSize | Set pageSize to number of command slots used by sequence
 | mpiSequenceStatus | Return sequence status

Event Methods
 | mpiSequenceEventNotifyGet | Select an event mask for host notification of events
 | mpiSequenceEventNotifySet | Enable host notification of sequence events
 | mpiSequenceEventReset | Reset sequence events

Action Methods
 | meiSequenceCompile |
 | mpiSequenceLoad | Load sequence commands into firmware
 | mpiSequenceResume | Resume execution of sequence
 | mpiSequenceStart | Start execution of sequence
 | mpiSequenceStep | Execute count steps of a stopped sequence
 | mpiSequenceStop | Stop sequence

Memory Methods
 | mpiSequenceMemory | Set address used to access sequence memory
 | mpiSequenceMemoryGet | Get bytes of sequence memory and put into application memory
 | mpiSequenceMemorySet | Put (set) bytes of application memory into sequence memory

Relational Methods
 | mpiSequenceControl | Get handle to Control
 | mpiSequenceNumber | Get index number of sequence
 | List Methods for Event Sources
 | mpiSequenceCommand | Return handle to indexed command of sequence
 | mpiSequenceCommandAppend | Append command to sequence
 | mpiSequenceCommandCount | Count the number of commands in sequence
 | mpiSequenceCommandFirst | Return handle to first command in sequence
 | mpiSequenceCommandIndex | Return the index of a command in sequence
 | mpiSequenceCommandInsert | Insert command into sequence
 | mpiSequenceCommandLast | Return handle of last command in sequence
 | mpiSequenceCommandListGet | Get list of commands in sequence
 | mpiSequenceCommandListSet | Set list of commands in sequence
 | mpiSequenceCommandNext | Get handle to next command in list
 | mpiSequenceCommandPrevious | Get handle to previous command in list
 | mpiSequenceCommandRemove | Remove command from list

Data Types

MPISequenceConfig / MEISequenceConfig
MPISequenceMessage
MPISequenceState
MPISequenceStatus
MEISequenceTrace


MPISequenceConfig / MEISequenceConfig

MPISequenceConfig

typedef MPIEmpty    MPISequenceConfig;
Description

SequenceConfig is currently not supported and is reserved for future use.

MEISequenceConfig

typedef MPIEmpty    MEISequenceConfig;
Description

SequenceConfig is currently not supported and is reserved for future use.

See Also | mpiSequenceConfigGet | mpiSequenceConfigSet


MPISequenceMessage

MPISequenceMessage

typedef enum {

    MPISequenceMessageSEQUENCE_INVALID,
    MPISequenceMessageCOMMAND_COUNT,
    MPISequenceMessageCOMMAND_NOT_FOUND,
    MPISequenceMessageSTARTED,
    MPISequenceMessageSTOPPED,
} MPISequenceMessage;

Description
MPISequenceMessageSEQUENCE_INVALID
 | The sequence number is out of range. This message code is returned by mpiSequenceCreate(…) if the sequence number is less than zero or greater than or equal to MEIXmpMAX_PSs. This message code is also returned if the specified sequence number is not active in the controller. To correct this problem, use mpiControlConfigSet(…) to enable the sequence object, by setting the sequenceCount to greater than the sequence number. For example, to enable sequence 0 to 3, set sequenceCount to 4. This message code is returned by mpiSequenceLoad(…) if the sequence buffer size and the sequence page size are not equal. This indicates an internal MPI Library problem.
MPISequenceMessageCOMMAND_COUNT
 | The sequence command count is out of range. This message code is returned by mpiSequenceStart(…) or meiSequenceCompile(…) if the sequence command count is less than or equal to zero. To correct this problem, set the command count to a value greater than zero.
MPISequenceMessageCOMMAND_NOT_FOUND
 | The sequence command is not found. This message code is returned by mpiSequenceLoad(…), mpiSequenceStart(…), or meiSequenceCompile(…) if the specified command is not a member of the sequence. To correct this problem, specify a command that is a member of the sequence.
MPISequenceMessageSTARTED
 | The program sequencer is already running. This message code is returned by mpiSequenceResume(…), mpiSequenceStart(…), or mpiSequenceStep(…) if the program sequencer has already been started. If this is a problem, call mpiSequenceStop(…) to stop the program sequencer or monitor the sequence status and wait for the state to equal STOPPED.
MPISequenceMessageSTOPPED
 | The program sequencer is not running. This message code is returned by mpiSequenceStop(…) if the program sequencer has already been stopped. If this is a problem, call mpiSequenceStart(…) to start the program sequencer.
See Also


MPISequenceState

MPISequenceState

typedef enum {
    MPISequenceStateSTOPPED = 0,
    MPISequenceStateSTARTED,
} MPISequenceState;

Description
 | MPISequenceStateSTOPPED | Means that the XMP's on-board program sequencer state is stopped. The program sequencer is in this state after it is created, and is not running. If the program sequencer has already been started, then a call to the MPI method mpiSequenceStop will stop the sequencer, and the sequencer state will be MPISequenceStateSTOPPED.
 | MPISequenceStateSTARTED | Means that the XMP's on-board program sequencer state is running. The program sequencer is in this state after it has been created, and successfully started with a call to the MPI method mpiSequenceStart.
See Also


MPISequenceStatus

MPISequenceStatus

typedef struct MPISequenceStatus {
    MPICommand		command;
    MPISequenceState	state;
} MPISequenceStatus;
Description

MPISequenceStatus is a status structure for MPISequence objects

command | The current command of the MPISequence object
state | The current state of the MPISequence object

See Also | MPISequence | mpiSequenceStatus


MEISequenceTrace

MEISequenceTrace

typedef enum {
    MEISequenceTraceLOAD,

} MEISequenceTrace;
Description

MPISequenceTrace sets tracing on for the mpiSequenceLoad() method.

See Also | MPISequence | MEITrace | mpiSequenceLoad


mpiSequenceConfigGet

Declaration
long mpiSequenceConfigGet(MPISequence sequence,
                          MPISequenceConfig *config,
                          void *external)
Required Header stdmpi.h
Description

SequenceConfigGet gets the configuration of a Sequence object (sequence) and writes it in the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Sequence’s configuration information in external is in addition to the Sequence’s configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEISequenceConfig{} or is NULL.
Return Values
MPIMessageOK if SequenceConfigGet successfully gets and writes the configuration of a Sequence object into the structure(s)
See Also | mpiSequenceConfigSet | MEISequenceConfig


mpiSequenceConfigSet

Declaration
long mpiSequenceConfigSet(MPISequence sequence,
                          MPISequenceConfig *config,
                          void *external)
Required Header stdmpi.h
Description

SequenceConfigSet sets the configuration of a Sequence (sequence) using data from the structure pointed to by config, and also using data from the implementation- specific structure pointed to by external (if external is not NULL).

The Sequence’s configuration information in external is in addition to the Sequence’s configuration information in config, i.e, the configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEISequenceConfig{} or is NULL.
Return Values
MPIMessageOK if SequenceConfigSet successfully sets a Sequence’s configuration using data from the structure(s)
See Also | mpiSequenceConfigGet | MEISequenceConfig


mpiSequenceCommand

Declaration
MPICommand mpiSequenceCommand(MPISequence sequence,
                              long        index)
Required Header stdmpi.h
Description

SequenceCommand returns the element at the position on the list indicated by index.

sequence | a handle to the Sequence object.
index | a position in the list.

Return Values
handle | to the indexth Command of a Sequence (sequence)
MPIHandleVOID | if sequence is invalid if index is less than 0 if index is greater than or equal to mpiSequenceCount(sequence)
MPIMessageARG_INVALID | if index is a negative number.
MEIListMessageELEMENT_NOT_FOUND | if index is greater than or equal to the number of elements in the list.
MPIMessageHANDLE_INVALID | if sequence is an invalid handle.
See Also


mpiSequenceCommandAppend

Declaration
long mpiSequenceCommandAppend(MPISequence sequence,
                              MPICommand  command)
Required Header stdmpi.h
Description

SequenceCommandAppend appends a Command (command) to a Sequence (sequence).

sequence | a handle to the Sequence object.
command | a handle to a Command object.

Return Values
MPIMessageOK | if SequenceCommandAppend successfully appends a Command to a Sequence
MPIMessageHANDLE_INVALID | Either sequence or command is an invalid handle.
MPIMessageNO_MEMORY | Not enough memory was available.
See Also


mpiSequenceCommandCount

Declaration
long mpiSequenceCommandCount(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceCommandCount returns the number of elements on the list.

sequence | a handle to the Sequence object.

Return Values
number of Commands | in a Sequence (sequence)
-1 | if sequence is invalid
0 | if sequence is empty
See Also


mpiSequenceCommandFirst

Declaration
MPICommand mpiSequenceCommandFirst(MPISequence  sequence)
Required Header stdmpi.h
Description

SequenceCommandFirst returns the first element in the list. This function can be used in conjuntion with mpiSequenceCommandNext() in order to iterate through the list.

sequence | a handle to the Sequence object.

Return Values
handle | to the first Command in a Sequence (sequence)
MPIHandleVOID | if sequence is invalid if sequence is empty
MPIMessageHANDLE_INVALID | if sequence is an invalid handle.

See Also | mpiSequenceCommandNext | mpiSequenceCommandLast


mpiSequenceCommandInsert

Declaration
long mpiSequenceCommandInsert(MPISequence sequence,
                              MPICommand  command,
                              MPICommand  insert)
Required Header stdmpi.h
Description

SequenceCommandInsert inserts a Command (insert) in a Sequence (sequence) just after the specified Command (command).

Return Values
MPIMessageOK if SequenceCommandInsert successfully inserts the Command (insert) in a Sequence following the specified Command (command)
See Also


mpiSequenceCommandIndex

Declaration
long mpiSequenceCommandIndex(MPISequence  sequence,
                             MPICommand   command)
Required Header stdmpi.h
Description

SequenceCommandIndex returns the position of "command" on the list.

sequence | a handle to the Sequence object.
command | a handle to a Command object.

Return Values
index | of a Command (command) in a Sequence (sequence)
-1 | if sequence is invalid if the Command (command) was not found in the Sequence (sequence)
See Also


mpiSequenceCommandLast

Declaration
MPICommand mpiSequenceCommandLast(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceCommandLast returns the last element in the list. This function can be used in conjuntion with mpiSequenceCommandPrevious() in order to iterate through the list backwards.

sequence | a handle to the Sequence object.

Return Values
handle | to the last Command in a Sequence (sequence)
MPIHandleVOID | if sequence is invalid if sequence is empty
MPIMessageHANDLE_INVALID | if sequence is an invalid handle.

See Also | mpiSequenceCommandFirst | mpiSequenceCommandPrevious | mpiSequenceCommandNext


mpiSequenceCommandListGet

Declaration
long mpiSequenceCommandListGet(MPISequence  sequence,
                               long         *commandCount,
                               MPICommand   *commandList)
Required Header stdmpi.h
Description

SequenceCommandListGet gets the Commands in a Sequence (sequence). SequenceCommandListGet writes the number of Commands [in a Sequence (sequence)] to the location (pointed to by commandCount), and also writes an array (of commandCount Command handles) to the location (pointed to by commandList).
Return Values
MPIMessageOK if SequenceCommandListGet successfully gets the list of Commands in a Sequence
See Also | mpiSequenceCommandListSet


mpiSequenceCommandListSet

Declaration
long mpiSequenceCommandListSet(MPISequence  sequence,
                               long         commandCount,
                               MPICommand   *commandList)
Required Header stdmpi.h
Description

SequenceCommandListSet creates a Sequence (sequence) of commandCount Commands using the Command handles specified by commandList. Any existing command Sequence is completely replaced.

The commandList parameter is the address of an array of commandCount Command handles, or is NULL (if commandCount is equal to zero).

You can also create a command Sequence incrementally (i.e., one command at a time), by using the Append and/or Insert methods. Use the List methods to examine and manipulate a command Sequence, regardless of how it was created.

Return Values
MPIMessageOK if SequenceCommandListGet successfully creates a Sequence of Commands using the Command handles specified by commandList
See Also | mpiSequenceCommandListGet


mpiSequenceCommandNext

Declaration
MPICommand mpiSequenceCommandNext(MPISequence sequence,
                                  MPICommand  command)
Required Header stdmpi.h
Description

SequenceCommandNext returns the next element following "command" on the list. This function can be used in conjuntion with mpiSequenceCommandFirst() in order to iterate through the list.

sequence | a handle to the Sequence object.
command | a handle to a Command object.

Return Values
handle | to the Command following the Command (command) in a Sequence (sequence)
MPIHandleVOID | if sequence is invalid if command is the last command in a Sequence (sequence)
MPIMessageHANDLE_INVALID | Either sequence or command is an invalid handle.

See Also | mpiSequenceCommandFirst | mpiSequenceCommandPrevious


mpiSequenceCommandPrevious

Declaration
MPICommand mpiSequenceCommandPrevious(MPISequence sequence,
                                      MPICommand  command)
Required Header stdmpi.h
Description

SequenceCommandPrevious returns the previous element prior to "command" on the list. This function can be used in conjuntion with mpiSequenceCommandLast() in order to iterate through the list backwards.

sequence | a handle to the Sequence object.
command | a handle to a Command object.

Return Values
handle | to the Command preceding the Command (command) in a Sequence (sequence)
MPIHandleVOID | if sequence is invalid if command is the first command in a Sequence (sequence)
MPIMessageHANDLE_INVALID | Either sequence or command is an invalid handle.

See Also | mpiSequenceCommandLast | mpiSequenceCommandNext


mpiSequenceCommandRemove

Declaration
long mpiSequenceCommandRemove(MPISequence sequence,
                              MPICommand  command)
Required Header stdmpi.h
Description

SequenceCommandRemove removes a Command (command) from a Sequence (sequence).
Return Values
MPIMessageOK if SequenceCommandRemove successfully removes the Command from a Sequence
See Also


mpiSequenceControl

Declaration
MPIControl mpiSequenceControl(MPISequence sequence)
Required Header stdmpi.h
Description SequenceControl returns a handle to the Control object with which the Sequence object is associated.
sequence | a handle to the Sequence object.

Return Values
MPIControl | a handle to the Sequence object
MPIHandleVOID | if sequence is invalid

See Also | mpiSequenceCreate | mpiControlCreate


meiSequenceCompile

Declaration
long meiSequenceCompile(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceCompile “compiles” a sequence object by reading its list of Command objects and then creating an equivalent list of XMP commands.

Return Values
MPIMessageOK if SequenceCompile successfully reads a Sequence object’s list of Command objects and creates an equivalent list of XMP commands
See Also


mpiSequenceCreate

Declaration
MPISequence mpiSequenceCreate(MPIControl control,
                              long       number,
                              long       pageSize)
Required Header stdmpi.h
Description

SequenceCreate creates a Sequence object associated with the program sequencer identified by number located on motion controller (control). SequenceCreate is the equivalent of a C++ constructor.

If | Then
number is -1 | SequenceCreate selects the next unused program sequencer. If this is the first use of the program sequencer, then SequenceCreate will attempt to allocate pageSize firmware command slots.
pageSize is -1 | SequenceCreate will allocate all remaining firmware command slots, which may prevent any more Sequence objects from being created.

Return Values
handle | to a Sequence object
MPIHandleVOID | if the object could not be created

See Also | mpiSequenceDelete | mpiSequenceValidate


mpiSequenceDelete

Declaration
long mpiSequenceDelete(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceDelete deletes a Sequence object and invalidates its handle (sequence). SequenceDelete is the equivalent of a C++ destructor.

All Command objects in a Sequence are deleted when the Sequence object is deleted.
Return Values
MPIMessageOK if SequenceDelete successfully a Sequence object and invalidates its handle
See Also | mpiSequenceCreate | mpiSequenceValidate


mpiSequenceEventNotifyGet

Declaration
long mpiSequenceEventNotifyGet(MPISequence   sequence,
                               MPIEventMask  *eventMask,
                               void          *external)
Required Header stdmpi.h
Description

SequenceEventNotifyGet writes an event mask [that specifies the event types (generated by the Sequence sequence, for which host notification has been requested] to the structure pointed to by eventMask, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The event mask information in external is in addition to the event mask information in eventMask, i.e, the event mask information in eventMask and in external is not the same information. Note that eventMask or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEIEventMask{} or is NULL.
Return Values
MPIMessageOK if SequenceEventNotifyGet successfully writes the event mask to the structure(s)
See Also | MEIEventMask | mpiSequenceEventNotifySet


mpiSequenceEventNotifySet

Declaration
long mpiSequenceEventNotifySet(MPISequence   sequence,
                               MPIEventMask  eventMask,
                               void          *external)
Required Header stdmpi.h
Description

SequenceEventNotifySet requests host notification of the event(s) specified by eventMask and generated by a Sequence (sequence), and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The event mask information in external is in addition to the event mask information in eventMask, i.e, the event mask information in eventMask and in external is not the same information. Note that eventMask or external can be NULL (but not both NULL).

The mask of event types generated by a Sequence object consists of MPIEventMaskEXTERNAL. When a Sequence issues a Command of type MPICommandTypeEVENT, an event of type MPIEventTypeEXTERNAL is generated. The only event generated by a Sequence is MPIEventTypeEXTERNAL, which is generated when a Sequence issues a Command of type MPICommandTypeEVENT.

To | Use "eventMask"
Disable host notification of all Sequence events | MPIEventTypeNONE
Enable host notification of all Sequence events | MPIEventMaskALL
XMP Only

external either points to a structure of type MEIEventMask{} or is NULL.
Return Values
MPIMessageOK if SequenceEventNotifySet successfully requests host notification of the events in the event mask(s)
See Also | MPIEventMaskEXTERNAL | MEIEventMask | mpiSequenceEventNotifyGet


mpiSequenceEventReset

Declaration
long mpiSequenceEventReset(MPISequence  sequence,
                           MPIEventMask eventMask)
Required Header stdmpi.h
Description

SequenceEventReset resets the event(s) that are specified in eventMask and generated by a Sequence (sequence). Your application should not call SequenceEventReset until one or more latchable events have occurred.

Return Values
MPIMessageOK if SequenceEventReset successfully resets the event(s) that are specified in eventMask and generated by a Sequence object
See Also


mpiSequenceFlashConfigGet

Declaration
long mpiSequenceFlashConfigGet(MPISequence       sequence,
                               void              *flash,
                               MPISequenceConfig *config,
                               void              *external)
Required Header stdmpi.h
Description

SequenceFlashConfigGet gets a Sequence’s (sequence) flash configuration and writes it into the structure pointed to by config, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The Sequence’s flash configuration information in external is in addition to the Sequence’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL). The implementation-specific flash argument is used to access flash memory.
XMP Only

external either points to a structure of type MEISequenceConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.

Return Values
MPIMessageOK if SequenceFlashConfigGet successfully writes the Sequence’s flash configuration to the structure(s)
See Also | mpiSequenceFlashConfigSet


mpiSequenceFlashConfigSet

Declaration
long mpiSequenceFlashConfigSet(MPISequence       sequence,
                               void              *flash,
                               MPISequenceConfig *config,
                               void              *external)
Required Header stdmpi.h
Description

SequenceFlashConfigSet sets a Sequence’s (sequence) flash configuration using data from the structure pointed to by config, and also using data from the implementation-specific structure pointed to by external (if external is not NULL).

The Sequence’s flash configuration information in external is in addition to the Sequence’s flash configuration information in config, i.e., the flash configuration information in config and in external is not the same information. Note that config or external can be NULL (but not both NULL). The implementation-specific flash argument is used to access flash memory.

XMP Only

external either points to a structure of type MEISequenceConfig{} or is NULL. flash is either an MEIFlash handle or MPIHandleVOID. If flash is MPIHandleVOID, an MEIFlash object will be created and deleted internally.
Return Values
MPIMessageOK if SequenceFlashConfigSet successfully sets the Sequence’s flash configuration using data from the structure(s)
See Also | MEISequenceConfig | mpiSequenceFlashConfigGet


mpiSequenceLoad

Declaration
long mpiSequenceLoad(MPISequence sequence,
                     MPICommand  command,
                     long        start)
Required Header stdmpi.h
Description

SequenceLoad loads the firmware command slots of a Sequence (sequence) as necessary, starting with the Command (command).

SequenceLoad is intended to be called initially by mpiSequenceStart(...) and called thereafter by mpiEventMgrService(...) (in response to reception of an internal page fault event notification from the firmware). Except when you are debugging a sequence via mpiSequenceStep(...), your application should never need to directly call SequenceLoad.

If | Then
command is MPIHandleVOID | SequenceLoad loads Commands starting with the first Command of the Sequence
start is not FALSE | SequenceLoad starts the sequence after the commands are loaded
Return Values
MPIMessageOK if SequenceLoad successfully loads the firmware command slots of a Sequence
See Also | mpiSequenceStart | mpiEventMgrService | mpiSequenceStep


mpiSequenceMemory

Declaration
long mpiSequenceMemory(MPISequence sequence,
                       void        **memory)
Required Header stdmpi.h
Description SequenceMemory writes an address [used to access a Sequence’s (sequence) memory] to the contents of memory. This address (or an address calculated from it) is passed as the src argument to mpiSequenceMemoryGet(...) and as the dst argument to mpiSequenceMemorySet(...).
Return Values
MPIMessageOK if SequenceMemory successfully writes the address (used to access Sequence memory) to the contents of memory
See Also | mpiSequenceMemoryGet | mpiSequenceMemorySet


mpiSequenceMemoryGet

Declaration
long mpiSequenceMemoryGet(MPISequence sequence,
                          void        *dst,
                          void        *src,
                          long        count)
Required Header stdmpi.h
Description SequenceMemoryGet copies count bytes of a Sequence’s (sequence) memory (starting at address src) to application memory (starting at address dst).
Return Values
MPIMessageOK if SequenceMemoryGet successfully copies count bytes of Sequence memory to application memory
See Also | mpiSequenceMemorySet | mpiSequenceMemory


mpiSequenceMemorySet

Declaration
long mpiSequenceMemorySet(MPISequence sequence,
                          void        *dst,
                          void        *src,
                          long        count)
Required Header stdmpi.h
Description

SequenceMemorySet copies count bytes of application memory (starting at address src) to a Sequence’s (sequence) memory (starting at address dst).

Return Values
MPIMessageOK if SequenceMemorySet successfully copies count bytes of application memory to a Sequence object’s memory
See Also | mpiSequenceMemory | mpiSequenceMemoryGet


mpiSequenceNumber

Declaration
long mpiSequenceNumber(MPISequence sequence,
                       long        *number)
Required Header stdmpi.h
Description

SequenceNumber writes the index of a Sequence (sequence, on the motion controller that the Sequence object is associated with) to the contents of number.

Return Values
MPIMessageOK if SequenceNumber successfully writes the Sequence’s index to the contents of number
See Also


mpiSequencePageSize

Declaration
long mpiSequencePageSize(MPISequence sequence,
                         long        *pageSize)
Required Header stdmpi.h
Description

SequencePageSize writes the number of command slots that are available to a Sequence (sequence, on its associated motion controller) to the contents of pageSize.
Return Values
MPIMessageOK if SequencePageSize successfully writes the number of command slots (available to the Sequence) to the contents of pageSize
See Also


mpiSequenceResume

Declaration
long mpiSequenceResume(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceResume resumes a Sequence (sequence) from the point where the Sequence has stopped (if execution has been stopped).
Return Values
MPIMessageOK if SequenceResume successfully resumes a Sequence from the point where the Sequence has stopped
See Also


mpiSequenceStep

Declaration
long mpiSequenceStep(MPISequence sequence,
                     long        count)
Required Header stdmpi.h
Description

SequenceStep executes count steps (Commands) of a stopped Sequence (sequence). After executing the Commands, the Sequence will be in the MPISequenceStateSTOPPED state.
Return Values
MPIMessageOK if SequenceStep successfully executes count steps (Commands) of a stopped Sequence
See Also


mpiSequenceStop

Declaration
long mpiSequenceStop(MPISequence sequence)
Required Header stdmpi.h
Description

SequenceStop stops a Sequence (sequence), if execution has been started. A stopped Sequence can be resumed from the point where it has stopped.
Return Values
MPIMessageOK if SequenceStop successfully stops a Sequence (while it is executing)
See Also | mpiSequenceStart


mpiSequenceStart

Declaration
long mpiSequenceStart(MPISequence sequence,
                      MPICommand  command)
Required Header stdmpi.h
Description

SequenceStart begins the execution of a Sequence (sequence), starting with the Command (command). If command is MPIHandleVOID, execution starts with the first command of the Sequence.
Return Values
MPIMessageOK if SequenceStart successfully begins the execution of a Command Sequence
See Also | mpiSequenceStop


mpiSequenceStatus

Declaration
long mpiSequenceStatus(MPISequence       sequence,
                       MPISequenceStatus *status,
                       void              *external)
Required Header stdmpi.h
Description

SequenceStatus returns the status of a Sequence (sequence), and writes it into the structure pointed to by status, and also writes it into the implementation-specific structure pointed to by external (if external is not NULL).

The status information in external is in addition to the status information in status, i.e, the status information in status and in external is not the same information. Note that status or external can be NULL (but not both NULL).

XMP Only

external either points to a structure of type MEISequenceStatus{} or is NULL.

Return Values
MPIMessageOK if SequenceStatus successfully returns the Sequence’s status and writes the status to the structure(s)
See Also | MPISequenceStatus


mpiSequenceValidate

Declaration
long mpiSequenceValidate(MPISequence sequence)
Required Header stdmpi.h
Description SequenceValidate validates the Sequence object and its handle (sequence).
Return Values
MPIMessageOK if Sequence is a handle to a valid object.
See Also | mpiSequenceCreate | mpiSequenceDelete


Service Objects

.

Service Objects

Introduction

A Service object creates and handles threads that help event managers dispatch events. Typically, one will use a Service Object to create threads that will call mpiEventMgrService(…) whenever an XMP interrupt occurs. They are a convenient way to have a program automatically deal with event managers and events. Thread handling is something that is different on every operating system. Service objects may therefore have different behaviors on different operating systems. Programmers that are experienced in multi-threaded application programming will probably want to program their own threads that will call mpiEventMgrService(…).

NOTE: The Service object is not part of the standard MPI. In order to use the Service Object, the file, apputil.h needs to be included by your code and the apputil library needs to be linked to your application.

Methods

Create, Delete, Validate Methods
 | ServiceCreate | Create a Service for EventMgr and the threads necessary for it to run.
 | ServiceDelete | Stop all threads belonging to the Service and deletes the Service.

Configuration and Information Methods
ServiceEnable Enable or disables the Service.


ServiceCreate

Declaration
const Service serviceCreate(MPIEventMgr eventMgr,
                            long        priority,
                            long        sleep)
Required Header service.h
Description

ServiceCreate creates threads for each control associated with eventMgr, flushes eventMgr, and starts threads with priority that call mpiEventMgrService(eventMgr, … ) every sleep milliseconds.

priority is a platform specific variable.

If "priority" is | Then
-1 | The operating system will choose some default priority for the service’s threads.
>0 | ServiceCreate will attempt to assign the priority to all of the service’s threads.

If "sleep" is | Then
-1 | ServiceCreate will attempt to create interrupt driven threads.
0 | ServiceCreate will create threads that call mpiEventMgrService(eventMgr,...) as quickly as possible.
>0 | ServiceCreate will create threads that attempt to call mpiEventMgrService(eventMgr,...) every sleep milliseconds.

Return Values
handle | to a Service object
MPIHandleVOID | if the Service could not be created

See Also | mpiEventMgrService | ServiceDelete


ServiceDelete

Declaration
long serviceDelete(Service service)
Required Header service.h
Description

ServiceDelete alerts all threads that they should end, waits for all threads to end, and frees the memory allocated to service.
Return Values
MPIMessageOK if serviceDelete successfully deletes a Service object and invalidates its handle
See Also | ServiceCreate


ServiceEnable

Declaration
long serviceEnable(Service service,
                   long    enabled)
Required Header service.h
Description

ServiceEnable enables or disables all threads belonging to Service.

If "enabled" is | Then
FALSE | serviceEnable will disable service.
TRUE | serviceEnable will enable service.

Return Values
handle | to a Service object
MPIHandleVOID | if the Service could not be created
See Also


SqNode Objects

.

SqNode Objects

Introduction

A SqNode object manages a single SynqNet network node connected to a SynqNet network. It represents the physical network node. It contains information about the node, as well as its status and configuration. It provides read/write access to the node via network cyclic data and service commands. It also provides an interface to any drives connected to the node.

During network initialization, the SynqNet nodes are discovered and mapped to the SynqNet object. The number of motors per SqNode is determined and mapped to the controller's motor objects. Each node connected to a controller is assigned a number (0, 1, 2, etc) in the order it is discovered. The node number is used to index the SqNode objects.

Methods

Create, Delete, Validate Methods
 | meiSqNodeCreate
 | meiSqNodeDelete
 | meiSqNodeValidate

Configuration and Information Methods
 | meiSqNodeCommand
 | meiSqNodeConfigGet
 | meiSqNodeConfigSet
 | meiSqNodeDriveConfigGet
 | meiSqNodeDriveConfigSet
 | meiSqNodeDriveInfo
 | meiSqNodeDriveMapParamCount
 | meiSqNodeDriveMapParamList
 | meiSqNodeDriveMapConfigCount
 | meiSqNodeDriveMapConfigList
 | meiSqNodeDriveMapParamFileGet
 | meiSqNodeDriveMapParamFileSet
 | meiSqNodeDriveMonitor
 | meiSqNodeDriveMonitorConfigGet
 | meiSqNodeDriveMonitorConfigSet
 | meiSqNodeDriveParamCalculate
 | meiSqNodeDriveParamClear
 | meiSqNodeDriveParamGet
 | meiSqNodeDriveParamListGet
 | meiSqNodeDriveParamListSet
 | meiSqNodeDriveParamReload
 | meiSqNodeDriveParamRestore
 | meiSqNodeDriveParamSet
 | meiSqNodeDriveParamStore
 | meiSqNodeInfo
 | meiSqNodeStatus

Action Methods
meiSqNodeDownload

Event Methods
 | meiSqNodeEventNotifyGet
 | meiSqNodeEventNotifySet
 | meiSqNodeEventReset

Memory Methods
 | meiSqNodeMemory
 | meiSqNodeMemoryGet
 | meiSqNodeMemorySet

Relational Methods
 | meiSqNodeControl
 | meiSqNodeNumber

Data Types

MEISqNodeCallback
MEISqNodeChannel
MEISqNodeCmdType
MEISqNodeCmdHeader
MEISqNodeCommand
MEISqNodeConfig
MEISqNodeConfigIoAbort
MEISqNodeConfigAlarm
MEISqNodeConfigPacketError
MEISqNodeConfigTrigger
MEISqNodeConfigUserFault
MEISqNodeDataSize
MEISqNodeDownloadParams
MEISqNodeDriveInfo
MEISqNodeDriveMonitor
MEISqNodeDriveMonitorConfig
MEISqNodeDriveMonitorData
MEISqNodeDriveMonitorDataType
MEISqNodeDriveParamCallback
MEISqNodeDriveParamCallbackType
MEISqNodeFpgaType
MEISqNodeInfo
MEISqNodeInfoFpga
MEISqNodeInfoId
MEISqNodeInfoNetwork
MEISqNodeMemory
MEISqNodeMessage
MEISqNodeMonitorValue
MEISqNodeMonitorValueIndex
MEISqNodeResponse
MEISqNodeStatus
MEISqNodeStatusCrcError
MEISqNodeStatusPacketError

Constants

MEISqNodeID_CHAR_MAX
MEISqNodeDriveParamMAX_STRING_LENGTH
MEISqNodeSTATUS_NOT_AVAILABLE


MEISqNodeCallback

MEISqNodeCallback

typedef long (*MEISqNodeCallback)(long percentage);
Description

SqNodeCallback is a pointer to a function, which can be used to monitor the meiSqNodeDownload(…) progress.

percentage | The portion (from 0% to 100%) of memory download that has been completed.

See Also | meiSqNodeDownload


MEISqNodeConfig

MEISqNodeConfig

typedef struct MEISqNodeConfig {
    MEISqNodeConfigAlarm        nodeAlarm;
    MEISqNodeConfigIoAbort      ioAbort;
    MEISqNodeConfigPacketError  upStreamError;
    MEISqNodeConfigPacketError  downStreamError;
    MEISqNodeConfigUserFault    userFault;
} MEISqNodeConfig;
Description

The SqNodeConfig structure specifies the SynqNet node configurations.

nodeAlarm | A structure to configure a SynqNet node's trigger conditions for the Node Alarm output bit. The node alarm circuit is node specific, but is intended to notify users when the node has a problem. The nodeAlarm occurs on an ioAbort, DedicatedInAMP_FAULT (one per motor/drive) or an FPGA fails to operate with run-time code. See MEISqNodeConfigIoAbort and MEISqNodeConfigNodeAlarm for the trigger configurations.
ioAbort | A structure to configure a SynqNet node's trigger conditions for an I/O Abort action. When an ioAbort is triggered, the SynqNet node's outputs are disabled (set to the power-on condition). See MEISqNodeConfigIoAbort for the trigger configurations.
upStreamError | A structure used to configure the fault and failure limits for the upstream SynqNet packets. The controller keeps track of how many bad packets are received from the Node and performs the appropriate actions when the fault and fail limits are reached. See MEISqNodeConfigPacketError for appropriate ranges and resulting actions.
downStreamError | A structure used to configure the fault and failure limits for the downstream SynqNet packets. The node keeps track of how many bad packets are received from the controller and performs the appropriate actions when the fault and fail limits are reached. See MEISqNodeConfigPacketError for appropriate ranges and resulting actions.
userFault | A structure to configure the trigger conditions for a SynqNet node user fault. When a user fault is triggered, a node ioAbort and/or an action on each motor will occur. See MEISqNodeConfigUserFault for the trigger configurations.

See Also | meiSqNodeConfigGet | meiSqNodeConfigSet | MEISqNodeConfigPacketError


MEISqNodeConfigNodeAlarm

.

MEISqNodeConfigAlarm

MEISqNodeConfigAlarm

typedef struct MEISqNodeConfigAlarm {
    unsigned long   mask;              /* One bit per drive/motor. Triggered by
                                          the MEIMotorDedicatedInAMP_FAULT input. */
    long            notCyclicEnable;   /* allow nodeAlarm to be asserted when the node
                                          is not in cyclic mode */
    long            ioAbortEnable;     /* allow ioAbort to assert nodeAlarm	*/
} MEISqNodeConfigAlarm;
Description

The SqNodeConfigAlarm structure specifies the input trigger for the SynqNet node alarm output. The input triggers are the MEIMotorDedicatedInAMP_FAULT bits for each motor/drive interface.
mask Each bit in the mask represents a motor or drive interface. For example, a value of 0x3 will trigger the node alarm output when either motor 0’s OR motor 1’s MEIMotorDedicatedInAMP_FAULT bit is TRUE.
notCyclicEnable

This Boolean variable is used to specify whether or not a node can receive an alarm when it is not in cyclic mode.

TRUE = node alarm can be asserted in any mode.
FALSE = node alarm can only be asserted in cyclic mode.
ioAbortEnable

This Boolean variable is used to specify the effect an I/O abort will have on the node alarm output.

TRUE = an I/O abort will trigger a node alarm.
FALSE = an I/O abort will not necessarily trigger a node alarm.

See Also | meiSqNodeConfigGet | meiSqNodeConfigSet | MEIMotorDedicatedIn


MEISqNodeIoAbort

.

MEISqNodeConfigIoAbort

MEISqNodeConfigIoAbort

typedef struct MEISqNodeConfigIoAbort {
    MEISqNodeConfigTrigger   synqLost;     /* communication error */
    MEISqNodeConfigTrigger   nodeDisable;  /* external input */
    MEISqNodeConfigTrigger   powerFault;   /* analog power failure */
    long                     userFault;    /* TRUE = user fault causes ioabort */
} MEISqNodeConfigIoAbort;
Description

The SqNodeConfigIoAbort structure specifies the SynqNet node configurations to generate an I/O Abort action. When an ioAbort is triggered, the SynqNet node's outputs are disabled (set to the power-on condition). The IoAbort is triggered when any one or more of the following enabled configurations occur:

synqLost | Occurs when a SynqNet node drops out of SYNQ (cyclic) mode to SYNQ_LOST mode. See MEISqNodeConfigTrigger.
nodeDisable | An input bit to the SynqNet node. The node disable circuit is node specific, but is intended to shutdown the node via the IoAbort. See MEISqNodeConfigTrigger.
powerFault | An input bit to the SynqNet node. The power fault circuit is node specific, but is usually connected to an analog power monitor. Typically, when the DAC power or other analog component power is either too high or drops below a threshold, the power fault is triggered. Please see the node/drive manufacturer's documentation for details. See MEISqNodeConfigTrigger.
userFault | A user configurable trigger condition. A value of TRUE enables the trigger, FALSE disables the trigger.

See Also | meiSqNodeConfigGet | meiSqNodeConfigSet


MEISqNodeConfigPacketError

MEISqNodeConfigPacketError

typedef struct MEISqNodeConfigPacketError {
    long faultLimit;    /* 0 - 255 */
    long failLimit;     /* 0 - 255 */
} MEISqNodeConfigPacketError;
Description

The SqNodeConfigPacketError structure specifies the limit conditions for SynqNet node packet rate errors.

faultLimit | Packet error rate limit to generate a fault. When the faultLimit is reached, the node will attempt to recover by switching the port used for data transmission. Valid range is 0 to 255. The value saturates at 255.
failLimit | Packet error rate limit to generate a failure. When the failLimit is reached, the node will drop to the SYNQ_LOST state and disable its outputs. Valid range is 0 to 255. The value saturates at 255.

See Also | meiSqNodeConfigGet | meiSqNodeConfigSet


MEISqNodeConfigTrigger

MEISqNodeConfigTrigger

typedef struct MEISqNodeConfigTrigger {
    long    enable;
    long    invert;
} MEISqNodeConfigTrigger;
Description

The SqNodeConfigTrigger structure specifies trigger configurations.

enable | Enables or disables the trigger. A value of TRUE enables the trigger, FALSE disables the trigger.
invert | Normal or inverted trigger polarity. A value of FALSE indicates normal polarity, TRUE indicates inverted polarity.

See Also | MEISqNodeConfigIoAbort


MEISqNodeConfigUserFault

MEISqNodeConfigUserFault

typedef struct MEISqNodeConfigUserFault {
    long            *addr;    /* firmware addr */
    unsigned long   mask;
    unsigned long   pattern;
} MEISqNodeConfigUserFault;
Description

The SqNodeConfigUserFault structure specifies the trigger conditions for a user defined input. The trigger condition can be configured for any controller address. When the masked value at the specified addr matches the pattern, the user fault is active. The user fault triggers a SynqNet node IoAbort if the userFault flag in MEISqNodeConfigIoAbort{…} is enabled. The user fault also triggers an action for all the motors associated with the node. The userFaultAction is specified in the MEIMotorConfig{…} structure.

*addr | A pointer to a controller address.
mask | A bit mask ANDed with the value at the controller address.
pattern | A bit pattern compared to the masked value at the controller address. When the masked value equals the pattern, the user trigger is TRUE.

See Also | MEISqNodeConfigIoAbort | MEIMotorConfig | meiSqNodeConfigGet | meiSqNodeConfigSet


MEISqNodeChannel

MEISqNodeChannel

typedef enum MEISqNodeChannel {
    MEISqNodeChannelDRIVE0,
    MEISqNodeChannelDRIVE1,
    MEISqNodeChannelDRIVE2,
    MEISqNodeChannelDRIVE3,
    MEISqNodeChannelDRIVE4,
    MEISqNodeChannelDRIVE5,
    MEISqNodeChannelDRIVE6,
    MEISqNodeChannelDRIVE7,
    MEISqNodeChannelNODE,

} MEISqNodeChannel;
Description

SqNodeChannel is an enumeration of communication interfaces to a node. All SynqNet nodes support a single NODE channel to the network interface device. SynqNet nodes may support one or more drive channels to a drive processor. DRIVE channels are indexed by an enumeration (DRIVE0, DRIVE1, DRIVE2, etc.).

MEISqNodeChannelDRIVE0 | interface to drive number 0
MEISqNodeChannelDRIVE1 | interface to drive number 1
MEISqNodeChannelDRIVE2 | interface to drive number 2
MEISqNodeChannelDRIVE3 | interface to drive number 3
MEISqNodeChannelDRIVE4 | interface to drive number 4
MEISqNodeChannelDRIVE5 | interface to drive number 5
MEISqNodeChannelDRIVE6 | interface to drive number 6
MEISqNodeChannelDRIVE7 | interface to drive number 7
MEISqNodeChannelNODE | interface to the node device

See Also | meiSqNodeCommand | meiSqNodeDownload


MEISqNodeCommand

MEISqNodeCommand

typedef struct MEISqNodeCommand {
    MEISqNodeCmdHeader  header;
    unsigned long       address;  /* command resgisters */
    unsigned long       data;     /* command data */
} MEISqNodeCommand;
Description

The SqNodeCommand structure specifies the service command. It includes a header structure (channel, memory, size, and type), a destination address, and the data.

header | A structure that specifies the channel, memory region, and data size. See MEISqNodeCmdHeader.
address | A memory location to read or write the data.
data | The command data to send.

See Also | meiSqNodeCommand | MEISqNodeResponse


MEISqNodeCmdHeader

MEISqNodeCmdHeader

typedef struct MEISqNodeCmdHeader {
    MEISqNodeChannel    channel;    /* internal node destination */
    MEISqNodeMemory     memory;
    MEISqNodeDataSize   size;
    MEISqNodeCmdType    type;       /* read/write command */
} MEISqNodeCmdHeader;
Description

The SqNodeCmdHeader structure specifies the service command communication interface to the device, the memory region on the device to access, the data size, and type.

channel | Communication interface to a device. See MEISqNodeChannel.
memory | The memory region to access. See MEISqNodeMemory.
size | The length of data to send or receive. See MEISqNodeDataSize.
type | The service command action (read or write). See MEISqNodeCmdType.

See Also | meiSqNodeCommand | MEISqNodeCommand


MEISqNodeCmdType

MEISqNodeCmdType

typedef enum MEISqNodeCmdType {
    MEISqNodeCmdTypeREAD,
    MEISqNodeCmdTypeWRITE,
} MEISqNodeCmdType;
Description

SqNodeCmdType is an enumeration of service command types to send to a node or drive.

MEISqNodeCmdTypeREAD | read data
MEISqNodeCmdTypeWRITE | write data

See Also | meiSqNodeCommand | MEISqNodeCmdHeader


MEISqNodeDownloadParams

MEISqNodeDownloadParams

typedef struct MEISqNodeDownloadParams {
    char                *filename;
    MEISqNodeChannel    channel;
    MEISqNodeCallback   callback;
} MEISqNodeDownloadParams;
Description

The SqNodeDownloadParams structure specifies the parameters for downloading a binary image to a SynqNet node.

*filename | A pointer to a file name. The file contains a header and binary code/data. Files are node/drive specific. Please see the Node Binary Files: Product Table or the drive manufacturer's documentation for the drive binary files.
channel | A communication interface to a node's logic device or drive processor. See MEISqNodeChannel.
callback | A pointer to a callback function, to monitor the download progress. See MEISqNodeCallback.

See Also | meiSqNodeDownload


MEISqNodeDriveInfo

MEISqNodeDriveInfo

typedef struct MEISqNodeDriveInfo {
    char    firmwareVersion[MEISqNodeDriveParamMAX_STRING_LENGTH];
} MEISqNodeDriveInfo;
Description

SqNodeDriveInfo is a structure containing information about a specified drive.

firmwareVersion | A string containing drive firmware version information that is retrieved from the Drive Processor on the Node.
See Also


MEISqNodeDriveMonitor

MEISqNodeDriveMonitor

typedef struct MEISqNodeDriveMonitor {
    MEISqNodeDriveMonitorDataType    type;
    MEISqNodeDriveMonitorData        data;
} MEISqNodeDriveMonitor;
Description

The SqNodeDriveMonitor structure specifies the data to be placed in the monitor field by the drive.

type | The drive data is selected by its type. See MEISqNodeDriveMonitorDataType.
data | The location of the drive data. See MEISqNodeDriveMonitorData.

See Also | MEISqNodeMonitorValue | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet


MEISqNodeDriveMonitorConfig

MEISqNodeDriveMonitorConfig

typedef struct MEISqNodeDriveMonitorConfig {
    MEISqNodeDriveMonitor    monitorA;
    MEISqNodeDriveMonitor    monitorB;
    MEISqNodeDriveMonitor    monitorC;
}MEISqNodeDriveMonitorConfig;
Description

The SqNodeDriveMonitorConfig structure specifies the configuration for the drive monitor fields.

monitorA | configuration for drive monitor A
monitorB | configuration for drive monitor B
monitorC | configuration for drive monitor C

See Also | MEISqNodeDriveMonitor | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet |


MEISqNodeDriveMonitorData

MEISqNodeDriveMonitorData

typedef union {
    long    index;     /* the values for these parameters are drive specific	*/
    long    address;   /* and can be found in the appropriate drive modules	*/
} MEISqNodeDriveMonitorData;
Description

SqNodeDriveMonitorData specifies the location of the monitor data. Drive data can be specified by either an index or an address. The location is drive specific. Please see the drive manufacturer's documentation.

index | A drive specific value to select a monitor data field from a table.
address | A drive specific memory address to select the monitor data.

See Also | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet


MEISqNodeDriveMonitorDataType

MEISqNodeDriveMonitorDataType

typedef enum MEISqNodeDriveMonitorDataType {
    MEISqNodeDriveMonitorDataTypeINDEX,
    MEISqNodeDriveMonitorDataTypeADDRESS,
} MEISqNodeDriveMonitorDataType;
Description

SqNodeDriveMonitorDataType is an enumeration of monitor data selection types.

MEISqNodeDriveMonitorDataTypeINDEX | Select monitor data using an index to a table.
MEISqNodeDriveMonitorDataTypeADDRESS | Select monitor data using an address.

See Also | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet


MEISqNodeDriveParamCallback

MEISqNodeDriveParamCallback

typedef void (*MEISqNodeDriveParamCallback)
             (MEISqNodeDriveParamCallbackType  type,
              char                             *name,
              long                             number,
              char                             *value);
Description

In the SqNodeDriveParamCallback structure, the function's pointer type defines a function that can be passed to the meiSqNodeDriveParamFileSet function. The meiSqNodeDriveParamFileSet function will call this type of function to report progress or warnings. A NULL value for the callback pointer will disable the callback feature.

type | the type of event that caused the callback function to be called.
name | name of the drive parameter.
number | drive parameter index.
value | the value of the drive parameter.

See Also | meiSqNodeDriveParamFileSet


MEISqNodeDriveParamCallbackType

MEISqNodeDriveParamCallbackType

typedef enum {
    MEISqNodeDriveParamCallbackTypeCHANGED,
    MEISqNodeDriveParamCallbackTypeSET_FAILED,
} MEISqNodeDriveParamCallbackType;
Description

The SqNodeDriveParamCallbackType enumeration is used by the MEISqNodeDriveParamCallback function to describe the type of event that caused the callback function to be called.

MEISqNodeDriveParamCallbackTypeCHANGED | This indicates that the new drive parameter value is different to the current parameter value.
MEISqNodeDriveParamCallbackTypeSET_FAILED | Setting this drive parameter failed.

See Also | MEISqNodeDriveParamCallback


MEISqNodeDataSize

MEISqNodeDataSize

typedef enum MEISqNodeDataSize {  /* read/write data width */
    MEISqNodeDataSize8BIT,
    MEISqNodeDataSize16BIT,
    MEISqNodeDataSize24BIT,
    MEISqNodeDataSize32BIT,
} MEISqNodeDataSize
Description

SqNodeDataSize is an enumeration of service command data lengths. The data length is in units of bits.

MEISqNodeDataSize8BIT | 8 bit data length
MEISqNodeDataSize16BIT | 16 bit data length
MEISqNodeDataSize24BIT | 24 bit data length
MEISqNodeDataSize32BIT | 32 bit data length

See Also | meiSqNodeCommand | MEISqNodeCmdHeader


MEISqNodeFpgaType

MEISqNodeFpgaType

typedef enum MEISqNodeFpgaType {
    MEISqNodeFpgaTypeBOOT,
    MEISqNodeFpgaTypeRUN_TIME,
} MEISqNodeFpgaType
Description

sqNodeFpgaType is an enumeration of FPGA types.

MEISqNodeFpgaTypeBOOT | The FPGA is operating with a boot image. The boot image only supports basic SynqNet communication. Use meiSqNodeDownload(…) to download the runtime image to the SynqNet node.
MEISqNodeFpgaTypeRUN_TIME | The FPGA is operating with a runtime image.

See Also | meiSqNodeInfo | MEISqNodeInfoFpga | meiSqNodeDownload


MEISqNodeID_CHAR_MAX

MEISqNodeID_CHAR_MAX

#define	MEISqNodeID_Char_MAX  (30)

Description
 | sqNodeID_CHAR_MAX defines the maximum length (number of characters) in a sqNode identification string.
See Also


MEISqNodeInfo

MEISqNodeInfo

typedef struct MEISqNodeInfo {
    long                    motorCount;
    long                    driveCount;
    long                    motorOffset;
    MEISqNodeInfoId         id;
    MEISqNodeInfoFpga       fpga;
    MEISqNodeInfoNetwork    network;
} MEISqNodeInfo;
Description

The SqNodeInfo structure contains static data stored for the SynqNet node. The motor objects are indexed sequentially across all the SynqNet nodes associated with each network. Each motor on a controller has a unique number.

motorCount | The number of motors that the SynqNet node supports.
driveCount | The number of drives interfaces that the SynqNet node supports.
motorOffset | The starting number for the first motor on the SynqNet node.
id | A structure that contains identification data for the SynqNet node. See MEISqNodeInfoId.
fpga | A structure that contains identification data for the SynqNet node FPGA. See MEISqNodeInfoFpga.
network | A structure that contains network interface information for the SynqNet node. See MEISqNodeInfoNetwork.

See Also | meiSqNodeInfo


MEISqNodeInfoFpga

MEISqNodeInfoFpga

typedef struct MEISqNodeInfoFpga {
    MEISqNodeFpgaType          type;
    unsigned           long    vendorDevice;
    unsigned           long    version;
} MEISqNodeInfoFpga;
Description

The SqNodeInfoFpga structure contains identification data for the SynqNet node FPGA.

type | The FPGA type. See MEISqNodeFpgaType.
vendorDevice | A 32 bit value that identifies the FPGA image. The upper 16 bits represent the manufacturer of the SynqNet node network interface device. Each manufacturer has a unique vendor value. The lower 16 bits represent the SynqNet node network interface component. The device is typically an FPGA (could be an ASIC). If the device is an FPGA, the vendorDevice information is stored in the FPGA binary image. Each device for a particular vendor has a unique device value. Typically, the vendorDevice value is displayed in hexadecimal format.
version | A 32 bit value that represents the revision of the device. The upper 16 bits represent the SynqNet network interface revision. The lower 16 bits represent the device revision. Typically, the version value is displayed in hexadecimal format.

See Also | meiSqNodeInfo | MEISqNodeInfoId


MEISqNodeInfoId

MEISqNodeInfoId

typedef struct MEISqNodeInfoId {
    unsigned  long   nodeType;   /* product/mfg code   */
    char             *nodeName;  /* product/mfg string */
    unsigned  long   option;     /* product option code*/
    unsigned  long   switchId;   /* rotary switch id   */
    unsigned  long   unique;     /* unique id code     */

    long             exactMatch; /* TRUE/FALSE         */

    char             serialNumber[MEISqNodeID_CHAR_MAX];
    char             modelNumber[MEISqNodeID_CHAR_MAX];
} MEISqNodeInfoId;
Description

The SqNodeInfoId structure contains identification data for the SynqNet node.
nodeType | A 32 bit value that identifies the node hardware. The upper 16 bits represent the manufacturer of the SynqNet node hardware. Each manufacturer has a unique value. The lower 16 bits represent the SynqNet node product type. The SynqNet node manufacturer determines a unique value to track a product series. Typically, the node type value is displayed in hex.
*nodeName | A string that represents the SynqNet nodeType. The nodeName string matches the name of the SqNodeLib node specific header file.
option | The product option code within a product series.
switchId

If a node/drive have an physical address switch on its faceplate, switchId will contain the value to which the switch is set. If an ID switch is not supported by a node, this value will be set to -1 (0xFFFFFFFF).

unique

A 32 bit value that identifies the node. The SynqNet node manufacturer determines this unique value to track a single product. This is useful to determine when individual nodes of the same type are switched or replaced.

NOTE: It is possible for a manufacturer to use the same unique identification number for two nodes of different models. The combination of SqNode.Name and SqNode.UniqueId will be unique for any given code.
exactMatch | A string that tells you if the node is running under a matched or unmatched classification. The value of meiSqNodeInfo.id.exactMatch is TRUE when all ID components have been matched to a supported configuration. The value is FALSE when running with a default (unmatched) configuration.
serialNumber | A string that represents the SynqNet node serial number. For a given node type, the serial number is unique. The SynqNet node manufacturer determines the serial number to track an individual unit.
modelNumber | A string that represents the SynqNet node model number. The SynqNet node manufacturer determines the model number.
See Also | meiSqNodeInfo | MEISqNodeInfoFpga


MEISqNodeInfoNetwork

MEISqNodeInfoNetwork

typedef struct MEISqNodeInfoNetwork {
    long    number;
    long    inPorts;
    long    outPorts;
} MEISqNodeInfoNetwork;
Description

The SqNodeInfoNetwork structure contains information about the SynqNet node's network interface.

number | An index to a SynqNet network associated with a controller.
inPorts | The number of SynqNet IN port network interfaces.
outPorts | The number of SynqNet OUT port network interfaces.

Remarks
 | The labeling convention for IN and OUT ports is for convenience. The hardware ports are identical. During SynqNet initialization, the node are discovered based on the OUT to IN port connections.

See Also | meiSqNodeInfo


MEISqNodeMemory

MEISqNodeMemory

typedef enum MEISqNodeMemory {
    MEISqNodeMemoryDATA,       /* node/drive processor RAM */
    MEISqNodeMemoryPROGRAM,    /* drive processor program memory */
    MEISqNodeMemoryIO,         /* drive I/O memory */
    MEISqNodeMemoryDRIVE,      /* direct command to drive */
} MEISqNodeMemory;
Description

SqNodeMemory is an enumeration of drive region types to access with a service command.

MEISqNodeMemoryDATA | node/drive processor data memory
MEISqNodeMemoryPROGRAM | drive processor program memory
MEISqNodeMemoryIO | drive I/O memory
MEISqNodeMemoryDRIVE | direct command to drive processor

See Also | MEISqNodeCmdHeader | meiSqNodeCommand


MEISqNodeMessage

MEISqNodeMessage

typedef enum {
    MEISqNodeMessageINVALID,
    MEISqNodeMessageMAP_NETWORK_MISMATCH,
    MEISqNodeMessageMAP_CONFIG_MISMATCH,
    MEISqNodeMessageNOT_IN_CONFIG_FILE,
    MEISqNodeMessageCONFIG_FILE_FORMAT_INVALID,
} MEISqNodeMessage;
Description

SqNodeMessage is an enumeration of SynqNet node error messages that can be returned by the MPI library.

MEISqNodeMessageINVALID
 | The SqNode type is out of range. This message code is returned by SynqNet node methods if the node type is not a member of the SQNodeLibNodeType enumeration.
MEISqNodeMessageMAP_NETWORK_MISMATCH
 | The type of map file specified in meiSqNodeDriveParamFileSet does not match the type of drive found on the network.
MEISqNodeMessageMAP_CONFIG_MISMATCH
 | The parameter name or number specified in meiSqNodeDriveMapParamFileSet was not valid for the specified drive.
MEISqNodeMessageNOT_IN_CONFIG_FILE
 | The parameter name or number specified in meiSqNodeDriveMapParamFileSet was not found.
MEISqNodeMessageCONFIG_FILE_FORMAT_INVALID
 | A file with an incorrect format was used in meiSqNodeDriveMapParamFileSet.

See Also | meiSqNodeDriveMapParamFileSet


MEISqNodeMonitorValue

MEISqNodeMonitorValue

typedef struct MEISqNodeMonitorValue {
    long    count;
    long    monitor[MEISqNodeMonitorValueIndexLAST];
} MEISqNodeMonitorValue;
Description

The SqNodeMonitorValue structure contains the data for the monitor fields read by the meiSqNodeDriveMonitor(…) method.

count | The number of monitor fields read. This specifies the size of the monitor array.
monitor | An array of monitor data fields. Each field is indexed by the MEISqNodeMonitorValueIndex enumeration.

See Also | meiSqNodeDriveMonitor | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet


MEISqNodeMonitorValueIndex

MEISqNodeMonitorValueIndex

typedef enum MEISqNodeMonitorValueIndex {
    MEISqNodeMonitorValueIndexA,
    MEISqNodeMonitorValueIndexB,
    MEISqNodeMonitorValueIndexC,
    MEISqNodeMonitorValueIndexD,
} MEISqNodeMonitorValueIndex;
Description

SqNodeMonitorValueIndex is an enumeration of indices to node monitor values.

MEISqNodeMonitorValueIndexA | Index to node monitor value A.
MEISqNodeMonitorValueIndexB | Index to node monitor value B.
MEISqNodeMonitorValueIndexC | Index to node monitor value C.
MEISqNodeMonitorValueIndexD | Index to node monitor value D.

See Also | meiSqNodeDriveMonitor | meiSqNodeDriveMonitorConfigGet | meiSqNodeDriveMonitorConfigSet


MEISqNodeResponse

MEISqNodeResponse

typedef struct MEISqNodeResponse {
    unsigned long    data;    /* response data */
} MEISqNodeResponse;
Description

The SqNodeResponse structure contains the service command response data.

data | The response information from a service command. The data field is only valid for MEISqNodeCmdTypeREAD command types.

See Also | meiSqNodeCommand


MEISqNodeStatus

MEISqNodeStatus

typedef struct MEISqNodeStatus {
    MEISqNodeStatusPacketError   upStreamError;
    MEISqNodeStatusPacketError   downStreamError;
    MEISqNodeStatusCrcError      crcError;
    MPIEventMask                 eventMask;
} MEISqNodeStatus;
Description

The SqNodeStatus structure contains error counters and the eventMask for a SynqNet node.

upStreamError | The rate and count of bad synqNet messages received by the controller from the Node. See MEISqNodeStatusPacketError.
downStreamError | The rate and count of bad synqNet messages received by the Node from the controller. See MEISqNodeStatusPacketError.
crcError | Counters for the CRC errors. See MEISqNodeStatusCrcError.
eventMask | Array that defines the event mask bits. The array is defined as: typedef MPIEventMaskELEMENT_TYPE MPIEEventMask[MPIEventMaskELEMENTS] The bits are defined by the MPI/MEIEventType enumerations.

See Also | meiSqNodeStatus | meiSynqNetStatus | MEISqNodeConfig


MEISqNodeStatusCrcError

MEISqNodeStatusCrcError

typedef struct MEISqNodeStatusCrcError {
    long    port[MEINetworkPortLAST];
} MEISqNodeStatusCrcError;
Description

The SqNodeStatusCrcError structure contains CRC error counters for each network port. The CRC error counters are helpful for diagnosing data integrity problems. The counter increments for any CRC error on any packet received at that port (whether the packet is addressed to the node or not). The CRC error counters are cleared during network initialization.

port | An array of CRC error counters. Each network port has one CRC error counter. The valid range is 0 to 255. The value saturates at 255.

See Also | meiSqNodeStatus | MEINetworkPort


MEISqNodeSTATUS_NOT_AVAILABLE

MEISqNodeSTATUS_NOT_AVAILABLE

#define  MEISqNodeSTATUS_NOT_AVAILABLE  (-1)

Description
 | With exception to MEISqNodeStatus.eventMaskValue, the SqNodeSTATUS_NOT_AVAILABLE value is assigned to all Node status variables when the Status is not available as a result of lost communication with the node.

See Also | MEISqNodeStatus


MEISqNodeStatusPacketError

MEISqNodeStatusPacketError

typedef struct MEISqNodeStatusPacketError {
    long    rate;
    long    count;
} MEISqNodeStatusPacketError;
Description

The SqNodeStatusPacketError structure contains packet error counters and rate counters. Each SynqNet node has a packet error counter and a packet error rate counter. Packets addressed to a node are checked for integrity.

The packet error counters are used to monitor long-term data integrity. These counters do not trigger any fault or fail actions. The packet error counter is incremented once for each missing or invalid packet. Typically, an application will periodically read the packet error counters and store the values in a log.

The packet error rate counters are used to trigger fault recovery and/or failure shutdown. The packet error rate counter is incremented for each missing or invalid packet and is decremented for 16 consecutive valid packets. Thus, the packet error rate counters can detect large errors over short periods of time or small errors over long periods of time.

rate | The packet error rate counter. The valid range is 0 to 255. The value saturates at 255.
count | The packet error counter. The valid range is 0 to 255. The value saturates at 255.

See Also | meiSqNodeStatus | MEISqNodeConfigPacketError


meiSqNodeConfigGet

Declaration
long meiSqNodeConfigGet(MEISqNode        node,
                        MEISqNodeConfig  *config,
                        MEIFlash         flash);
Required Header stdmei.h
Description

SqNodeConfigGet reads a SynqNet node's configuration and writes it into the structure pointed to by config.

If the flash handle is NULL, the configuration is read from the controller's external memory.

If the flash handle is valid, the configuration is read from the controller's flash memory.

node | a handle to a SynqNet node object.
*config | a pointer to a SynqNet node config structure.
flash | a handle to a flash object.

Return Values
MPIMessageOK | if SqNodeConfigGet successfully reads the node configuration.

See Also | meiSqNodeInfo | meiSqNodeDriveConfigGet


meiSqNodeConfigSet

Declaration
long meiSqNodeConfigSet(MEISqNode        node,
                        MEISqNodeConfig  *config,
                        MEIFlash         flash);
Required Header stdmei.h
Description

SqNodeConfigSet writes a SynqNet node's configuration from the structure pointed to by config. If the flash handle is NULL, the configuration is written to the controller's external memory. If the flash handle is valid, the configuration is written to the controller's flash memory.

node | a handle to a SynqNet node object
*config | a pointer to a SynqNet node config structure
flash | a handle to a flash object
Return Values
MPIMessageOK if SqNodeConfigGet successfully writes the node configuration.
See Also | meiSqNodeInfo | meiSqNodeDriveConfigSet


meiSynqNetCommand

.

meiSqNodeCommand

Declaration
long meiSqNodeCommand(MEISqNode         node,
                      MEISqNodeCommand  *command,
                      MEISqNodeResponse *response);
Required Header stdmei.h
Description

SqNodeCommand sends a service command to a SynqNet node using the data from the structure pointed to by command and writes the response into the structure pointed to by response. Service commands occur across the SynqNet network through a service channel. In SYNQ mode there is one service channel for each node. In ASYNQ mode there is one service channel for all nodes. The controller sends the command and waits for a response using a 4 state handshake. In SYNQ mode the service command data is sent through the cyclic packets, but due to the handshaking, it is not considered a cyclic operation.

For SynqNet nodes that have drive memory interfaces, service commands can be sent to drives. Also, the service commands supports access to drive data memory, program memory, I/O memory, and direct commands. Please see the MEISqNodeCommand{…} and MEISqNodeResponse{…} structures for more information. And be sure to consult the drive's header file in the (C:\MEI)\XMP\sqNodeLib\include directory, as well as, the drive manufacturer's manual for valid drive addresses.

node | a handle to a SynqNet node object
*command | a pointer to a SynqNet node command structure
*response | a pointer to a SynqNet node response structure

Return Values
MPIMessageOK | if SqNodeCommand successfully sends a service command and receives a response.
MPIMessageARG_INVALID | if the command pointer is NULL or the response pointer is NULL
MEISynqNetMessageRESPONSE_TIMEOUT | if the node does not respond to the service command.
MEISynqNetMessageREADY_TIMEOUT | if the node is busy and does not acknowledge the service command.

See Also | MEISqNodeCommand | MEISqNodeResponse | MEISqNodeCmdHeader | MEISqNodeCmdType | MEISqNodeDataSize | MEISqNodeMemory | MEISqNodeChannel


meiSynqNodeControl

.

meiSqNodeControl

Declaration
meiSqNodeControl(MEISqNode node);
Required Header stdmei.h
Description

SqNodeControl returns a handle to the control object associated with the SqNode object.

node | a handle to a SynqNet node object

Return Values
MPIControl | a handle to a control object
MPIHandleVOID | if node is not valid

See Also | meiSqNodeCreate | mpiControlCreate


meiSqNodeCreate

Declaration
meiSqNodeCreate(MPIControl  control,
                long        number)
Required Header stdmei.h
Description

SqNodeCreate creates a SqNode object identified by number, which is associated with a control object.

SqNodeCreate is the equivalent of a C++ constructor.

control | a handle to a Control object
number | an index to the SqNode. The first node number is 0, the second is 1, etc.

Return Values
handle | to a SqNode object. After creating a SqNode object it must be validated using meiSqNodeValidate().
MPIHandleVOID | if the object could not be created

See Also | meiSqNodeDelete | meiSqNodeValidate


meiSqNodeDelete

Declaration
long meiSqNodeDelete(MEISqNode  node);
Required Header stdmei.h
Description

SqNodeDelete deletes a SqNode object and invalidates its handle.

SqNodeDelete is the equivalent of a C++ destructor.

node | a handle of the SqNode object to delete in the reverse order to avoid memory leaks.
Return Values
MPIMessageOK if SqNode successfully deleted the object.
See Also | meiSqNodeCreate | meiSqNodeValidate


meiSqNodeDownload

Declaration
long meiSqNodeDownload(MEISqNode                node,
                       MEISqNodeDownloadParams  *params);
Required Header stdmei.h
Description

SqNodeDownload SqNodeDownload reads a binary image from a file and writes it into a SynqNet node's non-volatile storage. SynqNet nodes may support one or more drive interfaces. SqNodeDownload can also write binary images to a drives' non-volatile storage if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The SynqNet node binary files are node specific. Please see the Node Binary Files: Product Table.

The SynqNet drive binary files are drive specific. The SqNodeLib includes the drive specific code necessary to support various hardware download protocols. Please see the drive manufacturer's documentation for details. Use meiSqNodeInfo(…), to determine if the SynqNet node supports a drive interface and it's type.

The binary download process requires a significant amount of time, probably between 5 to 30 seconds, depending on the node/drive type and file size. A callback function pointer is provided in the MEISqNodeDownloadParams structure for the calling application to monitor the download progress.

node | a handle to a SynqNet node object
*params | a pointer to the download parameters structure.
Return Values
MPIMessageOK if SqNodeNumber successfully reads the network number
See Also | meiSqNodeInfo | meiSynqNetInfo | MEISqNodeDownloadParams | MEISqNodeChannel | MEISqNodeCallback


meiSqNodeDriveConfigGet

Declaration
long meiSqNodeDriveConfigGet(MEISqNode  node,
                             long       driveIndex, /* relative to the node */
                             void       *config);   /* node specific        */
Required Header stdmei.h
Description

SqNodeDriveConfigGet reads a SynqNet node's drive configuration and writes it into a drive specific structure pointed to by config. SynqNet nodes may support one or more drive interfaces. The drive configuration can be read if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The drive configuration structure is drive specific. The SqNodeLib includes the drive specific structures and methods. Please see the drive's header file in the (C:\MEI)\XMP\sqNodeLib\include directory, as well as, the drive manufacturer's documentation for details. Use meiSqNodeInfo(…), to determine if the SynqNet node supports a drive interface and it's type.

node | a handle to a SynqNet node object
driveIndex | an index to a drive interface on a SynqNet node. The first drive interface is 0, the second is 1, etc.
*config | a pointer to a drive specific configuration structure.
Return Values
MPIMessageOK if SqNodeDriveConfigGet successfully reads the drive configuration.
See Also | meiSqNodeInfo | meiSqNodeDriveInfo | meiSqNodeConfigGet |


meiSqNodeDriveConfigSet

Declaration
long meiSqNodeDriveConfigSet(MEISqNode  node,
                             long       driveIndex, /* relative to the node */
                             void       *config);   /* node specific        */
Required Header stdmei.h
Description

SqNodeDriveConfigSet writes a SynqNet node's drive configuration from a drive specific structure pointed to by config. SynqNet nodes may support one or more drive interfaces. The drive configuration can be written if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The drive configuration structure is drive specific. The SqNodeLib includes the drive specific structures and methods. Please see the drive manufacturer's documentation for details. Use meiSqNodeInfo(…), to determine if the SynqNet node supports a drive interface and its type.

node | a handle to a SynqNet node object
driveIndex | an index to a drive interface on a SynqNet node. The first drive interface is 0, the second is 1, etc.
*config | a pointer to a drive specific configuration structure.
Return Values
MPIMessageOK if SqNodeDriveConfigSet successfully writes the drive configuration.
See Also | meiSqNodeInfo | meiSqNodeDriveInfo | meiSqNodeConfigSet |


meiSqNodeDriveInfo

Declaration
long meiSqNodeDriveInfo(MEISqNode          node,
                        long               driveIndex, /* relative to the node */
                        MEISqNodeDriveInfo *info,
                        void               *external);  /* node specific */
Required Header stdmei.h
Description

SqNodeDriveInfo reads a SynqNet node's drive information and writes it into a drive specific structure pointed to by info. The drive info structure contains read only data. SynqNet nodes may support one or more drive interfaces. The drive information can be read if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The drive information structure is drive specific. The SqNodeLib includes the drive specific structures and methods. Please see the drive's header file for the drive specific information structures, as well as, the drive manufacturer's documentation for details. All supported drive header files are located in the (C:\MEI)\XMP\sqNodeLib\include directory. Use meiSqNodeInfo(…), to determine if the SynqNet node supports a drive interface and it's type.

node | a handle to a SynqNet node object.
driveIndex | an index to a drive interface on a SynqNet node. The first drive interface is 0, the second is 1, etc.
*info | a pointer to a structure that contains general drive information.
*external | a pointer to a drive specific information structure. See the appropriate drive vendor *.h for definition. (NOTE: it can be NULL)

Return Values
MPIMessageOK | if SqNodeDriveInfo successfully reads the drive information.

See Also | meiSqNodeInfo | meiSqNodeConfigGet | meiSqNodeDriveConfigGet |


meiSqNodeDriveMapConfigCount

Declaration
long meiSqNodeDriveMapConfigCount (MEISqNode    sqNode,
                                   MEIDriveMap  driveMap,
                                   long         driveIndex,
                                   long         *configCount);
Required Header stdmei.h
Description

SqNodeDriveMapScanConfigCount scans the drive map file for a drive entry that matches this node on the network. If an entry is found, this function returns the number of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiSqNodeDriveMapConfigList function. This function is first called to get the size of the drive configuration list. Then the user can use this size to allocate enough memory to hold the complete configuration list before calling meiSqNodeDriveMapConfigList to fill in the list.

sqNode | a handle to a SynqNet node object.
driveMap | a handle to a DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
*configCount | pointer to the variable that will be set by this function.
Return Values
MPIMessageOK if meiSqNodeDriveMapConfigCount successfully scans the drive map file for a drive entry that matches this node on the network and returns the number of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiSqNodeDriveMapConfigList


meiSqNodeDriveMapConfigList

Declaration
long meiSqNodeDriveMapConfigList (MEISqNode    sqNode,
                                  MEIDriveMap  driveMap,
                                  long         driveIndex,
                                  long         configCount,
                                  long         *configList);
Required Header stdmei.h
Description

SqNodeDriveMapScanConfigList scans the drive map file for a drive entry that matches this node on the network. If an entry is found, this function returns the list of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiSqNodeDriveMapConfigCount function. The meiSqNodeDriveMapConfigCount function is first called to get the size of the drive configuration list. Then the user can use this size to allocate enough memory to hold the complete configuration list before calling this function to fill in the list.

sqNode | a handle to a SynqNet node object.
driveMap | a handle to a DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
configCount | the number of drive parameter information records that can be written to the configList list.
*configList | pointer to the list of drive parameters that make up the drive configuration that will be filled in by this function.
Return Values
MPIMessageOK if meiSqNodeDriveMapConfigList successfully scans the drive map file for a drive entry that matches this node on the network and returns the list of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiSqNodeDriveMapConfigCount


meiSqNodeDriveMapParamCount

Declaration
long meiSqNodeDriveMapParamCount (MEISqNode    sqNode,
                                  MEIDriveMap  driveMap,
                                  long         driveIndex,
                                  long         *paramsCount);
Required Header stdmei.h
Description

SqNodeDriveMapParamCount scans the drive map file for a drive entry that matches this node on the network. If an entry is found, then this function returns the number of drive parameters that need to be preserved for the configuration of the drive.

This function is normally used with the meiSqNodeDriveMapParamList function. First, this function is called in order to get the size of the drive parameter list. Then the user can use this size to allocate enough memory to hold the complete parameter list before calling meiSqNodeDriveMapParamList to fill in the list.

sqNode | a handle to a SynqNet node object.
driveMap | a handle to a DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
*paramsCount | pointer to the variable that will be set by this function.
Return Values
MPIMessageOK if meiSqNodeDriveMapParamCount successfully scans the drive map file for a drive entry that matches this node on the network and returns the number of drive parameters that need to be preserved for the configuration of the drive.
See Also | meiSqNodeDriveMapParamList


meiSqNodeDriveMapParamFileGet

Declaration
long meiSqNodeDriveMapParamFileGet(MEISqNode     sqNode,
                                   MEIDriveMap   driveMap,
                                   long          driveIndex,
                                   char          *driveConfigFilename,
                                   long          append);
Required Header stdmei.h
Description

SqNodeDriveMapParamFileGet saves the current set of drive parameters in the drive to the driveConfigFilename.
sqNode | a handle to the SynqNet node object.
driveMap | a handle to the DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
*driveConfigFilename | the name of the file that holds the stored drive configuration file.
append

1 = The new data is appended to the existing drive configuration file if it exists.

0 = A new drive configuration file is created to hold the drive parameters. If a file already exists, it will be overwritten.
Return Values
MPIMessageOK if SqNodeDriveMapParamFileGet successfully saves the current set of drive parameters in the drive to the driveConfigFilename.
See Also | meiSqNodeDriveMapParamFileSet


meiSqNodeDriveMapParamFileSet

Declaration
long meiSqNodeDriveMapParamFileSet(MEISqNode                   sqNode,
                                   MEIDriveMap                 driveMap,
                                   long                        driveIndex,
                                   char                        *driveConfigFilename,
                                   MEISqNodeDriveParamCallback callback,
                                   long                        warning);
Required Header stdmei.h
Description

SqNodeDriveMapParamFileSet loads the drive parameters stored in the file named driveConfigFilename into the drive.

sqNode | a handle to the SynqNet node object.
driveMap | a handle to the DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
*driveConfigFilename | the name of the file that holds the stored drive configuration file.
callback | A callback function that this function calls to indicate if the function is changing the value of a drive parameter or setting a new drive parameter that has failed. Passing NULL for this parameter will disable the callback feature.
warning | 0 = if setting a drive parameter fails, this function will fail immediately. 1 = if setting a drive parameter fails, then the function will continue with the remaining drive parameters and generate a warning by calling the callback function.
Return Values
MPIMessageOK if SqNodeDriveMapParamFileSet successfully loads the drive parameters stored in the file named driveConfigFilename into the drive.
See Also | meiSqNodeDriveMapParamFileGet


meiSqNodeDriveMapParamList

Declaration
long meiSqNodeDriveMapParamList (MEISqNode             sqNode,
                                 MEIDriveMap           driveMap,
                                 long                  driveIndex,
                                 long                  paramsCount,
                                 MEIDriveParamInfo     *driveParamInfo);
Required Header stdmei.h
Description

SqNodeDriveMapParamList scans the drive map file for an entry that matches the node on the network. If a drive entry is found, this function writes the drive parameter information about each of the drive parameters to the driveParamInfo list.

This function is normally used with the meiSqNodeDriveMapParamCount function. The meiSqNodeDriveMapParamCount function is called first to get the size of the parameter list, the user can then use this size to allocate enough memory to hold the complete parameter list before calling this function to fill in the parameter list.

sqNode | a handle to a SynqNet node object.
driveMap | a handle to a DriveMap object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
paramsCount | the number of drive parameter information records that can be written to the driveParamInfo list.
*driveParamInfo | pointer to the list of drive parameter information records that will be filled in by this function.
Return Values
MPIMessageOK if meiSqNodeDriveMapParamList successfully scans the drive map file for an entry that matches the node on the network and writes the information about each of the drive parameters to the driveParamInfo list.
See Also | meiSqNodeDriveMapParamCount


meiSqNodeDriveMonitor

Declaration
long meiSqNodeDriveMonitor(MEISqNode             node,
                           long                  driveIndex, /* relative to the node */
                           MEISqNodeMonitorValue *value);
Required Header stdmei.h
Description

SqNodeDriveMonitor reads the monitor fields from the drive and writes them into the structure pointed to by value.

node | a handle to a SynqNet node object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
*value | pointer to a structure of monitor values
Return Values
MPIMessageOK if SqNodeDriveMonitor successfully reads the monitor information.
See Also | MEISqNodeMonitorValue


meiSqNodeDriveMonitorConfigGet

Declaration
long meiSqNodeDriveMonitorConfigGet(MEISqNode    node,
                                    long         driveIndex, /* relative to the node */
                                    MEISqNodeDriveMonitorConfig   *config);
Required Header stdmei.h
Description

SqNodeDriveMonitorConfigGet reads a SynqNet node's drive monitor configuration and writes it into a structure pointed to by config. SynqNet nodes may support one or more drive interfaces. The drive monitor configuration can be read if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The SynqNet network packets have some extra fields that can be configured to read drive data every sample. Each monitor field is 32 bits. SynqNet nodes with drive interfaces that support drive monitoring can be configured to transmit the data. The drive manufacturer determines what data is available for monitoring. The monitor data can be specified by a predetermined index or memory address. Please see the drive's header file for the drive specific configuration structures, as well as, the drive manufacturer's documentation for details. All supported drive header files are located in the (C:\MEI)\XMP\sqNodeLib\include directory.

node | a handle to a SynqNet node object.
driveIndex | an index to a drive interface on a SynqNet node. The first drive interface is 0, the second is 1, etc.
*config | a pointer to a drive monitor configuration structure.
Return Values
MPIMessageOK if SqNodeDriveMonitorConfigGet successfully reads the drive monitor configuration.
See Also | meiSqNodeInfo | meiSqNodeDriveInfo


meiSqNodeDriveMonitorConfigSet

Declaration
long meiSqNodeDriveMonitorConfigSet(MEISqNode  node,
            long                          driveIndex,   /* relative to the node */
            MEISqNodeDriveMonitorConfig   *config);
Required Header stdmei.h
Description

SqNodeDriveMonitorConfigSet writes a SynqNet node's drive monitor configuration from a structure pointed to by config. SynqNet nodes may support one or more drive interfaces. The drive monitor configuration can be written if the drive interface hardware supports a communication channel to the drive processor. The drive interface(s) for a SynqNet node are indexed by a number (0, 1, 2, etc.).

The SynqNet network packets have some extra fields that can be configured to read drive data every sample. Each monitor field is 32 bits. SynqNet nodes with drive interfaces that support drive monitoring can be configured to transmit the data. The drive manufacturer determines what data is available for monitoring. The monitor data can be specified by a predetermined index or memory address. Please see the drive's header file for the drive specific configuration structures, as well as, the drive manufacturer's documentation for details. All supported drive header files are located in the (C:\MEI)\XMP\sqNodeLib\include directory.

node | a handle to a SynqNet node object.
driveIndex | an index to a drive interface on a SynqNet node. The first drive interface is 0, the second is 1, etc.
*config | a pointer to a drive monitor configuration structure.
Return Values
MPIMessageOK if SqNodeDriveMonitorConfigSet successfully writes the drive monitor configuration.
See Also | meiSqNodeInfo | meiSqNodeDriveInfo


meiSqNodeDriveParamCalculate

Declaration
long meiSqNodeDriveParamCalculate(MEISqNode    sqNode,
                                  long         driveIndex);
Required Header stdmei.h
Description

Some drives need to calculate some internal quantities after a drive parameter has been changed. The SqNodeDriveParamCalculate function will instruct the drive to calculate its internal quantities. This feature is not supported or required by all drives.

sqNode | a handle to a SynqNet node object
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
Return Values
MPIMessageOK if SqNodeDriveParamCalculate successfully has the drive to calculate its internal quantities.
See Also


meiSqNodeDriveParamClear

Declaration
long meiSqNodeDriveParamClear(MEISqNode    sqNode,
                              long         driveIndex);
Required Header stdmei.h
Description

SqNodeDriveParamClear clears the previously saved drive by loading the default set of drive parameters into the current and non-volatile storage on the drive. These drive parameters will be used each time this drive is subsequently started (after a power-on or network reset). The default drive parameters will take effect immediately.

NOTE: This function may not be supported by all drives. The default set of drive parameters may be different between different drive types and different drive manufactures.

sqNode | a handle to a SynqNet node object
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
Return Values
MPIMessageOK if SqNodeDriveParamClear successfully clears the previously saved drive by loading the default set of drive parameters into the current and non-volatile storage on the drive.
See Also | meiSqNodeDriveParamReload


meiSqNodeDriveParamGet

Declaration
long meiSqNodeDriveParamGet(MEISqNode                 node,
                            long                      driveIndex,
                            long                      param,
                            MEIDriveMapParamType      paramType,
                            MEIDriveMapParamValue     *value);
Required Header stdmei.h
Description

SqNodeDriveParamGet reads a drive parameter from the drive and fills in the appropriate field of the union pointed to by value. The paramType defines the type of data that is read from the drive and also defines which field will be used in the value union.

node | a handle to the SynqNet node object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
param | an index for the drive parameter that is being accessed.
paramType | the type of the data read from the drive and which field will be used in the value union.
*value | a pointer to the union that will be filled in.
Return Values
MPIMessageOK if SqNodeDriveParamGet successfully reads a drive parameter from the drive and fills in the appropriate field of the union pointed to by value.
See Also | meiSqNodeDriveParamSet


meiSqNodeDriveParamListGet

Declaration
long meiSqNodeDriveParamListGet(MEISqNode                 node,
                                long                      driveIndex,
                                long                      size,
                                long                      *paramList,
                                MEIDriveMapParamType      *paramTypes,
                                MEIDriveMapParamValue     *paramValues);
Required Header stdmei.h
Description

SqNodeDriveParamListGet reads a series of drive parameters from the drive and fills in the appropriate fields of the unions pointed to by paramValues. The paramTypes defines the type of data that is read from the drive and also defines which fields in the paramValues unions are going to be used.

node | a handle to the SynqNet node object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
size | the number of drive parameters to be read.
*paramList | a pointer to a list of the drive parameter indexes that are being accessed.
*paramTypes | a pointer to a list of drive parameter types to be read from the drive and which field in the paramValues union is going to be used.
*paramValues | a pointer to a list of unions that will be filled in by this function.
Return Values
MPIMessageOK if SqNodeDriveParamListGet successfully reads a series of drive parameters from the drive and fills in the appropriate fields of the unions pointed to by paramValues.
See Also | meiSqNodeDriveParamListSet


meiSqNodeDriveParamListSet

Declaration
long meiSqNodeDriveParamListSet(MEISqNode                 node,
                                long                      driveIndex,
                                long                      size,
                                MEIDriveMapParamType      *paramTypes,
                                long                      *paramList,
                                MEIDriveMapParamValue     *paramValues);
Required Header stdmei.h
Description

SqNodeDriveParamListSet writes a series of drive parameters pointed to by value to the drive. The paramTypes defines each type of data item that is written to the drive and also defines which field in the paramValues unions are going to be used.

node | a handle to the SynqNet node object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
size | the number of drive parameters to be written.
*paramTypes | a pointer to a list of the drive parameter indexes that are being accessed.
*paramList | a pointer to a list of drive parameter types to be written to the drive and which field in the paramValues union is going to be used.
*paramValues | a pointer to a list of unions that will be written to the drive.
Return Values
MPIMessageOK if SqNodeDriveParamListSet successfully writes a series of drive parameters pointed to by value to the drive.
See Also | meiSqNodeDriveParamListGet


meiSqNodeDriveParamReload

Declaration
long meiSqNodeDriveParamReload(MEISqNode    sqNode,
                               long         driveIndex);
Required Header stdmei.h
Description

SqNodeDriveParamReload overwrites the current set of drive parameters with the set from the non-volatile storage on the drive. These new drive parameters will take effect immediately.

sqNode | a handle to a SynqNet node object
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
Return Values
MPIMessageOK if SqNodeDriveParamReload successfully overwrites the current set of drive parameters with the set from the non-volatile storage on the drive.
See Also | meiSqNodeDriveParamClear


meiSqNodeDriveParamRestore

Declaration
long meiSqNodeDriveParamRestore(MEISqNode    sqNode,
                                long         driveIndex);
Required Header stdmei.h
Description

SqNodeDriveParamRestore loads the default set of drive parameters into current set of drive parameters on the drive. The default drive parameters will take effect immediately.

sqNode | a handle to a SynqNet node object
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
Return Values
MPIMessageOK if SqNodeDriveParamRestore successfully loads the default set of drive parameters into current set of drive parameters on the drive.
See Also | meiSqNodeDriveParamStore


meiSqNodeDriveParamSet

Declaration
long meiSqNodeDriveParamSet(MEISqNode                 node,
                            long                      driveIndex,
                            long                      param,
                            MEIDriveMapParamType      paramType,
                            MEIDriveMapParamValue     *value);
Required Header stdmei.h
Description

SqNodeDriveParamSet writes the drive parameter that is pointed to by value to the drive. The paramType defines the type of data that is written to the drive and also defines which field will be used in the value union.

node | a handle to the SynqNet node object.
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
param | an index for the drive parameter that is being accessed.
paramType | the type of data being written to the drive and which field will be used in the value union.
*value | pointer to the union that will be written to the drive.
Return Values
MPIMessageOK if SqNodeDriveParamSet successfully writes the drive parameter that is pointed to by value to the drive.
See Also | meiSqNodeDriveParamGet


meiSqNodeDriveParamStore

Declaration
long meiSqNodeDriveParamStore(MEISqNode    sqNode,
                              long         driveIndex);
Required Header stdmei.h
Description

SqNodeDriveParamStore saves the drive parameters into non-volatile storage on the drive. These drive parameters will be used each time the drive is subsequently started (after a power-on or network reset).

NOTE: This function may not be supported by all drives.

sqNode | a handle to a SynqNet node object
driveIndex | an index to the drive (0, 1, 2, etc), relative to the node.
Return Values
MPIMessageOK if SqNodeDriveParamStore successfully saves the drive parameters into non-volatile storage on the drive.
See Also | meiSqNodeDriveParamRestore


meiSqNodeEventNotifyGet

Declaration
long meiSqNodeEventNotifyGet(MEISqNode       node,
                             MPIEventMask    *eventMask,
                             void            *external);
Required Header stdmei.h
Description

SqNodeEventNotifyGet reads the event mask (that specifies the event types for which host notification has been requested) to the location pointed to by eventMask, and also writes it into the implementation specific location pointed to by external. (if external is not NULL).

Use the event mask macros mpiEventMaskGET(…), mpiEventMaskBitGET(…), etc. to decode the eventMask.

The event notification data in external is in addition to the event notification data in eventMask. If external is NULL, the event notification data will not be copied to the external pointer.
XMP Only

external either points to a structure of type MEIEventNotifyData{…} or is NULL.

node | a handle to a SynqNet node object
*eventMask | pointer to an event mask, whose bits are defined by the MPI/MEIEventType enumerations.
*external | pointer to external

Return Values
MPIMessageOK | if SqNodeEventNotifyGet successfully reads the event mask
MPIMessageARG_INVALID | if the eventMask pointer is NULL

See Also | MPI/MEIEventType | MEIEventNotifyData | MEIEventStatusInfo


meiSqNodeEventNotifySet

Declaration
long meiSqNodeEventNotifySet(MEISqNode       node,
                             MPIEventMask    eventMask,
                             void            *external);
Required Header stdmei.h
Description

SqNodeEventNotifySet requests host notification of the event(s) that are generated by SqNode and specified by eventMask, and also specified by the implementation specific location pointed to by external (if external is not NULL).

Use the event mask macros meiEventMaskSQNODE(…), mpiEventMaskSET(…), mpiEventMaskBitSET(…), mpiEventMaskCLEAR(…), etc. to create the eventMask.

The event notification data in external is in addition to the event notification data in eventMask. If external is NULL, the event notification data will not be copied to the external pointer.
XMP Only

external either points to a structure of type MEIEventNotifyData{…} or is NULL.

The MEIEventNotifyData{…} structure is an array of controller addresses, whose contents are placed into the MEIEventStatusInfo{…} structure (of all events generated by this object).

node | a handle to a SynqNet node object
eventMask | pointer to an event mask, whose bits are defined by the MPI/MEIEventType enumerations.
*external | pointer to external

Return Values
MPIMessageOK | if SynqNetEventNotifySet successfully writes the event mask
MPIMessageARG_INVALID | if the eventMask pointer is NULL

See Also | MEI/MPIEventType | MEIEventNotifyData | MEIEventStatusInfo


meiSqNodeEventReset

Declaration
long meiSqNodeEventReset(MEISqNode      sqNode,
                         MPIEventMask   eventMask);
Required Header stdmei.h
Description

SqNodeEventReset is a method used to reset events that have been latched on a node. Events that can be reset by this method include:

See MEIEventType.

/* SqNode events */
MEIEventTypeSQNODE_IO_ABORT,
MEIEventTypeSQNODE_NODE_DISABLE,
MEIEventTypeSQNODE_NODE_ALARM,
MEIEventTypeSQNODE_ANALOG_POWER_FAULT,
MEIEventTypeSQNODE_USER_FAULT,
MEIEventTypeSQNODE_NODE_FAILURE,

sqNode | a handle to a SynqNet node object
eventMask | pointer to an event mask, whose bits are defined by the MPI/MEIEventType enumerations.

Return Values
MPIMessageOK | if SynqNetEventReset successfully writes the event mask
MPIMessageARG_INVALID | if the eventMask pointer is NULL
See Also


meiSqNodeInfo

Declaration
long meiSqNodeInfo(MEISqNode       node,
                   MEISqNodeInfo   *info);
Required Header stdmei.h
Description

SqNodeInfo reads a SynqNet node's information and writes it into a structure pointed to by info. The info structure contains read only data about the node.

node | a handle to a SynqNet node object.
*info | a pointer to a drive specific information structure.

Return Values
MPIMessageOK | if SqNodeInfo successfully reads the node information.
MPIMessageARG_INVALID | if the info pointer is NULL.

See Also | meiSqNodeDriveInfo | meiSqNodeConfigGet | meiSqNodeDriveConfigGet


meiSqNodeMemory

Declaration
long meiSqNodeMemory(MEISqNode    node,
                     void         **memory);
Required Header stdmei.h
Description

SqNodeMemory writes an address (that can be used to access SqNode memory) to the contents of memory. This address (or an address calculated from it) can be passed as the src argument to mpiSqNodeMemoryGet(…) or the dst argument to mpiSqNodeMemorySet(…).

node | a handle to a SynqNet node object
**memory | a pointer to an SqNode memory address.
Return Values
MPIMesssageOK if SqNodeMemory successfully writes the SqNode memory address to the contents of memory.
See Also | meiSqNodeMemoryGet | meiSqNodeMemorySet


meiSqNodeMemoryGet

Declaration
long meiSqNodeMemoryGet(MEISqNode    node,
                        void         *dst,
                        void         *src,
                        long         count);
Required Header stdmei.h
Description

SqNodeMemoryGet reads count bytes of an SqNode's memory, starting from address src and writes it to application memory, starting at address dst.

node | a handle to a SynqNet node object
*dst | pointer to the destination address in application memory
*src | pointer to the source address in SqNode memory
count | number of bytes to copy
Return Values
MPIMesssageOK if SqNodeMemoryGet successfully copies data from SqNode memory to application memory.
See Also | meiSqNodeMemory | meiSqNodeMemorySet


meiSqNodeMemorySet

Declaration
long meiSqNodeMemorySet(MEISqNode    node,
                        void         *dst,
                        void         *src,
                        long         count);
Required Header stdmei.h
Description

SqNodeMemorySet reads count bytes of application memory, starting from address src and writes it to an SqNode's memory, starting at address dst.

node | a handle to a SynqNet node object
*dst | pointer to the destination address in SqNode memory
*src | pointer to the source address in application memory
count | number of bytes to copy
Return Values
MPIMesssageOK if SqNodeMemorySet successfully copies data from application memory to SqNode memory.
See Also | meiSqNodeMemory | meiSqNodeMemoryGet


meiSqNodeNumber

Declaration
long meiSqNodeNumber(MEISqNode    node,
                     long         *number);
Required Header stdmei.h
Description

SqNodeNumber reads the index of a SynqNet node and writes it into the contents of a long pointed to by number. Each SqNode associated with a controller is indexed by a identification number (0, 1, 2, etc.).

node | a handle to a SynqNet node object
*number | a pointer to the index of a SynqNet node.
Return Values
MPIMessageOK if SqNodeNumber successfully reads the network number
See Also | meiSynqNetInfo | meiSynqNetNumber


meiSqNodeStatus

Declaration
long meiSqNodeStatus(MEISqNode          node,
                     MEISqNodeStatus    *status);
Required Header stdmei.h
Description

SqNodeStatus reads status from the node associated with the SynqNet object and writes it into the structure pointed to by status. The SynqNet node status structure contains error counters and event mask data. This data is updated every controller sample.

node | a handle to a SynqNet node object.
*status | pointer to a SynqNet status structure.

Return Values
MPIMessageOK | if SynqNetStatus successfully reads the node status and writes it into the structure.
MPIMessageARG_INVALID | if the status pointer is NULL.

See Also | meiSynqNetStatus | meiSqNodeInfo


meiSqNodeValidate

Declaration
long meiSqNodeValidate(MEISqNode  node);
Required Header stdmei.h
Description

SqNodeValidate validates a SqNode object and its handle.

SqNodeValidate is the equivalent of a C++ constructor.

node | a handle to SqNode object.
Return Values
MPIMessageOK if SqNode is a handle to a valid object.
See Also | meiSqNodeCreate | meiSqNodeDelete


SynqNet Objects

.

SynqNet Objects

Introduction

A SynqNet object manages a single SynqNet network connected to a motion controller. It represents the physical network. It contains information about the network state, number of nodes, and netowrk status.

A SynqNet network can have one or more SqNode objects associated with it and each SqNode object can have one or more motors and/or drive interfaces. The SynqNet network provides read/write access to each node. During network initialization, the SynqNet nodes are discovered and mapped to the SynqNet object. The number of motors per SqNode object are determined and mapped to the controller's motor objects.

Methods

Create, Delete, Validate Methods
 | meiSynqNetCreate
 | meiSynqNetDelete
 | meiSynqNetValidate

Configuration and Information Methods
 | meiSynqNetCableNumToNodePort
 | meiSynqNetConfigGet
 | meiSynqNetConfigSet
 | meiSynqNetIdleCableListGet
 | meiSynqNetIdleCableStatus
 | meiSynqNetInfo
 | meiSynqNetPortToCableNum
 | meiSynqNetPacketConfigGet
 | meiSynqNetPacketConfigSet
 | meiSynqNetStatus
 | meiSynqNetTiming

Action Methods
 | meiSynqNetInit
 | meiSynqNetShutdown
 | meiSynqNetTopologyClear
 | meiSynqNetTopologySave

Event Methods
 | meiSynqNetEventNotifyGet
 | meiSynqNetEventNotifySet
 | meiSynqNetEventReset

Relational Methods
 | meiSynqNetControl
 | meiSynqNetNumber

Data Types

MEISynqNetCableList
MEISynqNetCableLength
MEISynqNetCableStatus
MEISynqNetConfig
MEISynqNetFailedNodeMask
MEISynqNetInfo
MEISynqNetMessage
MEISynqNetRecoveryMode
MEISynqNetResourceCommand
MEISynqNetResourceIoBits
MEISynqNetResourceMonitor
MEISynqNetPacketCfg
MEISynqNetPacketCfgEncoder
MEISynqNetPacketCfgMotor
MEISynqNetPacketCfgNode
MEISynqNetState
MEISynqNetStatus
MEISynqNetStatusCrcError
MEISynqNetTiming
MEISynqNetTrace

Constants

MEISynqNetMaxCableHOP_COUNT
MEISynqNetMaxEncoderFEEDBACK_COUNT
MEISynqNetMaxMotorCAPTURE_COUNT
MEISynqNetMaxMotorCOMPARE_COUNT
MEISynqNetMaxMotorENCODER_COUNT
MEISynqNetMaxMotors
MEISynqNetMaxNodeMOTORS
MEISynqNetMaxNODE_COUNT


MEISynqNetMaxCableHOP_COUNT

.

MEISynqNetCableHOP_COUNT

MEISynqNetCableHOP_COUNT

#define MEISynqNetCableHOP_COUNT (MEISynqNetMaxNODE_COUNT + 1)
Description

SynqNetMaxCableHOP_COUNT is the maximum number of cables for a SynqNet network. Presently, string and ring topologies are supported. The maximum number of cables is based on the maximum number of nodes, plus one return cable for ring topologies.

See Also | MEISynqNetCableList | MEISynqNetConfig


MEISynqNetCableLength

MEISynqNetCableLength

typedef struct MEISynqNetCableLength {	/* lengths in meters */
    long minimum;
    long nominal;
    long maximum;
} MEISynqNetCableLength;
Description

The SynqNetCableLength structure contains the nominal (average), minimum and maximum length in meters for each discovered network cable. The maximum and minimum values are used in the initialization topology check when a specific network topology is saved to flash.

At network discovery, where network topology has not been saved to flash, the controller will send network packets to measure each cable length and automatically fill out these values for each cable found.
minimum

Minimum cable length in meters. At network initialization, if the measured cable length is less than this number, a return value of MEISynqNetMessageCABLE_LENGTH_MISMATCH will be returned.

A value less than zero or greater than the nominal value is invalid.

nominal

Nominal cable length in meters. Network timing values will be optimized for a cable of this length.

A value less than one is invalid.
maximum

Maximim cable length in meters. At network initialization, if the measured cable length is greater than this number a return value of MEISynqNetMessageCABLE_LENGTH_MISMATCH will be returned.

A value less than the nominal value is invalid.

NOTE: This value is also used in the network calculations--using too large of a margin above the nominal value will result in a waste of network bandwidth. A margin of 25 meters is suggested.

See Also | MEISynqNetConfig | meiSynqNetConfigSet | meiSynqNetConfigSet


MEISynqNetCableList

MEISynqNetCableList

typedef struct MEISynqNetCableList {
    long    count;
    long    cableNumber[MEISynqNetCableHOP_COUNT];
} MEISynqNetCableList;
Description

The SynqNetCableList structure contains the number of cables in the SynqNet network and their identifying numbers. The idle cables can be identified with the meiSynqNetIdleCableListGet(…) method.

A cable can also be identified by the node number and port. Use meiSynqNetCableNumToNodePort(...) to translate the cable number to a node number and a port.

count | The number of cables and number of valid elements in the cableNumber[] array.. Range is 0 to MEISynqNetCableHOP_COUNT.
cableNumber | The cables identified by their number. Cables are numbered in the order they are discovered during network initialization.

See Also | meiSynqNetIdleCableListGet | meiSynqNetIdleCableStatus | meiSynqNetCableNumToNodePort


MEISynqNetCableStatus

MEISynqNetCableStatus

typedef enum MEISynqNetCableStatus {
    MEISynqNetCableStatusGOOD,
    MEISynqNetCableStatusBAD_UPSTREAM,
    MEISynqNetCableStatusBAD_DOWNSTREAM,
    MEISynqNetCableStatusBAD,
} MEISynqNetCableStatus;
Description

SynqNetCableStatus is an enumeration of a network connection's operating condition. Data transmission is verified in both directions. If the network hardware does not support separate upstream and downstream data path verification, it will report either GOOD or BAD.

MEISynqNetCableStatusGOOD | Network communication across the cable is working properly in both directions.
MEISynqNetCableStatusBAD_UPSTREAM | Network communication across the cable failed in the upstream direction (from node to controller).
MEISynqNetCableStatusBAD_DOWNSTREAM | Network communication across the cable failed in the downstream direction (from the controller to the node).
MEISynqNetCableStatusBAD | Network communication across the cable failed in both directions.

See Also | meiSynqNetIdleCableStatus | meiSynqNetIdleCableListGet


MEISynqNetConfig

MEISynqNetConfig

typedef struct MEISynqNetConfig {
    MEISynqNetRecoveryMode   recoveryMode;
    MEISynqNetCableLength    cableLength[MEISynqNetCableHOP_COUNT];
} MEISynqNetConfig;
Description

The SynqNetConfig structure contains configurations for the network's fault recovery mode and the network's cable lengths. The SynqNet configuration can be read with meiSynqNetConfigGet(…) and can be written with meiSynqNetConfigSet(…).

recoveryMode | A enumerated value representing the network's fault recovery response mode.
cableLength | An array of cable lengths. Range for cable lengths is 0 to 100 meters.

See Also | meiSynqNetConfigGet | meiSynqNetConfigSet | meiSynqNetInfo


MEISynqNetFailedNodeMask

MEISynqNetFailedNodeMask

#define MEISynqNetNodeMaskELEMENTS  (1)
typedef long MEISynqNetFailedNodeMask  [MEISynqNetNodeMaskELEMENTS];
Description

SynqNetFailedNodeMask is an array of longs with a length of MEISynqNetNodeMaskELEMENTS. Each bit in the failed node mask represents a failed node (0x1 = node 0, 0x2 = node 2, 0x4 = node 3, etc.). A node failure occurs when the packet error rate counters exceed the packet error rate fail limit.

See Also | MEISynqNetStatus | meiSynqNetStatus | meiSqNodeStatus | MEISqNodeConfig


MEISynqNetInfo

MEISynqNetInfo

typedef struct MEISynqNetInfo {
    MEINetworkType networkType;
    long           nodeCount;
    long           nodeOffset;
    long           cableLength[MEISynqNetCableHOP_COUNT]; /* measured length */
} MEISynqNetInfo;
Description

The SynqNetInfo structure contains static data that is determined during network initialization. It identifies the network type, number of nodes on the network, starting number (offset) of the first node, and an rough estimate of measured cable lengths.

networkType | contains currently discovered network topology type.
nodeCount | Contains the number of nodes currently discovered on the network.
nodeOffset | Starting node number for nodes on this network. Nodes are currently numbered sequentially across all networks on a controller.
cableLength | An array of measured network cable lengths. These values are estimated values.
See Also


MEISynqNetMaxEncoderFEEDBACK_COUNT

MEISynqNetMaxEncoderFEEDBACK_COUNT

#define MEISynqNetMaxEncoderFEEDBACK_COUNT  (1) /* single 32bit feedback */
Description

SynqNetMaxEncoderFEEDBACK_COUNT defines the maximum number of feedback fields per encoder.

NOTE: Feedback count may be further limited by the available resources on the node.

See Also


MEISynqNetMaxMOTORS

MEISynqNetMaxMOTORS

#define MEISynqNetMaxMOTORS (MEIXmpMAX_Motors) /* 32 */
Description

SynqNetMaxMOTORS defines the maximum number of motors supported on a single SynqNet network.
See Also


MEISynqNetMaxMotorCAPTURE_COUNT

MEISynqNetMaxMotorCAPTURE_COUNT

#define MEISynqNetMaxMotorCAPTURE_COUNT (MEIXmpMaxCapturesPerMotor) /*  2 */
Description

SynqNetMaxMotorCAPTURE_COUNT defines the maximum number of capture resources per motor.

NOTE: Capture count may be further limited by the available resources on the node.

This define should be used instead of the MEIXmpMaxCapturesPerMotor definition in xmp.h. It is recommended that applications avoid programming to defines or structures in xmp.h

See Also


MEISynqNetMaxMotorCOMPARE_COUNT

MEISynqNetMaxMotorCOMPARE_COUNT

#define MEISynqNetMaxMotorCOMPARE_COUNT (MEIXmpMaxCapturesPerMotor) /*  2 */
Description

SynqNetMaxMotorCOMPARE_COUNT defines the maximum number of compare resources per motor.

NOTE: Compare count may be further limited by the available resources on the node.

This define should be used instead of the MEIXmpMaxComparesPerMotor definition in xmp.h. It is recommended that applications avoid programming to defines or structures in xmp.h

See Also


MEISynqNetMaxMotorENCODER_COUNT

MEISynqNetMaxMotorENCODER_COUNT

#define MEISynqNetMaxMotorENCODER_COUNT (MEIXmpMotorEncoders) /*  2 */
Description

SynqNetMaxMotorENCODER_COUNT defines the maximum number of encoder resources per motor.

NOTE: The encoder count may be further limited by the available resources on the node.

This define should be used instead of the MEIXmpMotorEncoders definition in xmp.h. It is recommended that applications avoid programming to defines or structures in xmp.h

See Also


MEISynqNetMaxNODE_COUNT

MEISynqNetMaxNODE_COUNT

#define MEISynqNetMaxNODE_COUNT (MEIXmpMaxSynqNetBlocks) /* 32 */
Description

SynqNetMaxNODE_COUNT defines the maximum number of nodes supported on a single SynqNet network. This define should be used instead of the MEIXmpMaxSynqNetBlocks definition in xmp.h. It is recommended that applications avoid programming to defines or structures in xmp.h

See Also


MEISynqNetMaxNodeMOTORS

MEISynqNetMaxNodeMOTORS

#define MEISynqNetMaxNodeMOTORS (MEIXmpMotorsPerBlock) /*  8 */
Description

SynqNetMaxNodeMOTORS defines the maximum number of motor objects supported on a single SynqNet node.This define should be used instead of the MEIXmpMotorsPerBlock definition in xmp.h. It is recommended that applications avoid programming to defines or structures in xmp.h

See Also


MEISynqNetMessage

MEISynqNetMessage

typedef enum {
    MEISynqNetMessageSYNQNET_INVALID,
    MEISynqNetMessageMAX_NODE_ERROR,
    MEISynqNetMessageSTATE_ERROR,

    MEISynqNetMessageCOMM_ERROR,
    MEISynqNetMessageCOMM_ERROR_CRC,
    MEISynqNetMessageCOMM_ERROR_RX,
    MEISynqNetMessageCOMM_ERROR_RX_LEN,
    MEISynqNetMessageCOMM_ERROR_RX_FIFO,
    MEISynqNetMessageCOMM_ERROR_RX_DRIBBLE,
    MEISynqNetMessageCOMM_ERROR_RX_CRC,

    MEISynqNetMessageINTERFACE_NOT_FOUND,
    MEISynqNetMessageTOPOLOGY_MISMATCH,
    MEISynqNetMessageTOPOLOGY_MISMATCH_FLASH,

    MEISynqNetMessageRESET_REQ_TIMEOUT,
    MEISynqNetMessageRESET_ACK_TIMEOUT,
    MEISynqNetMessageDISCOVERY_TIMEOUT,
    MEISynqNetMessageNO_NODES_FOUND,
    MEISynqNetMessageNODE_UNAVAILABLE,

    MEISynqNetMessageNO_TIMING_DATA_AVAIL,
    MEISynqNetMessageRESPONSE_TIMEOUT,
    MEISynqNetMessageREADY_TIMEOUT,
    MEISynqNetMessageSRVC_ERROR,
    MEISynqNetMessageSRVC_UNSUPPORTED,
    MEISynqNetMessageINTERNAL_BUFFER_OVERFLOW,
    MEISynqNetMessageINVALID_MOTOR_COUNT,
    MEISynqNetMessageINVALID_AUX_ENC_COUNT,
    MEISynqNetMessageINCOMPLETE_MOTOR,
    MEISynqNetMessageINVALID_COMMAND_CFG,
    MEISynqNetMessageINVALID_ENCODER_COUNT,
    MEISynqNetMessageINVALID_CAPTURE_COUNT,
    MEISynqNetMessageINVALID_COMPARE_COUNT,
    MEISynqNetMessageINVALID_INPUT_COUNT,
    MEISynqNetMessageINVALID_OUTPUT_COUNT,
    MEISynqNetMessageINVALID_MONITOR_CFG,

    MEISynqNetMessageLINK_NOT_IDLE,
    MEISynqNetMessageIDLE_LINK_UNKNOWN,
    MEISynqNetMessageRING_ONLY,
    MEISynqNetMessageRECOVERING,

    MEISynqNetMessageCABLE_LENGTH_UNSUPPORTED,
    MEISynqNetMessageCABLE_LENGTH_MISMATCH,
    MEISynqNetMessageCABLE_LENGTH_INVALID_NOMINAL,
    MEISynqNetMessageCABLE_LENGTH_INVALID_MIN,
    MEISynqNetMessageCABLE_LENGTH_INVALID_MAX,

    MEISynqNetMessageNODE_FPGA_VERSION,
    MEISynqNetMessageMAX_NODE_ERROR,
    MEISynqNetMessagePLL_ERROR,

} MEISynqNetMessage;
Description

SynqNetMessage is an enumeration of SynqNet error messages that can be returned by the MPI library.

MEISynqNetMessageSYNQNET_INVALID
 | The SynqNet number is out of range. This message code is returned by meiSynqNetCreate(…) if the SynqNet network number is less than zero or greater than or equal to MEIXmpMaxSynqNets.
MEISynqNetMessageMAX_NODE_ERROR
 | The SynqNet node number is out of range. This message code is returned by a SynqNet method if the specified node number is greater than or equal to MEIXmpMaxSynqNetBlocks.
MEISynqNetMessageSTATE_ERROR
 | The SynqNet network state is not valid. This message code is returned by any method that initializes a SynqNet network if the controller's network state is not a member of the MEIXmpSynqNetState or MEIXmpSynqNetInternalState enumeration. The most commonly used methods that initialize the SynqNet network are: mpiControlInit(…), mpiControlReset(…) and meiSynqNetInit(…). This message code indicates a failure in the controller's initialization sequence. To correct this problem, call mpiControlReset(…).
MEISynqNetMessageCOMM_ERROR
 | The SynqNet network communication failed. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_CRC
 | The SynqNet network communication failed due to excessive CRC errors. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_RX
 | The SynqNet network communication failed due to a Rincon receive error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_RX_LEN
 | The SynqNet network communication failed due to a Rincon receive length error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_RX_FIFO
 | The SynqNet network communication failed due to a Rincon receive buffer error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_RX_DRIBBLE
 | The SynqNet network communication failed due to a Rincon receive dribble error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageCOMM_ERROR_RX_CRC
 | The SynqNet network communication failed due to a Rincon receive CRC error. This message code is returned by MPI methods that fail a service command transaction due to a network shutdown. This message indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageINTERFACE_NOT_FOUND
 | The controller does not support a SynqNet interface. This message code is returned by meiSynqNetValidate(…), meiSynqNetTopologySave(…), meiSynqNetTopologyClear(…), mpiControlInit(…), and mpiControlReset(…) if the controller does not have a SynqNet hardware interface. To correct this problem, use a controller that supports SynqNet.
MEISynqNetMessageTOPOLOGY_MISMATCH
 | The network topology does not match the expected network topology. This message code is returned by mpiControlInit(…) or meiSynqNetInit(…) if the discovered network topology does not match the controller's expected network topology (stored in dynamic memory). During the first network initialization the controller stores node identification information (manufacturer, product, and unique values) into it's dynamic memory. This message code indicates the number of nodes, the node order, or types of nodes have changed since the initial network initialization. To correct this problem, either change the network topology to the original configuration or clear the controller's memory with mpiControlReset(…).
MEISynqNetMessageTOPOLOGY_MISMATCH_FLASH
 | The network topology does not match the expected network topology. This message code is returned by mpiControlInit(…) or meiSynqNetInit(…) if the discovered network topology does not match the controller's expected network topology (stored in flash memory). During the first network initialization the controller stores node identification information (manufacturer, product, and unique values) into it's dynamic memory. Later, when meiSynqNetTopologySave(…) is called, the topology information is stored into flash memory. This message indicates the number of nodes, the node order, or types of nodes have changed since the topology information was stored in flash. To correct this problem, either change the network topology to the saved configuration or clear the controller's flash topology with meiSynqNetTopologyClear(…).
MEISynqNetMessageRESET_REQ_TIMEOUT
 | The network reset request packet exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiSynqNetInit(…) if the reset request packet fails to traverse the network in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageRESET_ACK_TIMEOUT
 | The network reset complete packet exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlInit(…), or meiSynqNetInit(…) if the reset complete packet fails to traverse the network in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageDISCOVERY_TIMEOUT
 | The network topology discovery exceeded the timeout. This message code is returned by mpiControlInit(…), mpiControlInit(…), or meiSynqNetInit(…) if the controller failed to discover the network topology in the allotted time. This message code indicates a node or network cable failure. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageNO_NODES_FOUND
 | The controller did not find network nodes. This message code is returned by mpiControlInit(…), meiSynqNetPacketConfigSet(…), or meiSynqNetInit(…) if the controller failed to discover any nodes during network initialization. This message code indicates the first node has failed or the network connection from the controller to the first node is faulty. To correct this problem, check your network wiring and node condition.
MEISynqNetMessageNODE_UNAVAILABLE
 | The node number is not available on the network. This message code is returned by MPI methods that fail a service command transaction due to the specified node number is greater than or equal to the total number of nodes discovered during network initialization. To correct this problem, check the discovered node count with meiSynqNetInfo(…). If the node count is not what you expected check your network wiring, node condition, and re-initialize the network with mpiControlReset(…).
MEISynqNetMessageNO_TIMING_DATA_AVAIL
 | The corresponding SynqNet node module does not contain timing data, so the network cannot be initialized. Contact MEI or drive manufacturer for an updated node module.
MEISynqNetMessageRESPONSE_TIMEOUT
 | The node failed to respond to a service command within the timeout. This message code is returned by MPI methods that fail a service command transaction because the node failed to respond within the allotted amount of time. To correct this problem, check your node hardware.
MEISynqNetMessageREADY_TIMEOUT
 | The node failed to be ready for a service command within the timeout. This message code is returned by MPI methods that fail a service command transaction because the node is not ready to accept service commands. To correct this problem, check your node hardware.
MEISynqNetMessageSRVC_ERROR
 | The service command failed. This message code is returned by MPI methods that fail a service command transaction. To correct this problem, check your node hardware.
MEISynqNetMessageSRVC_UNSUPPORTED
 | The node does not support the service command. This message code is returned by MPI methods that fail a service command transaction because the node does not support it. Contact MEI or the node manufacturer for updated software or firmware to correct this problem.
MEISynqNetMessageINTERNAL_BUFFER_OVERFLOW
 | The controller's SynqNet buffer size was exceeded. This message code is returned by mpiControlInit(…), mpiControlReset(…), or meiControlInit(…) if the controller's SynqNet buffer could not be allocated due to overflow. This message code indicates the controller does not have enough memory to initialize the network topology. To correct the problem, either reduce the network nodes or use a different controller model.
MEISynqNetMessageINVALID_MOTOR_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more motors than supported by the node.
MEISynqNetMessageINVALID_AUX_ENC_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more secondary encoders than supported by the node.
MEISynqNetMessageINCOMPLETE_MOTOR
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a motor configuration that is missing feedback or command fields.
MEISynqNetMessageINVALID_COMMAND_CFG
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a different command configuration than is supported by the node.
MEISynqNetMessageINVALID_ENCODER_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more encoders than supported by the node.
MEISynqNetMessageINVALID_CAPTURE_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger capture count than is supported by the node.
MEISynqNetMessageINVALID_COMPARE_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger compare count than is supported by the node.
MEISynqNetMessageINVALID_INPUT_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger ioInput count than is supported by the node.
MEISynqNetMessageINVALID_OUTPUT_COUNT
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains a larger ioOutput count than is supported by the node.
MEISynqNetMessageINVALID_MONITOR_CFG
 | This message is returned by meiSynqNetPacketConfigSet(…), when the packet configuration contains more monitor fields than the node can support.
MEISynqNetMessageLINK_NOT_IDLE
 | This message is returned by meiSynqNetIdleCableStatus(...) when the cable number supplied is not the idle link. The status check can only be run on an idle cable. See meiSynqNetIdleCableListGet(…).
MEISynqNetMessageIDLE_LINK_UNKNOWN
 | This message is returned by meiSynqNetIdleCableListGet(…) when an idle cable number in a ring topology cannot be determined. This is due to one or more failed nodes on a ring topology. Be sure to check the status of the nodes.
MEISynqNetMessageRECOVERING
 | The network is recovering from a fault condition. This message is returned by meiSynqNetIdleCableStatus(...) during network fault recovery, because the network traffic is being redirected around the faulted cable and a new idle cable is in the process of being assigned. If you receive this message, wait for recovery to complete and then check the identity of the idle cable with meiSynqNetIdleCableListGet(…).
MEISynqNetMessageRING_ONLY
 | This message is returned by meiSynqNetIdleCableListGet(…) and meiSynqNetIdleCableStatus(...) because idle cables exist on ring topologies only. It is also returned by meiSynqNetConfigSet(...) when attempting to enable SynqNet recovery mode, which is only supported for ring topologies.
MEISynqNetMessageCABLE_LENGTH_UNSUPPORTED
 | This message is returned when a cable on the network is too long.
MEISynqNetMessageCABLE_LENGTH_MISMATCH
 | This message is returned at network initialization when topology has been saved to flash and a cable length is detected that lies outside the MEISynqNetConfig.cableLength[n].minimum and maximum. Check cable length (if necessary) and save new cable length values to flash.
MEISynqNetMessageCABLE_LENGTH_INVALID_NOMINAL
 | The nominal cable length is too long.
MEISynqNetMessageCABLE_LENGTH_INVALID_MIN
 | The minimum cable length is too long or exceeds nominal value.
MEISynqNetMessageCABLE_LENGTH_INVALID_MAX
 | The maximum cable length is too long or is less than nominal value.
MEISynqNetMessageNODE_FPGA_VERSION
 | The node FGPA version is out of date. Use the sqNodeFlash.exe utility to load most current FPGA version to node.
MEISynqNetMessageMAX_MOTOR_ERROR
 | The number of motors on the network exceeds the number set by MEISynqNetMaxMOTORS.
MEISynqNetMessagePLL_ERROR
 | The node PLL is unable to lock with drive.
See Also


MEISynqNetPacketCfg

MEISynqNetPacketCfg

typedef struct MEISynqNetPacketCfg {
    MEISynqNetPacketCfgNode node[MEISynqNetMaxNODE_COUNT];
} MEISynqNetPacketCfg;
Description

The SynqNetPacketCfg structure is used as a parameter to the meiSynqNetPacketConfigGet/Set methods. It contains the network packet configuration for all nodes found on the network. Only configurable packet data is represented in this structure.

NOTE: Fixed packet fields are NOT application configurable.
node

is an array of configurable packet structures for node data. Array indices 0 through MEISynqNetInfo.nodeCount are valid, with a maximum number of motors per node being defined by MEISynqNetMaxNODE_COUNT.

See Also | meiSynqNetPacketConfigSet | meiSynqNetPacketConfigGet | MEISynqNetPacketCfgNode | MEISynqNetPacketCfgMotor | MEISynqNetPacketCfgEncoder


MEISynqNetPacketCfgEncoder

MEISynqNetPacketCfgEncoder

typedef struct MEISynqNetPacketCfgEncoder {
    long feedbackCount;    /* per encoder */
    long captureCount;     /* per encoder */
    long compareCount;     /* per encoder */
} MEISynqNetPacketCfgEncoder;
Description

The SynqNetPacketCfgEncoder structure is a member of the MEISynqNetPacketCfgMotor configuration structure. It contains the network packet configuration for a single encoder found on a particular motor. Only configurable packet data is represented in this structure. Fixed packet fields are not application configurable.

Setting all structure members to zero (0x0) values will effectively disable the encoder on the motor. Disabling an encoder will NOT affect encoder numbering, however, encoders with higher index numbers must be disabled before using encoders with lower index numbers.

NOTE: A motor is considered incomplete if it has no encoders enabled.

feedbackCount

configures the number of 32-bit feedback data fields to be sent for an encoder. Valid numbers are zero thru MEISynqNetMaxEncoderFEEDBACK_COUNT , but may be further limited by the available resources on the node.

NOTE: Setting this count to a value of zero (0x0) will affectively disable the encoder. All other encoder resources must also be set to NONE or zero (0x0).
captureCount

configures the number of 32-bit capture data fields to be sent for an encoder. Valid numbers are zero thru MEISynqNetMaxMotorCAPTURE_COUNT, but may be further limited by the available resources on the node. If feedbackCount is zero (0x0), then this value must also be zero.

NOTE: all capture/compare resources on a motor rely on 2 fixed 32bit data fields for command and status information. These fixed fields are currently not configurable.
compareCount

configures the number of 32-bit compare data fields to be sent for an encoder. Valid numbers are zero thru MEISynqNetMaxMotorCOMPARE_COUNT, but may be further limited by the available resources on the node.

If feedbackCount is zero (0x0), then this value must also be zero.

NOTE: all capture/compare resources on a motor rely on 2 fixed 32bit data fields for command and status information. These fixed fields are currently not configurable.

See Also | meiSynqNetPacketConfigGet | meiSynqNetPacketConfigSet | MEISynqNetPacketCfgMotor | MEISynqNetPacketCfg | MEISynqNetPacketCfgNode


MEISynqNetPacketCfgMotor

MEISynqNetPacketCfgMotor

typedef struct MEISynqNetPacketCfgMotor {
    MEISynqNetResourceCommand   command;
    MEISynqNetPacketCfgEncoder  encoder[MEISynqNetMaxMotorENCODER_COUNT];
    MEISynqNetResourceIoBits    ioInput;
    MEISynqNetResourceIoBits    ioOutput;
    MEISynqNetResourceMonitor   monitor;
} MEISynqNetPacketCfgMotor;
Description

The SynqNetPacketCfgMotor structure is a member of the MEISynqNetPacketCfgNode configuration structure. It contains the network packet configuration for a single motor found on a particular node. Only configurable packet data is represented in this structure. Fixed packet fields are not application configurable.

NOTE: Setting all structure members to a NONE or Zero (0x0) value will effectively disable the motor on the network. This will cause the controller to renumber the subsequent motors on the network.

command | Selects the command data type and count. Please see MEISynqNetResourceCommand.
encoder | Configuration structure for encoder/feedback data for this motor. Please see MEISynqNetPacketCfgEncoder.
ioInput | Selects the number of input bit data received from this motor. Please see MEISynqNetResourceIoBits.
ioOutput | Selects the number of output bit data sent to this motor. Please see MEISynqNetResourceIoBits.
monitor | Selects the number of montior data fields received from this motor. Please see MEISynqNetResourceMonitor.

See Also | meiSynqNetPacketConfigGet | meiSynqNetPacketConfigSet | MEISynqNetPacketCfg | MEISynqNetPacketCfgNode | MEISynqNetPacketCfgEncoder | MEISynqNetResourceCommand | MEISynqNetResourceIoBits | MEISynqNetResourceMonitor


MEISynqNetPacketCfgNode

MEISynqNetPacketCfgNode

typedef struct MEISynqNetPacketCfgNode {
     MEISynqNetPacketCfgMotor   motor[MEISynqNetMaxNodeMOTORS];
} MEISynqNetPacketCfgNode;
Description

The SynqNetPacketCfgNode structure is a member of the MEISynqNetPacketCfg configuration structure. It contains the network packet configuration for all motors found on a particular node. Only configurable packet data is represented in this structure. Fixed packet fields are not application configurable.

motor | an array of configurable packet structures for motor data. Array indices 0 through MEISqNodeInfo.motorCount are valid, with a maximum number of motors per node being defined by MEISynqNetMaxNodeMOTORS.

See Also | meiSynqNetPacketConfigGet | meiSynqNetPacketConfigSet | MEISynqNetPacketCfg | MEISynqNetPacketCfgMotor | MEISynqNetPacketCfgEncoder


MEISynqNetRecoveryMode

MEISynqNetRecoveryMode

typedef enum MEISynqNetRecoveryMode {
    MEISynqNetRecoveryModeDISABLED,
    MEISynqNetRecoveryModeSINGLE_SHOT,
    MEISynqNetRecoveryModeAUTO_ARM,
} MEISynqNetRecoveryMode;
Description

SynqNetRecoveryMode is an enumeration of a network's fault recovery mode. Networks with ring topologies can be configured to recover from a fault condition. A fault condition occurs when a packet error rate counter exceeds its packet error rate fault limit. If fault recovery is enabled and a fault occurs, the node hardware and/or controller will detect the location of the fault and switch the direction of network traffic for nodes downstream from the faulted connection. During fault recovery, the network state is MEISynqNetStateSYNQ_RECOVERING. After the upstream and downstream packet error rate counters decrement to zero, the recovery is completed, and the network state returns to MEISynqNetStateSYNQ.

When fault recovery occurs, the controller will generate a MEIEventTypeSYNQNET_RECOVERY status/event. An application should notify the user about the fault and fix the broken cable/hardware as soon as possible. An application can determine the location of the fault using meiSynqNetIdleCableListGet(...). A network with a ring topology has one idle cable, which has no data traffic. The operation of the idle cable can be tested with meiSynqNetIdleCableStatus(...).

WARNING: If the idle cable is broken and a second fault occurs, then fault recovery will not be able to fully recover from the fault. SynqNet will try to recover, but some nodes will be stranded. Presently, SynqNet does not support an event to notify the application if an idle cable fails. In the meantime, an application can periodically poll the idle cable with meiSynqNetIdleCableStatus(...) to test the cable.

MEISynqNetRecoveryModeDISABLED | The network will not attempt to recover from a fault condition. This is the default mode for string topologies.
MEISynqNetRecoveryModeSINGLE_SHOT | The network will only attempt to recover from a fault condition one time. A second fault will be ignored.
MEISynqNetRecoveryModeAUTO_ARM | The network will attempt to recover from a fault condition. After the fault recovery is complete, the network will automatically be re-armed to respond to another fault condition. This is the default mode for ring topologies.

See Also | meiSynqNetConfigGet | meiSynqNetConfigSet | meiSynqNetStatus | meiSynqNetInfo | meiSynqNetIdleCableListGet | meiSynqNetIdleCableStatus


MEISynqNetResourceCommand

MEISynqNetResourceCommand

typedef enum MEISynqNetResourceCommand {
    MEISynqNetResourceCommandINVALID,
    MEISynqNetResourceCommandNONE,
    MEISynqNetResourceCommandDAC_ONE,
    MEISynqNetResourceCommandDAC_TWO,
    MEISynqNetResourceCommandDEMAND_A,
    MEISynqNetResourceCommandDEMAND_ABC,
} MEISynqNetResourceCommand;
Description

The SynqNetResourceCommand enumeration is a member of the MEISynqNetPacketCfgMotor configuration structure. The values are used to configure the number of 32-bit command data fields sent to drive a motor. Valid values range from greater or equal to MEISynqNetResourceCommandFIRST and less than MEISynqNetResourceCommandLast, but may be further limited by the available resources on the node.

NOTE: A motor is considered incomplete if it has a command value of NONE.

MEISynqNetResourceCommandINVALID | Non-vaild command value was detected.
MEISynqNetResourceCommandNONE | No command data will be sent to this motor. NOTE: this disables the motor and will require the application to remove all other resources for this motor.
MEISynqNetResourceCommandDAC_ONE | Configures a 32bit data field of DAC data to besent to the motor.
MEISynqNetResourceCommandDAC_TWO | Configures two 32bit data fields of DAC data to besent to the motor.
MEISynqNetResourceCommandDEMAND_A | Configures one 16bit data field of Demand data to be sent to the motor.
MEISynqNetResourceCommandDEMAND_ABC | Configures three 16bit data fields of Demand data to be sent to the motor.

See Also | meiSynqNetPacketConfigGet | meiSynqNetPacketConfigSet | MEISynqNetPacketCfgMotor | MEISynqNetPacketCfg | MEISynqNetPacketCfgNode


MEISynqNetResourceIoBits

MEISynqNetResourceIoBits

typedef enum MEISynqNetResourceIoBits {
    MEISynqNetResourceIoBitsINVALID,
    MEISynqNetResourceIoBitsNONE,
    MEISynqNetResourceIoBits16,
    MEISynqNetResourceIoBits48,
} MEISynqNetResourceIoBits;
Description

The SynqNetResourceIoBits enumeration is a member of the MEISynqNetPacketCfgMotor configuration structure. The values are used to configure the number of I/O data fields sent to a motor. Valid values range from greater or equal to MEISynqNetResourceIoBitsFIRST and less than MEISynqNetResourceIoBitsLAST, but may be further limited by the available resources on the node. This is a generic enumeration that is used to configure the resource count of different types of motor and node I/O.

NOTE: (for Motor I/O only) Enabled motors always contain one fixed 16bit data field of dedicated I/O. This is not application configurable.

MEISynqNetResourceIoBitsINVALID | Non-valid bit count was detected.
MEISynqNetResourceIoBitsNONE | No I/O bits will be sent/received.
MEISynqNetResourceIoBits16 | One data field of 16 I/O bits will be sent/received.
MEISynqNetResourceIoBits48 | One data field of 48 I/O bits will be sent/received.

See Also | meiSynqNetPacketConfigGet | meiSynqNetPacketConfigSet | MEISynqNetPacketCfgMotor | MEISynqNetPacketCfg | MEISynqNetPacketCfgNode | mpiMotorIoGet | mpiMotorIoSet


MEISynqNetResourceMonitor

MEISynqNetResourceMonitor

typedef enum MEISynqNetResourceMonitor {
    MEISynqNetResourceMonitorINVALID,
    MEISynqNetResourceMonitorNONE,
    MEISynqNetResourceMonitorAB,
    MEISynqNetResourceMonitorABCD,
} MEISynqNetResourceMonitor;
Description

The SynqNetResourceMonitor enumeration is a member of the MEISynqNetPacketCfgMotor configuration structure. The values are used to configure the number of Monitor data fields received from a motor. Valid values range from greater or equal to MEISynqNetResourceMonitorFIRST and less than MEISynqNetResourceMonitorLAST, but may be further limited by the available resources on the node.

MEISynqNetResourceMonitorINVALID | Non-valid bit count was detected.
MEISynqNetResourceMonitorNONE | No monitor data fields will be sent/received for this motor.
MEISynqNetResourceMonitorAB | Two 16bit fields of monitor data will be sent/received for this motor.
MEISynqNetResourceMonitorABCD | Four 16bit fields of monitor data will be sent/received for this motor.
See Also


MEISynqNetState

MEISynqNetState

typedef enum MEISynqNetState {
    MEISynqNetStateINVALID,
    MEISynqNetStateDISCOVERY,
    MEISynqNetStateASYNQ,
    MEISynqNetStateSYNQ,
    MEISynqNetStateSYNQ_RECOVERING,
} MEISynqNetState;
Description

SynqNetState is an enumeration of the SynqNet network states. Each state shows the present operation mode for the network. Network data traffic occurs in two modes: asynchronous and synchronous.

During asynchronous communication, the MPI or controller sends one packet to one node and the node responds with one packet. There are no timing restrictions. Asynchronous communication is used during network initialization, reset, discovery, and node binary download.

During synchronous communication, the controller sends packets to the nodes and the nodes respond with packets. All data traffic is scheduled in fixed timeslots to avoid collisions. Packet data updates are cyclic and synchronized to the controller's sample rate. The network state can be read with meiSynqNetStatus(…).

MEISynqNetStateDISCOVERY | This is the initial state before the network is initialized. During this phase, the controller checks the network integrity, determines the network topology, resets the nodes, identifies, initializes, and addresses the nodes. Data packets are sent/received asynchronously.
MEISynqNetStateASYNQ | This state is used for off-line operations, like node binary download. Data packets are sent/received asynchronously.
MEISynqNetStateSYNQ | This is the normal operating state. Data packets are sent/received synchronously.
MEISynqNetStateSYNQ_RECOVERING | During this state, a network fault condition was detected and the network is being reconfigured to route data packets around the fault. After the reconfiguration is complete and the packet error rate counters have decremented to zero, the network will return to the SYNQ state.

See Also | MEISynqNetStatus | meiSynqNetStatus


MEISynqNetStatus

MEISynqNetStatus

typedef struct MEISynqNetStatus {
    MEISynqNetState             state;
    MEISynqNetStatusCrcError    crcError;
    MPIEventMask                eventMask;
    MEISynqNetFailedNodeMask    failedNodeMask;
} MEISynqNetStatus;
Description

The SynqNetStatus structure contains network state information, CRC counters, eventMask, and the failedNodeMask for a SynqNet network. The network status can be read with the meiSynqNetStatus(…) method.
state

Present operation mode for the network.
crcError

CRC error counters for the controller's network ports. The CRC value increments when received data is corrupt. Range is from 0 to 255. Counter saturates at 255.
eventMask

An array that defines the status for the event mask bits. The array is defined as:

typedef MPIEventMaskELEMENT_TYPE
        MPIEventMask[MPIEventMaskELEMENTS]

The bits are defined by the MPI/MEIEventType enumerations.

failedNodeMask

Array that defines the failed node mask bits. Each bit represents a failed node (0x1 = node 0, 0x2 = node 2, 0x4 = node 3, etc.). The array is defined as:

#define MEISynqNetNodeMaskELEMENTS (1)
typedef long MEISynqNetFailedNodeMask[MEISynqNetNodeMaskELEMENTS];

See Also | meiSynqNetStatus | meiSqNodeStatus | MEISqNodeStatus


MEISynqNetStatusCrcError

MEISynqNetStatusCrcError

typedef struct MEISynqNetStatusCrcError {
    long port[MEINetworkPortLAST];
} MEISynqNetStatusCrcError;
Description

The SynqNetStatusCrcError structure contains the CRC values for each network port on the controller. This structure is read via the meiSynqNetStatus(…) method.

port

an array of CRC values, one for each network port.

See Also | MEINetworkPort | MEISynqNetStatus | meiSynqNetStatus | CRC Error Counters


MEISynqNetTiming

MEISynqNetTiming

typedef struct MEISynqNetTiming {
    double controllerFreq;      /* kHz */
    double controllerPeriod;    /* uS  */

    long   txTime;              /*  %  */
    double calculationLimit;    /* uS  */

    double driveUpdateFreq;     /* kHz */
    double driveUpdatePeriod;   /* uS  */

    long   bandwidthUsage;      /*  %  */

    struct {
        double calculationTime; /* uS  */
        double calculationSlack;/* uS  */
        double demandLatency;   /* uS  */
        double feedbackLatency; /* uS  */

        double total;           /* uS  */
        double latencySlack;    /* uS  */
    } controlLatency;

    struct {
        double synq;            /* uS  - synq packet + spacing         */
        double demand;          /* uS  - sum demand packets + spacing  */
        double control;         /* uS  - sum control packets + spacing */

        double total;           /* uS  */
    } downstream;

    struct {
        double feedback;        /* uS  - sum feedback packets + spacing */
        double status;          /* uS  - sum status packets + spacing   */

        double total;           /* uS  */
    } upstream;
} MEISynqNetTiming;
Description

The SynqNetTiming structure contains static data that is determined during network initialization. It identifies timing statistics about the current network. Most values are just reported based on network timing calculations. The values that can be configured by the MPI are stated below as configurable.

controllerFreq | The sample rate calculation of the SynqNet controller board, in kHz. It is also the rate at which SynqNet packets are sent. The controllerFreq must be configured so that the driveUpdateFreq is an integer multiple of the controllerFreq. This value is configurable. See MPIControlConfig.
controllerPeriod | The sample period calculation of the SynqNet controller board, in uS. Derived from controllerFreq.
txTime | The scheduled time for SynqNet packets to be sent, in % (of the controllerPeriod). Defaults to 75%. Must be set to a value greater than the foreground calculation time, and less than 100%. This value is configurable. See MEIControlConfig.
calculationLimit | The maximum allowed foreground calculation time, in uS. Derived from txTime * controllerPeriod.
driveUpdateFreq | The cyclic communication rate of a drive processor on a SynqNet node, in kHz. Typically fixed to 16 kHz, but may vary depending on drive type. May be configurable on some drives. This rate often matches the drive PWM rate.
driveUpdatePeriod | The cyclic communication period of a drive processor on a SynqNet node, in uS. Derived from driveUpdateFreq.
bandwidthUsage | The amount of SynqNet bandwidth used, in %, for this SynqNet configuration. The actual packet payload configured is divided by the maximum available SynqNet bandwidth, for both upstream and downstream packets. The greater of the two is reported.
calculationTime | The foreground calculation time of the controller, in uS.
calculationSlack | The available slack time between the foreground calculation time, and the scheduled txTime, in uS.
demandLatency | The time to send SynqNet demand data downstream from controller to nodes, in uS. Does not include drive demand delays.
feedbackLatency | The time to send SynqNet feedback data upstream from nodes to controller, in uS. Rounded up to make the total SynqNet latency an integer multiple of the driveUpdatePeriod. Does not include drive feedback delays.
latencySlack | The slack time from the configured feedbackLatency (which is rounded up to an integer multiple of the driveUpdatePeriod), to the minimum possible upstream delay, in uS.
controlLatency | The overall SynqNet system control latency, in uS. Always rounded up to an integer multiple of driveUpdatePeriod. Control latency begins when position feedback is sampled on the node, includes upstream packet delays, controller foreground calculation, downstream packet delays, and ends when demands are strobed on the nodes. Note drive feedback and demand delays are NOT included. Control latency can be broken down into the four components listed below: feedbackLatency, calculationTime, calculationSlack, and demandLatency.
synq | Downstream SYNQ packet payload, in uS. Includes spacing between packets.
demand | Downstream DEMAND packet payload, in uS. Includes spacing between packets.
control | Downstream CONTROL packet payload, in uS. Includes spacing between packets.
downstream | Total downstream (controller to nodes) packet payload, in uS. Includes spacing between packets. Breaks down into the following three packet types.
feedback | Upstream FEEDBACK packet payload, in uS. Includes spacing between packets.
status | Upstream STATUS packet payload, in uS. Includes spacing between packets.
upstream | Total upstream (nodes to controller) packet payload, in uS. Includes spacing between packets. Breaks down into the following two packet types.
See Also


MEISynqNetTrace

MEISynqNetTrace

typedef enum {
    MEISynqNetTraceDYNA_ALLOC   = MEISynqNetTraceFIRST << 0,
    MEISynqNetTraceDYNA_FREE    = MEISynqNetTraceFIRST << 1,
    MEISynqNetTraceINIT         = MEISynqNetTraceFIRST << 2,
    MEISynqNetTraceRESET        = MEISynqNetTraceFIRST << 3,
    MEISynqNetTraceTIMING       = MEISynqNetTraceFIRST << 4,
    MEISynqNetTraceSERVICE_CMD  = MEISynqNetTraceFIRST << 5,
    MEISynqNetTraceFLOWCTRL     = MEISynqNetTraceFIRST << 6,
    MEISynqNetTraceMAP          = MEISynqNetTraceFIRST << 7,
    MEISynqNetTraceUNMAP        = MEISynqNetTraceFIRST << 8,

} MEISynqNetTrace;
Description

SynqNetTrace is an enumeration of SynqNet trace bits that can be used to enable/disable library trace statement output for the SynqNet object.

MEISynqNetTraceDYNA_ALLOC | Enables trace statements for controller external memory allocation during SynqNet initialization.
MEISynqNetTraceDYNA_FREE | Enables trace statements for controller external memory de-allocation.
MEISynqNetTraceINIT | Enables trace statements for SynqNet network initialization.
MEISynqNetTraceRESET | Enables trace statements for SynqNet network reset.
MEISynqNetTraceTIMING | Enables trace statements for SynqNet network timing calculations.
MEISynqNetTraceSERVICE_CMD | Enables trace statements for SynqNet service command transactions between the controller and SynqNet nodes.
MEISynqNetTraceFLOWCTRL | This trace bit enables trace statements for the SynqNet service command handshake between the controller and SynqNet nodes.
MEISynqNetTraceMAP | This trace bit enables trace statements for the mapping of firmware pointers to the dynamic controller memory.
MEISynqNetTraceUNMAP | This trace bit enables trace statements for the unmapping of firmware pointers from the dynamic controller memory.

See Also | Trace.exe utility


meiSynqNetCableNumToNodePort

Declaration
long meiSynqNetCableNumToNodePort(MEISynqNet     synqNet,
                                  long           cableNumber,
                                  long           *nodeNumber,
                                  MEINetworkPort *port);
Required Header stdmei.h
Description

SynqNetCableNumToNodePort converts a cable number on a SynqNet network into a node number and port. It reads the node number and writes it into a long pointed to by nodeNumber and reads the port and writes it to the value pointed to by port.

Network connections can be identified by a cable number OR a node number and port. For simple network topologies, it is easier to identify network connections by a cable number. For complex network topologies, it is easier to identify network connections by a node number and port.

synqNet | a handle to the SynqNet object
cableNumber | the number of the cable
*nodeNumber | a pointer to a node number
*port | a pointer to an enumerated port value
Return Values
MPIMessageOK if SynqNetCableNumToNodePort successfully converts a cable number on a SynqNet network into a node number and port.
See Also | meiSynqNetNodePortToCableNum | MEISynqNetCableList


meiSynqNetConfigGet

Declaration
long meiSynqNetConfigGet(MEISynqNet         synqNet,
                         MEISynqNetConfig   *config,
                         MEIFlash           flash);
Required Header stdmei.h
Description

SynqNetConfigGet reads a SynqNet network's configuration and writes it into the structure pointed to by config.

If the flash handle is NULL, the configuration is read from the controller's external memory.

If the flash handle is valid, the configuration is read from the controller's flash memory.

synqNet | a handle to a SynqNet object
*config | a pointer to a SynqNet config structure.
flash | a handle to a flash object
Return Values
MPIMessageOK if meiSynqNetConfigGet successfully reads a SynqNet network's configuration and writes it into the structure pointed to by config.
See Also | meiSynqNetInfo | meiSqNodeConfigGet | meiSynqNetConfigSet


meiSynqNetConfigSet

Declaration
long meiSynqNetConfigSet(MEISynqNet         synqNet,
                         MEISynqNetConfig   *config,
                         MEIFlash           flash);
Required Header stdmei.h
Description

SynqNetConfigSet writes a SynqNet network's configuration from the structure pointed to by config.

If the flash handle is NULL, the configuration is written to the controller's external memory.

If the flash handle is valid, the configuration is written to the controller's flash memory.

synqNet | a handle to a SynqNet object
*config | a pointer to a SynqNet config structure.
flash | a handle to a flash object
Return Values
MPIMessageOK if meiSynqNetConfigSet successfully writes a SynqNet network's configuration from the structure pointed to by config.
See Also | meiSynqNetInfo | meiSqNodeConfigSet | meiSynqNetConfigGet


meiSynqNetControl

Declaration
meiSynqNetControl(MEISynqNet  synqNet);
Required Header stdmei.h
Description

SynqNetControl returns a handle to the control object associated with the SynqNet object.

synqNet | a handle to a SynqNet object

Return Values
MPIControl | a handle to a control object.
MPIHandleVOID | if synqNet is not valid.

See Also | meiSynqNetCreate | mpiControlCreate


meiSynqNetCreate

Declaration
meiSynqNetCreate(MPIControl  control,
                 long        number)
Required Header stdmei.h
Description

SynqNetCreate creates a SynqNet object identified by number, which is associated with a control object.

SynqNetCreate is the equivalent of a C++ constructor.

control | a handle to a Control object
number | An index to the SynqNet network. First network = 0 Second network = 1 Third network = 2, etc.

Return Values
handle | to a SynqNet object. After creating a SynqNet object it must be validated using meiSynqNetValidate().
MPIHandleVOID | if the object could not be created

See Also | meiSynqNetDelete | meiSynqNetValidate


meiSynqNetDelete

Declaration
long meiSynqNetDelete(MEISynqNet  synqNet);
Required Header stdmei.h
Description

SynqNetDelete deletes a SynqNet object and invalidates its handle.

SynqNetDelete is the equivalent of a C++ constructor.

synqNet | a handle to a SynqNet object.

Remarks
 | All objects that are created must be deleted in the reverse order to avoid memory leaks.
Return Values
MPIMessageOK if SynqNetDelete successfully deleted the object.
See Also | meiSynqNetCreate | meiSynqNetValidate


meiSynqNetEventNotifyGet

Declaration
long meiSynqNetEventNotifyGet(MEISynqNet    synqNet,
                              MPIEventMask  *eventMask,
                              void          *external);
Required Header stdmei.h
Description

SynqNetEventNotifyGet reads the event mask (that specifies the event types for which host notification has been requested) to the location pointed to by eventMask, and also writes it into the implementation specific location pointed to by external. (if external is not NULL).

Use the event mask macros mpiEventMaskGET(…), mpiEventMaskBitGET(…), etc. to decode the eventMask.

The event notification data in external is in addition to the event notification data in eventMask. If either eventMask is NULL or external is NULL (not both), then the event notification data will not be copied to the NULL pointer.

synqNet | a handle to a SynqNet object
*eventMask | pointer to an event mask, whose bits are defined by the MPI/MEIEventType enumerations.
*external | pointer to external
XMP Only

external either points to a structure of type MEIEventNotifyData{…} or is NULL.

The MEIEventNotifyData{…} structure is an array of controller addresses, whose contents are placed into the MEIEventStatusInfo{…} structure (of all events generated by this object).

Return Values
MPIMessageOK | if meiSynqNetEventNotifyGet successfully reads the event mask
MPIMessageARG_INVALID | if the eventMask pointer is NULL.

See Also | MEI/MPIEventType | MEIEventNotifyData | MEIEventStatusInfo


meiSynqNetEventNotifySet

Declaration
long meiSynqNetEventNotifySet(MEISynqNet    synqNet,
                              MPIEventMask  eventMask,
                              void          *external);
Required Header stdmei.h
Description

SynqNetEventNotifySet requests host notification of the event(s) that are generated by SynqNet and specified by eventMask, and also specified by the implementation specific location pointed to by external (if external is not NULL).

Use the event mask macros meiEventMaskSYNQNET(…), mpiEventMaskSET(…), mpiEventMaskBitSET(…), mpiEventMaskCLEAR(…), etc. to create the eventMask.

The event notification data in external is in addition to the event notification data in eventMask. If either eventMask is NULL or external is NULL (not both), then the event notification data will not be copied to the NULL pointer.

synqNet | a handle to a SynqNet object
eventMask | pointer to an event mask, whose bits are defined by the MPI/MEIEventType enumerations.
*external | pointer to external
XMP Only

external either points to a structure of type MEIEventNotifyData{…} or is NULL.

The MEIEventNotifyData{…} structure is an array of controller addresses, whose contents are placed into the MEIEventStatusInfo{…} structure (of all events generated by this object).

Return Values
MPIMessageOK | if SynqNetEventNotifySet successfully writes the event mask
MPIMessageARG_INVALID | if the eventMask pointer is NULL

See Also | MEI/MPIEventType | MEIEventNotifyData | MEIEventStatusInfo


meiSynqNetEventReset

Declaration
long meiSynqNetEventReset(MEISynqNet     synqNet,
                          MEIEventMask   eventMask);
Required Header stdmei.h
Description

SynqNetEventReset resets the status/event bits that are specified in the eventMask and generated by the synqNet object. After a SynqNet event occurs, SynqNetEventReset should be called to reset the latched status/event bits so the specified event(s) can be generated again.
synqNet a handle to a SynqNet object
eventMask

An array that defines the event mask bits. The array is defined as:

typedef MPIEventMaskELEMENT_TYPE
        MPIEventMask[MPIEventMaskELEMENTS]

The bits are defined by the MPI/MEIEventType enumerations.

Return Values
MPIMessageOK if meiSynqNetEventReset successfully resets the status/event bits that are specified in the eventMask and generated by the synqNet object.
See Also | meiSynqNetStatus | meiSqNodeEventReset | meiSqNodeStatus


meiSynqNetIdleCableListGet

Declaration
long meiSynqNetIdleCableListGet(MEISynqNet          synqNet,
                                MEISynqNetCableList *idleCable);
Required Header stdmei.h
Description

SynqNetIdleLinkGet reads a SynqNet network's list of idle cables and writes them into the structure pointed to by idleCable. An idle cable has no data traffic. It is the redundant network connection available in ring topologies only. A single ring topology has only one idle cable.

After network initialization, the cable from the last node to the controller is idle by default. If a network fault occurs and the network is configured for fault recovery, the network traffic will be redirected around the faulty connection, through the idle cable, and the faulty connection will become the new idle cable. To test the idle cable, use the meiSynqNetIdleCableStatus(…) method.

synqNet | a handle to a SynqNet object
*idleCable | a pointer to a SynqNet cable list structure. The cable list structure contains the number of idle cables and their identifying numbers.
Return Values
MPIMessageOK if meiSynqNetIdleCableListGet successfully reads a SynqNet network's list of idle cables and writes them into the structure pointed to by idleCable.
See Also | meiSynqNetIdleCableStatus | SynqNet Topologies


meiSynqNetIdleCableStatus

Declaration
long meiSynqNetIdleCableStatus(MEISynqNet             synqNet,
                               long                   cableNumber,
                               MEISynqNetCableStatus  *cableStatus);
Required Header stdmei.h
Description

SynqNetIdleCableStatus reads an idle cable's status and writes it into the structure pointed to by cableStatus. Normally, the idle cable has no data traffic. SynqNetIdleCableStatus sends a special test packet across the specified idle cable and then waits for a valid response, then it sends another test packet in the opposite direction and waits for valid response.

The idle cable number for a network can be found using meiSynqNetIdleCableListGet(…). SynqNetIdleCableStatus is not allowed for non-idle cables or when the network is recovering from a fault. During fault recovery (SynqNetState = SYNQ_RECOVERING), the network traffic is redirected around the faulty connection and the idle cable is reassigned. After recovery is complete (SynqNetState = SYNQ), the new idle cable can be tested with SynqNetIdleCableStatus. Use meiSynqNetStatus(…) to determine the SynqNet state.

synqNet | a handle to a SynqNet object
cableNumber | the number of the cable to be tested
*cableStatus | a pointer to a SynqNet cable status enumerated value.
Return Values
MPIMessageOK if meiSynqNetIdleCableStatus successfully reads an idle cable's status and writes it into the structure pointed to by cableStatus.
See Also | meiSynqNetIdleCableListGet | MEISynqNetState


meiSynqNetInfo

Declaration
long meiSynqNetInfo(MEISynqNet       synqNet,
                    MEISynqNetInfo   *info);
Required Header stdmei.h
Description

SynqNetInfo reads static information about the network associated with the SynqNet object and writes it into the structure pointed to by info. The SynqNet info structure contains read only data that was determined during network initialization.

synqNet | a handle to a SynqNet object
*info | pointer to a SynqNet network information structure

Return Values
MPIMessageOK | if SynqNetInfo successfully reads the network information and writes it into the info structure.
MPIMessageARG_INVALID | if the info pointer is NULL.

See Also | meiSynqNodeInfo | meiSynqNetStatus


meiSynqNetInit

Declaration
long meiSynqNetInit(MEISynqNet    synqNet);
Required Header stdmei.h
Description

SynqNetInit initializes a SynqNet network. This method performs the same network initialization that is automatically done with mpiControlInit(…).

synqNet | a handle to a SynqNet object

Return Values
MPIMessageOK | if SynqNetInit successfully initializes the network
MPIMessageARG_INVALID | if the eventMask pointer is NULL.

See Also | meiSynqNetInfo | meiSynqNetStatus


meiSynqNetNodePortToCableNum

Declaration
long meiSynqNetNodePortToCableNum(MEISynqNet     synqNet,
                                  long           nodeNumber,
                                  MEINetworkPort port,
                                  long           *cableNumber);
Required Header stdmei.h
Description

SynqNetNodePortToCableNum converts a node number and port on a SynqNet network into a cable number. It reads the cable number and writes it into a long pointed to by cableNumber.

Network connections can be identified by a cable number OR a node number and port. For simple network topologies, it is easier to identify network connections by a cable number. For complex network topologies, it is easier to identify network connections by a node number and port.

synqNet | a handle to the SynqNet object
nodeNumber | the number of the node
port | an enumerated port value
*cableNumber | a pointer to a cable number
Return Values
MPIMessageOK if SynqNetPortToCableNum successfully converts a node number and port on a SynqNet network into a cable number.
See Also | MEISynqNetCableList


meiSynqNetNumber

Declaration
long meiSynqNetNumber(MEISynqNet   synqNet,
                      long         *number);
Required Header stdmei.h
Description

SynqNetNumber reads the index of a SynqNet network and writes it into the contents of a long pointed to by number. Each SynqNet network associated with a controller is indexed by an identification number (0, 1, 2, etc.).

synqNet | a handle to a SynqNet object.
*number | a pointer to the index of a SynqNet network.
Return Values
MPIMessageOK if SynqNetNumber successfully reads the network number.
See Also | meiSynqNetInfo


meiSynqNetPacketConfigGet

Declaration
long  meiSynqNetPacketConfigGet(MEISynqNet           synqNet,
                                MEISynqNetPacketCfg  *config);
Required Header stdmei.h
Description

SynqNetPacketConfigGet reads the current network packet configuration for all nodes found on the network to the location pointed to by config.

This method is useful for viewing the current network packed data being sent across the network. It is used in conjunction with SynqNetPacketConfigSet. This method is also useful for optimizing network traffic (bandwith).

Only configurable packet data fields are configured by this method. Fixed packet fields are not application configurable.

synqNet | a handle to a SynqNet object
*config | pointer to configuation structure defined by MEISynqNetPacketCfg.

Return Values
MPIMessageOK | if SynqNetPacketConfigGet successfully reads the network packet configuration.
MPIMessageARG_INVALID | if the config pointer is NULL.
MPIMessageUNSUPPORTED | An sqNodeLib module is missing or it contains a corrupt a resource table.

See Also | meiSynqNetPacketConfigSet | MEISynqNetPacketCfgNode


meiSynqNetPacketConfigSet

Declaration
long  meiSynqNetPacketConfigSet(MEISynqNet           synqNet,
                                MEISynqNetPacketCfg  *config,
                                MEIFlash             flash);
Required Header stdmei.h
Description

SynqNetPacketConfigSet sets the network packet configuration to the configuration defined in the location pointed to by config.

WARNING: meiSynqNetPacketConfigSet(...) is a low-level network routine that will clear other controller object configurations and reset the SynqNet network. This method should be executed in your application before configuring any other MPI objects.

This method is useful for optimizing network traffic (bandwith).

Only configurable packet data fields are configured by this method. Fixed packet fields are not application configurable.

synqNet | a handle to a SynqNet object
*config | pointer to configuration structure defined by MEISynqNetPacketCfg.
flash | a handle to a flash object. If NULL, configuration will only be written to working memory.

Return Values
MPIMessageOK | if SynqNetPacketConfigSet successfully writes the network packet configuration.
MPIMessageARG_INVALID | if the config pointer is NULL.
MEISynqNetMessageINCOMPLETE_MOTOR | minimum packet requirements for a motor have not been met. Be sure that your motor has at least one command field and one encoder.
MEISynqNetMessageINVALID_AUX_ENC_COUNT | too many secondary encoders have been configured on a node, or there are more secondary encoders than configured/enabled motors.
MEISynqNetMessageINVALID_MOTOR_COUNT | more motors configured than supported by the node.
MEISynqNetMessageINVALID_COMMAND_CFG | an unsupported command value has been selected, or it is not supported by the node.
MEISynqNetMessageINVALID_ENCODER_COUNT | feedback count exceeds MEISynqNetMaxEncoderFEEDBACK_COUNT, or exceeds the count supported by the node.
MEISynqNetMessageINVALID_CAPTURE_COUNT | capture count value is out of range, capture count exceeds capture resources supported by the node, or capture count is non-zero when encoder is disabled (feedbackCount == 0x0).
MEISynqNetMessageINVALID_COMPARE_COUNT | compare count value out of range, compare count exceeds compare resources supported by the node, or compare count is non-zero when encoder is disabled (feedbackCount == 0x0).
MEISynqNetMessageINVALID_INPUT_COUNT | ioInput count is out of range or it exceeds the count supported by the node.
MEISynqNetMessageINVALID_OUTPUT_COUNT | ioOutput count is out of range or it exceeds the count supported by the node.
MEISynqNetMessageINVALID_MONITOR_CFG | monitorConfig is out of range or it exceeds the count supported by the node.
MPIMessageUNSUPPORTED | an sqNodeLib module is missing or it contains a corrupt a resource table.

See Also | meiSynqNetPacketConfigGet | MEISynqNetPacketCfgNode | MEISynqNetPacketCfg


meiSynqNetShutdown

Declaration
long meiSynqNetShutdown(MEISynqNet     synqNet);
Required Header stdmei.h
Description

SynqNetEventShutdown disables a SynqNet network by shutting off cyclic data transmission from the controller to the nodes. This will cause the network state to transition to MEISynqNetStateDISCOVERY and nodes will go into a SynqLost state and disable their outputs.

synqNet | a handle to a SynqNet object
Return Values
MPIMessageOK if meiSynqNetShutdown successfully disables a SynqNet network by shutting off cyclic data transmission from the controller to the nodes.
See Also | meiSynqNetInit | mpiControlReset | mpiControlInit | meiSynqNetStatus


meiSynqNetStatus

Declaration
long meiSynqNetStatus(MEISynqNet          synqNet,
                      MEISynqNetStatus    *status);
Required Header stdmei.h
Description

SynqNetStatus reads status from the network associated with the SynqNet object and writes it into the structure pointed to by status. The SynqNet status structure contains network operation state and error counters. This data is updated every controller sample.

synqNet | a handle to a SynqNet object
*status | pointer to a SynqNet status structure

Return Values
MPIMessageOK | if meiSynqNetStatus successfully gets the network status and writes it into the structure
MPIMessageARG_INVALID | if the status pointer is NULL

See Also | meiSqNodeStatus | meiSynqNetInfo


meiSynqNetTiming

Declaration
long meiSynqNetTiming(MEISynqNet        synqNet,
                      MEISynqNetTiming  *timing);
Required Header stdmei.h
Description

SynqNetTiming returns the network timing values to the location pointed to by *timing for the current operating network. This method can only be called in MEISynqNetStatus.state >= MEISynqNetStateSYNQ.

synqNet | handle to a valid SynqNet object.
*timing | a pointer to a MEISynqNetTiming structure.

Return Values
MPIMessageOK | if meiSynqNetTiming successfully retrieves the network timing values.
MPIMessageARG_INVALID | if *timing equals NULL.

See Also | MEISynqNetTiming | MEISynqNetState


meiSynqNetTopologyClear

Declaration
long meiSynqNetTopologyClear(MEISynqNet     synqNet);
Required Header stdmei.h
Description

SynqNetTopologyClear will clear any topology information that is saved in the controller's flash memory by meiSynqNetTopologySave().

Executing this method will disable the firmware/mpi from comparing the discovered network topology and will run with whatever network is discovered during initialization.

WARNING: This is a low-level network routine that will clear other controller object configurations and reset the SynqNet network. This method should be executed in your application before configuring any other MPI objects.

synqNet | a handle to an MEISynqNet object whose network topology is to be cleared.
Return Values
MPIMessageOK if meiSynqNetTopologyClear successfully clears the networks topology information.
See Also | Saving Current Topology To Flash | meiSynqNetTopologySave


meiSynqNetTopologySave

Declaration
long meiSynqNetTopologySave(MEISynqNet     synqNet);
Required Header stdmei.h
Description

SynqNetTopologySave will save the current SynqNet topology to the controller's flash memory.

After a power-on or network reset, the firmware/mpi will compare the discovered network topology with the topology saved in flash memory. If all of the topology information matches, the controller will automatically transition the network to Synq (cyclic) mode. If the topology doesn't match, then the mpiControlInit() and/or meiSynqNetInit() methods return one of the following error codes:

MEISynqNetMessageTOPOLOGY_MISMATCH_FLASH
MEISynqNetMessageCABLE_LENGTH_MISMATCH

WARNING: This is a low-level network routine that will clear other controller object configurations and reset the SynqNet network. This method should be executed in your application before configuring any other MPI objects.

synqNet | a handle to an MEISynqNet object whose network topology is to be saved.
Return Values
MPIMessageOK if meiSynqNetTopologySave successfully saves the current SynqNet topology to the controller's flash memory.
See Also | Saving Current Topology To Flash | meiSynqNetTopologyClear


meiSynqNetValidate

Declaration
long meiSynqNetValidate(MEISynqNet  synqNet);
Required Header stdmei.h
Description

SynqNetValidate validates the SynqNet object and its handle. SynqNetValidate should be called immediately after an object is created.

synqNet | a handle to SynqNet object

Return Values
MPIMessageOK | if SynqNet is a handle to a valid object.
MEISynqNetMessageINTERFACE_NOT_FOUND | if the controller does not support a SynqNet interface.

See Also | meiSynqNetCreate | meiSynqNetDelete


Trace Objects

.

Trace Objects

Introduction

Use the Trace module to selectively produce trace output on a global and/or per-object basis for your application. You can specify the types of trace output when an application is linked, or dynamically (by using a debugger).

NOTE: You can also define your own trace function, using meiPlatformTraceFunction(...) For example, you could define your own function to send traces to a circular memory buffer.

The format of the trace output is determined by printf(...)-like trace macros located in MPI library source. The trace macros are of the form meiTrace#(mask, format, arg ...), where format and the args determine the trace output, and where # indicates the total number of arguments following the format argument (because macros cannot take variable numbers of arguments).

The placement and content of the meiTrace(...) macros in the MPI library source is the responsibility of whomever maintains the library. Because trace can be added as desired, it is often useful to leave trace statements in the library source code rather than remove them, as is similarly done with debug printf(...) statements. It is also useful to define per-object trace output types so that the volume of trace output is set to a manageable level.

The Trace module interface is declared in the XMP\include\trace.h header file. In order for your application to use Trace functions, you must build your application with the MEI_TRACE conditional-compile symbol defined.

NOTE: Debug and DebugSingle are the only MPI library configurations that will produce trace output.

To install trace, simply install the DLL for either the Debug or DebugSingle configuration. The Debug and DebugSingle configurations of the MPI library are built with the MEI_TRACE compile-time symbol defined.

By default, trace output is sent to standard error. However, to send trace output to a file, your application can call the meiTraceFile(char *fileName) function.

To obtain the current global trace mask, call meiTraceGet(...).
To modify the global trace mask, call meiTraceSet(...).

To obtain an object's trace mask, call meiObjectTraceGet(...) (defined in stdmei.h).
To modify an object's trace mask, call meiObjectTraceSet(...).

Trace Masks | Global Trace Outputs | Per-Object Trace Outputs

Methods

Configuration and Information Methods
 | meiTraceEol | Set the end-of-line character to be used by Trace
 | meiTraceFile | Send trace output to a file
 | meiTraceFunction | sets function used to display a trace buffer
 | meiTraceGet | Get global trace mask
 | meiTraceMaskBits | Convert the trace mask into an array of trace bits.
 | meiTraceMsg | Convert the message identification value into a string.
 | meiTraceMsgFunction | Set a module's trace message function.
 | meiTraceSet | Set global trace mask

Data Types

MEITrace
MEITraceFunction
MEITraceMask
MEITraceMsgFunction

Constants

MEITraceMaskGLOBAL


MEITraceFunction

MEITraceFunction

typedef long (*MEITraceFunction)(const char *buffer);

Description | Definition for a trace function interface. TraceFunction can be used to define a custom trace output routine. MEITraceFunction function must take a pointer to a buffer as a parameter and must return a long.

See Also | meiTraceFunction


MEITraceMsgFunction

MEITraceMsgFunction

typedef long(*MEITraceMsgFunction)(const char *buffer);
Description

TraceMsgFunction is the type definition for the callback function used by meiTrace(…). A default callback function is provided internally to all MPI/MEI modules, but an application can also be written to override it and provide a custom message function instead.

See Also | meiTraceMsgFunction | MEITrace


MEITraceMask

MEITraceMask

typedef    unsigned long MEITraceMask;

Description | TraceMask is a bit mask used to enable/disable library trace statement output.

See Also | meiTraceGet | meiTraceSet | MEITraceMaskGLOBAL


MEITraceMaskGLOBAL

MEITraceMaskGLOBAL

extern MEITraceMask 	MEITraceMaskGLOBAL;
Description

TraceMaskGlobal is a non-object specific MPI Trace mask variable used for library wide Trace bits.

See Also | MEITraceMask


MEITrace

MEITrace

typedef enum {
    MEITraceNONE = 0,

    MEITraceFIRST = 0x0001,

    MEITraceFUNCTION_ENTRY  = MEITraceFIRST << 0,
    MEITraceFUNCTION_RETURN = MEITraceFIRST << 1,
    MEITraceMEMORY_ALLOC	= MEITraceFIRST << 2,
    MEITraceMEMORY_FREE		= MEITraceFIRST << 3,
    MEITraceMEMORY_GET		= MEITraceFIRST << 4,
    MEITraceMEMORY_SET		= MEITraceFIRST << 5,
    MEITraceVALIDATE		= MEITraceFIRST << 6,
    MEITraceLOCK_GIVE		= MEITraceFIRST << 7,
    MEITraceLOCK_TAKE		= MEITraceFIRST << 8,
    MEITraceEVENT			= MEITraceFIRST << 9,

    MEITraceALL = ((MEITraceLAST << 1) - 1)
} MEITrace;
Description

Trace is an enumeration of generic trace bits that can be used to enable/disable library trace statement output for objects throughout the MPI.

MEITraceFUNCTION_ENTRY | Trace the entry into all methods.
MEITraceFUNCTION_RETURN | Trace the return from all methods.
MEITraceMEMORY_ALLOC | Enables trace statements for all host memory allocations.
MEITraceMEMORY_FREE | Enables trace statements for all host memory de-allocations.
MEITraceMEMORY_GET | Enables trace statements for all controller memory reads.
MEITraceMEMORY_SET | Enables trace statements for all controller memory writes.
MEITraceVALIDATE | Enables trace statements for all function parameter validations.
MEITraceLOCK_GIVE | Enables trace statements for all IPC lock releases.
MEITraceLOCK_TAKE | Enables trace statements for all IPC lock takes.
MEITraceEVENT | Enables trace statements for all MPI Events.

See Also | Trace Object | Trace.exe utility


meiTraceEol

Declaration
char meiTraceEol(char eol)
Required Header stdmei.h
Description

TraceEol function simply calls meiPlatformTraceEol(...), which sets the end-of-line character that will be used by meiPlatformTrace(...). By default, meiPlatformTrace(...) will append a newline character ('\n') to the messages that it displays. The meiPlatformTraceEol(...) function allows your application to set the default end-of-line character.

Returns

 the previous end-of-line character used by meiPlatformTrace(...)
See Also | meiPlatformTrace | meiPlatformTraceEol


meiTraceFile

Declaration
long meiTraceFile(const char *fileName)
Required Header stdmei.h
Description TraceFile causes trace output to be sent to the file fileName. By default, trace output goes to standard output. Note that if fileName is Null, trace output still goes to standard output.
Return Values
MPIMessageOK if TraceFile successfully causes trace output to be sent to the file
See Also


meiTraceFunction

Declaration
MEITraceFunction meiTraceFunction(MEITraceFunction traceFunction)
Required Header stdmei.h
Description

TraceFunction sets the function used to display a trace buffer.

Front end to meiPlatformTraceFunction(). If traceFunction is NULL (default), then trace functions is fprintf(MEIPlatformTraceSTREAM) (default stdout).

Return Values
handle | to previous Trace function
NULL | otherwise
See Also


meiTraceGet

Declaration
MEITraceMask meiTraceGet(void)
Required Header stdmei.h
Description

TraceGet returns the current global trace mask for the application.

Returns

 the global trace mask
See Also | meiTraceSet


meiTraceMsg

Declaration
const char * meiTraceMsg(long    messageId,
                         char    *messageText);
Required Header stdmei.h
Description

TraceMsg converts the message identification value into a string pointed to by messageText.

messageId | a message identification value.
*messageText | a pointer to a character string containing the text for the messageId.

Returns

See Also | meiTraceMsgFunction


meiTraceMsgFunction

Declaration
long meiTraceMsgFunction(MPIModuleId            moduleId,
                         MEITraceMsgFunction    function);
Required Header stdmei.h
Description

TraceMsgFunction sets a module's trace message function.

moduleId | an enumerated module identification value
function | a pointer to a trace message function.

Returns
See Also


meiTraceMaskBits

Declaration
long meiTraceMaskBits(long    mask,
                      long    *bitCount,
                      long    *bit);
Required Header stdmei.h
Description

TraceMaskBits converts the trace mask into an array of trace bits and the length of the array.

mask | A bit mask of enumerated trace bits.
*bitCount | A pointer to a long containing the number of trace bits enabled in the mask. This value is also the length of the bit array.
*bit | A pointer to an array of longs containing the enumerated trace bits. Each array member contains one trace bit enumerated value.

Returns

See Also | MEITrace | meiTraceGet | meiTraceSet


meiTraceSet

Declaration
MEITraceMask meiTraceSet(MEITraceMask mask)
Required Header stdmei.h
Description TraceSet sets the global trace mask to mask.
If "traceMask" is | Then
MEITraceALL | all global categories of trace will be enabled
MEITraceNONE | all categories of trace will be disabled

Returns

 the value of the previous global trace mask
See Also | meiTraceGet


GlobalTrace Outputs

.

Global Trace Outputs

There is a global 32-bit trace mask: the low 16 bits are the global trace output types, while the upper 16 bits are the per-object trace output types. Each object has a similar trace mask. The upper 16 bits of the global trace mask are not defined, but can be used to set the per-object output types for all objects. To enable all trace output types for all objects, set the global trace mask to all 1s (i.e., -1).

The MEITrace{...} enum (declared in trace.h) specifies the global types of trace output, i.e., the types of trace output that can be produced by any object or module. The MEITrace{...} enum defines constants that you use together as a bit mask. You specify the desired trace output as a combination (logical OR) of MEITrace{...} constants.

There are 16 possible types of global trace output, with 12 global trace outputs defined.

Output Type | Displays
MEITraceFUNCTION_ENTRY | Function name & calling parameters upon entry to function
MEITraceFUNCTION_RETURN | Function name, calling parameters & return value upon exit from function
MEITraceMEMORY_ALLOC | The Address & byte count when memory is dynamically allocated
MEITraceMEMORY_FREE | The Address & byte count when dynamically allocated memory is freed
MEITraceMEMORY_GET | Source address, destination address, byte count when reading XMP firmware memory
MEITraceMEMORY_SET | Source address, destination address, byte count when writing XMP firmware memory
MEITraceVALIDATE | Results of object validation
MEITraceLOCK_GIVE | When a resource lock is released
MEITraceLOCK_TAKE | When a resource lock is waited for & obtained
MEITraceEVENT | When an XMP event is received
MEITraceALL | All global trace outputs (lower 16 bits)
MEIModuleTraceALL | All per-object trace outputs (upper 16 bits)

Return to Trace Object's page


Per-Object Trace Outputs

.

Per-Object Trace Outputs

There are 16 possible types of per-object trace output. Each object can declare up to 16 of its own trace output types. MPI modules declare per-object trace output types in stdmei.h. MEI modules declare per-object trace output types in the module header file.

Output Type | Displays
MEIMotionTraceSTATUS | Status of the Motion Supervisor
MEINotifyTrcaeTHREAD | When a thread goes to sleep or wakes up
MEISequenceTraceLOAD | When a batch of new commands are sent to the XMP Program Sequencer
MEIConfigTracePROGRESS | Displays “.” as it executes (used by config utility)
MEIRecorderTraceRECORD_GET | When the Recorder gets records from the XMP
MEIRecorderTraceSTATUS | The number of data records available in the XMP
Note: The first 5 output types overlap in the mask.

Return to Trace Object's page


Trace Masks

.

Trace Masks

Every MPI object contains an MEITraceMask and every process contains a single global MEITraceMask. An MEITraceMask consists of bits, where each bit corresponds to a single trace category. A trace category is a specific type of debug information that you want to be displayed by the MPI library. A trace category can be either global (applying to all MPI objects) or object-specific (applying only to a specific MPI object).

Trace Category | Is
global | declared by the MEITrace{...} enum in trace.h.
object-specific (for MPI objects) | declared in stdmei.h.
object-specific (for MEI objects) | declared in the object header file (for MEI objects). Note that the trace mask bits for object-specific trace categories overlap.

An object will produce trace output for a trace category when the logical OR of the global trace mask and the object's trace mask has the bit set that corresponds to the trace category.

If the global trace mask has all of its bits set, then all objects will display trace output for all trace categories.

If an object's trace mask has all of its bits set, then that object will display trace output for all trace categories, but a different object of the same type might produce less or no trace output depending on the setting of its trace mask. The setting of the global and object trace masks is under the control of your application.

The trace mask is derived in 2 steps:

    1. The global trace mask is logically ORed with the object trace mask. This yields the current trace mask, representing the desired trace output types as specified by the application.
    2. The current trace mask (from step1) is logically ANDed with a library-defined trace mask (that describes the trace output types for which the trace macro should produce output). If the result of the AND is non-zero, trace output will be produced using the format and the args [from meiTrace#(mask, format, arg ...

Return to Trace Object's page


Cut and Paste Functions

.

Last Updated: 18Jul02

Below is a list of MPI-related functions that you can cut and paste into your own application code. These cut and paste functions are useful for accomplishing many common tasks, such as enabling every amplifier associated with a motion supervisor.

Short descriptions of the functions are located at the top of the file, while full descriptions of the functions are located further down in the document. New functions will be added to this library, and the latest version will always be available here.

If you find a bug in one of these functions, please submit the bug to tech@motioneng.com.

NOTE: The functions located on this page are not officially supported by MEI. Feel free to use them at your own discretion.

CutNPaste.c --
/**********************************************************************

    A collection of various potentially useful functions. Nothing in here
    approaches supported status.

    Feel free to add, but not remove functions from this file. We only ask
    that you add some comments above each function and add the name and
    one line (or so) description to the following list to make it easy
    for others to use this file.

    After adding something to this file, PLEASE compile a program with it
    to make sure it isn't broke! Make sure to add appropriate #includes.

**********************************************************************/

/***********************************************************************

Listing of functions in this file:

* trapMove()            Commands a simple trap move. It checks for an
                        appropriate state first and returns error codes, if
                        appropriate.

* sCurveMove()      Commands a simple S Curve move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* ptMove()          Commands a pt move. Can be used to make appended lists.

* pvtMove()         Commands a pvt move. Can be used to make appended lists.

* velMove()         Commands a simple vel move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* isMotionDone()     returns a 1 if the motion is idle, a 0 if it is not.

* waitForMotionDone()   Stalls the program in a 10 msec polling loop until it
                        gets an MPIMotionIDLE

* clearError()          clears all the errors on an MS and enables the amps on that MS.

* motionAxisLoop()      For every axis attached to a motion supervisor (perform some action) [EXAMPLE]

* axisMotorLoop()       For every motor attached to an axis (perform some action) [EXAMPLE]

* motionMotorLoop()     For every motor attached to a motion supervisor (perform some action) [EXAMPLE]

* axisAmpEnable()       Enable the amplifier for every motor attached to an axis

* axisAmpDisable()      Disable the amplifier for every motor attached to an axis

* motionAmpEnable()     Enable the amplifier for every motor attached to a motion supervisor

* motionAmpDisable()    Disable the amplifier for every motor attached to a motion supervisor

* setIp()           configures the program to use a controller at address "server"

* parseCommandLine()    Parsing for apps that need command line arguments (example)

* basicParsing()    Perform basic command line parsing. (-control -server -port -trace)

* programInit() / programCleanup():
    A bare minimum object creation / deletion for programs of the scope of
    motion1 or so.

* programInitSingle()       Create and initialize MPI objects.
                                [One of each object -- Use as a model]

* programCleanupSingle()    Perform certain cleanup actions and delete MPI objects
                                [One of each object -- Use as a model]

* programInitMultiple()     Create and initialize MPI objects.
                                [Arrays of some objects -- Use as a model]

* programCleanupMultiple()  Perform certain cleanup actions and delete MPI objects
                                [Arrays of some objects -- Use as a model]

* programInitSingleWithMapping()    Create and initialize MPI objects, and place MS's axis map on XMP
                                        [One of each object -- Use as a model]

* programInitMultipleWithMapping()  Create and initialize MPI objects, and place MSs' axis maps on XMP
                                        [Arrays of some objects -- Use as a model]

* homeLimitOnInput()    Configure Home Limit to be triggered on the Home Input rather than the capture

* enableUserLimit()     Configures and enables one user limit

* disableUserLimit()    Disables and erases the configuration of one user limit

* userLimitEnable()     Enables or disables one user limit
                            This function does not change (most of) the configuration of a user limit.

* sequenceCommandAdd() Creates a command (MPICommand object) and appends it to
                        sequence's list of commands.

* sequenceProgramCreate()    Shows how one can create a MPISequence program.

* sequenceProgramDelete(MPISequence *sequence)  Removes and deletes all command objects on sequence's
                                                   command list and then deletes sequence.

* sequenceRun()     Starts a sequence, waits for the user to press a key and then
                       stops the sequence.

* recordData()      Start the XMP's recorder, get data, and stop the recorder

* configureRecorder()   Example of how to configure the data recorder object

* stopRecorder()    Stops the data recorder ignoring the MPIRecorderMessageSTOPPED
                        message if the recorder is already stopped.

            ** add yours here **

***********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>

#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

long    trapMove(MPIMotion      *motion,
                MPITrajectory   *trajectory,
                double          *position);

long    sCurveMove(MPIMotion        *motion,
                    MPITrajectory   *trajectory,
                    double          *position);

long    ptMove(MPIMotion    motion,
               double       point[],
               double       time[],
               long         numPoints,
               long         final);

long    pvtMove(MPIMotion   motion,
                double      point[],
                double      velocity[],
                double      time[],
                long        numPoints,
                long        final);

long    velMove(MPIMotion       *motion,
                MPITrajectory   *trajectory);

long    isMotionDone(MPIMotion      motion);

void    waitForMotionDone(MPIMotion     motion);

long    clearError(MPIMotion    motion);

void    motionAxisLoop(MPIMotion    motion);

void    axisMotorLoop(MPIAxis   axis);

void    motionMotorLoop(MPIMotion   motion);

void    axisAmpEnable(MPIAxis   axis);

void    axisAmpDisable(MPIAxis  axis);

void    motionAmpEnable(MPIMotion   motion);

void    motionAmpDisable(MPIMotion  motion);

void    setIp(MPIControlType    *controlType,
              MPIControlAddress *controlAddress,
              char              *server);

long    parseCommandLine(long               *motorNumber,
                         int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress);

void    basicParsing(int                     argc,
                    char                    *argv[],
                    MPIControlType          *controlType,
                    MPIControlAddress       *controlAddress);

long    programInit(long                motorNumber,
                    MPIControl          *control,
                    MPIMotor            *motor,
                    MPIAxis             *axis,
                    MPIMotion           *motion,
                    MPIControlType      *controlType,
                    MPIControlAddress   *controlAddress);

long    programCleanup(MPIMotion        *motion,
                       MPIAxis          *axis,
                       MPIMotor         *motor,
                       MPIControl       *control);

void    programInitSingle(MPIControl            *control,
                         MPIControlType      controlType,
                         MPIControlAddress  *controlAddress,
                         MPIMotion          *motion,
                         long                motionNumber,
                         MPIAxis            *axis,
                         long                axisNumber,
                         MPIFilter          *filter,
                         long                filterNumber,
                         MPIMotor           *motor,
                         long                motorNumber,
                         MPIRecorder        *recorder,
                         MPISequence        *sequence,
                         long                sequenceNumber,
                         MPICapture         *capture,
                         long                captureNumber,
                         MPICompare         *compare,
                         long                compareNumber,
                         MPIEventMgr        *eventMgr,
                         MPINotify          *notify,
                         Service            *service);

void    programCleanupSingle(MPIControl         *control,
                             MPIMotion          *motion,
                             MPIAxis            *axis,
                             MPIFilter          *filter,
                             MPIMotor           *motor,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             MPICapture         *capture,
                             MPICompare         *compare,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             Service            *service);

void    programInitMultiple(MPIControl          *control,
                             MPIControlType      controlType,
                             MPIControlAddress  *controlAddress,
                             MPIMotion          *motion,
                             long                numberOfMotions,
                             long               *motionNumber,
                             MPIAxis            *axis,
                             long                numberOfAxes,
                             long               *axisNumber,
                             MPIFilter          *filter,
                             long                numberOfFilters,
                             long               *filterNumber,
                             MPIMotor           *motor,
                             long                numberOfMotors,
                             long               *motorNumber,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             long                numberOfSequences,
                             long                sequencePageSize,
                             long               *sequenceNumber,
                             MPICapture         *capture,
                             long                numberOfCaptures,
                             long               *captureNumber,
                             MPICompare         *compare,
                             long                numberOfCompares,
                             long               *compareNumber,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             long                numberOfNotifys,
                             Service            *service);

void    programCleanupMultiple(MPIControl           *control,
                             MPIMotion          *motion,
                             long                numberOfMotions,
                             MPIAxis            *axis,
                             long                numberOfAxes,
                             MPIFilter          *filter,
                             long                numberOfFilters,
                             MPIMotor           *motor,
                             long                numberOfMotors,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             long                numberOfSequences,
                             long                sequencePageSize,
                             MPICapture         *capture,
                             long                numberOfCaptures,
                             MPICompare         *compare,
                             long                numberOfCompares,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             long                numberOfNotifys,
                             Service            *service);

void    programInitSingleWithMapping(MPIControl         *control,
                                     MPIControlType      controlType,
                                     MPIControlAddress  *controlAddress,
                                     MPIMotion          *motion,
                                     long                motionNumber,
                                     MPIAxis            *axis,
                                     long                axisNumber,
                                     MPIFilter          *filter,
                                     long                filterNumber,
                                     MPIMotor           *motor,
                                     long                motorNumber,
                                     MPIRecorder        *recorder,
                                     MPISequence        *sequence,
                                     long                sequenceNumber,
                                     MPICapture         *capture,
                                     long                captureNumber,
                                     MPICompare         *compare,
                                     long                compareNumber,
                                     MPIEventMgr        *eventMgr,
                                     MPINotify          *notify,
                                     Service            *service);

void    programInitMultipleWithMapping(MPIControl           *control,
                                     MPIControlType      controlType,
                                     MPIControlAddress  *controlAddress,
                                     MPIMotion          *motion,
                                     long                numberOfMotions,
                                     long               *motionNumber,
                                     MPIAxis            *axis,
                                     long                numberOfAxes,
                                     long               *axisNumber,
                                     MPIFilter          *filter,
                                     long                numberOfFilters,
                                     long               *filterNumber,
                                     MPIMotor           *motor,
                                     long                numberOfMotors,
                                     long               *motorNumber,
                                     MPIRecorder        *recorder,
                                     MPISequence        *sequence,
                                     long                numberOfSequences,
                                     long                sequencePageSize,
                                     long               *sequenceNumber,
                                             MPICapture         *capture,
                                     long                numberOfCaptures,
                                     long               *captureNumber,
                                     MPICompare         *compare,
                                     long                numberOfCompares,
                                     long               *compareNumber,
                                     MPIEventMgr        *eventMgr,
                                     MPINotify          *notify,
                                     long                numberOfNotifys,
                                     Service            *service);

void homeLimitOnInput(MPIMotor  motor,
                      long      activeHigh);

void enableUserLimit(MPIMotor       motor,
                     long           enable);

void disableUserLimit(MPIMotor      motor,
                      MEIEventType  limit);

void userLimitEnable(MPIMotor       motor,
                     MEIEventType   limit,
                     long           enable);

long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label);

MPISequence sequenceProgramCreate(MPIControl control);

long sequenceProgramDelete(MPISequence *sequence);

void sequenceRun(MPISequence sequence);

long    recordData(MPIRecorder           recorder,
                   long                  numRecords,
                   long                  period,
                   long                  eventCount,
                   MPIRecorderRecord    *records);

void configureRecorder(MPIRecorder recorder);

void stopRecorder(MPIRecorder recorder);

/*******************************************************

    trapMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory and    position information. It checks for an idle
    state before it commands the move. If it gets something an idle state, it
    commands a motionStart, if it gets a moving state, it commands a
    motionModify. If it gets something else, no move is commanded and an error
    code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE,MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long    trapMove(MPIMotion      *motion,
                MPITrajectory   *trajectory,
                double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.trapezoidal.trajectory   = trajectory;
    params.trapezoidal.position     = position;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeTRAPEZOIDAL,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/*******************************************************

    sCurveMove commands a simple trap move to the specified motion supervisor
    with the specified trajectory and position information. It checks for an
    idle state before it commands the move. If it gets something an idle state,
    it commands a motionStart, if it gets a moving state, it commands a
    motionModify.  If it gets something else, no move is commanded and an error
    code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long     sCurveMove(MPIMotion       *motion,
                    MPITrajectory   *trajectory,
                    double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.sCurve.trajectory    = trajectory;
    params.sCurve.position      = position;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeS_CURVE,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/******************************************************************************

    ptMove commands a PT move

******************************************************************************/

long    ptMove(MPIMotion    motion,
               double       point[],
               double       time[],
               long         numPoints,
               long         final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pt.pointCount = numPoints;   /* Number of time points */
    params.pt.position = point;     /* Position array */
    params.pt.time = time;          /* Time array */
    params.pt.point.retain = 0;     /* Flush frame buffer after execution */
    params.pt.point.final = final;      /* Last point */
    params.pt.point.emptyCount = 5; /* Start E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}

/******************************************************************************

    pvtMove commands a PVT move

******************************************************************************/

long    pvtMove(MPIMotion   motion,
                double      point[],
                double      velocity[],
                double      time[],
                long        numPoints,
                long        final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pvt.pointCount = numPoints;  /* Number of time points */
    params.pvt.position = point;        /* Position array */
    params.pvt.velocity = velocity;
    params.pvt.time = time;         /* Time array */
    params.pvt.point.retain = 0;        /* Flush frame buffer after execution */
    params.pvt.point.final = final;     /* Last point */
    params.pvt.point.emptyCount = 5;    /* E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePVT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePVT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}

/*******************************************************

    velMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory    information. It checks for an idle state before
    it commands the move. If it gets something an idle state, it commands a
    motionStart, if it gets a moving state, it commands a motionModify.  If it
    gets something else, no move is commanded and an error code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long    velMove(MPIMotion       *motion,
                MPITrajectory   *trajectory)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.velocity.trajectory  = trajectory;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeVELOCITY,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
            /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/*********************************************************************

    isMotionDone() returns a 1 if the motion is idle, a 0 if it is not.

**********************************************************************/

long    isMotionDone(MPIMotion      motion)
{
    MPIStatus   status;

    long    returnValue = FALSE;

    returnValue =
    mpiMotionStatus(motion,
                    &status,
                    NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateIDLE)
    {
        returnValue = TRUE;
    }

    return returnValue;
}

/*********************************************************************

 waitForMotionDone() polls motion to see if the axis is in an idle or error
 state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
 MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.

**********************************************************************/
void waitForMotionDone(MPIMotion motion)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue = MPIMessageOK;

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING_ERROR:
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 10ms and give up control to other threads */
                meiPlatformSleep(10);
                break;
            }
            case MPIStateIDLE:
            case MPIStateERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}

/******************************************************************************

 clearError() clears all the errors on an MS and enables the amps on that MS.
 It does this by commanding a mpiMotionAction(reset) and then waits a couple
 smaples, tries again if it needs to, then waits a couple samples and makes
 sure it happened, returning an error if it didn't, and enables all the amps on
 the MS using motionAmpEnable().

******************************************************************************/

long    clearError(MPIMotion motion)
{
    MPIStatus           status;         /* Status handle */

    long returnValue;

    returnValue = mpiMotionAction(motion, MPIActionRESET);
    msgCHECK(returnValue);

    meiControlSampleWait(mpiMotionControl(motion), 2);

    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateERROR)
    {
        returnValue = mpiMotionAction(motion, MPIActionRESET);
        msgCHECK(returnValue);
    }

    meiControlSampleWait(mpiMotionControl(motion), 2);

    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateERROR)
    {
        returnValue = MPIMotionMessageERROR;
    }

    motionAmpEnable(motion);

    return returnValue;
}

/*****************************************************************************

  For every axis attached to a motion supervisor (perform some action)

  This is a model for any MPI Object that has other MPI objects attached to
   it via a linked list. (i.e. there exists mpiXxxYyyFirst(...) and
   mpiXxxYyyNext(...) functions.)

******************************************************************************/

/* For every axis attached to a motion supervisor ... */
void motionAxisLoop(MPIMotion   motion)
{
    MPIAxis axis;

    /* For every axis attached to a motion ... */
    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Place your code here */
    }
}

/*****************************************************************************

  For every motor attached to an axis (perform some action).  This is useful
   when motor objects haven't been created or when someone is using gantry code.

  This is a model for any MPI Object that has other MPI objects attached to
   it via object maps.  (i.e. there exits an mpiXxxYyyMap(...) function.)

******************************************************************************/

/* For every motor attached to an axis ... */
void axisMotorLoop(MPIAxis  axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(map, motorIndex)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  For every motor attached to a motion supervisor (perform some action)

  This is a model for any MPI Object (Father) that has other MPI objects
   (Children) attached to it indirectly in the following way:

    MPIFather --(linked list)--> MPIIntermediate --(object map)-> MPIChild

******************************************************************************/

/* For every motor attached to a motion supervisor ... */
void motionMotorLoop(MPIMotion  motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Enable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.
   This code also sets the command position equal to the actual position and
   resets the integrator before enabling the amplifiers so that the motors will
   not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to an axis */
void axisAmpEnable(MPIAxis  axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    axisMotorMap;
    MPIObjectMap    motorFilterMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &axisMotorMap);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(axisMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* Get the actual position of the axis */
                returnValue = mpiAxisActualPositionGet(axis, &position);
                msgCHECK(returnValue);

                /* Set the command position equal to the actual position */
                returnValue = mpiAxisCommandPositionSet(axis, position);
                msgCHECK(returnValue);

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &motorFilterMap);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MEIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(motorFilterMap, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Disable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to an axis */
void axisAmpDisable(MPIAxis axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorNumber;
    long            returnValue;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorNumber = 0; motorNumber < MEIXmpMAX_Motors; motorNumber++) {

        if (map & (1<<motorNumber)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorNumber);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Enable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using
   gantry code.  This code also sets the command position equal to the actual
   position and resets the integrator before enabling the amplifiers so that
   the motors will not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to a motion supervisor */
void motionAmpEnable(MPIMotion  motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* For every axis */
                for (axis =  mpiMotionAxisFirst(motion);
                     axis != MPIHandleVOID;
                     axis =  mpiMotionAxisNext(motion, axis)) {

                    /* Get the object map for the motors */
                    returnValue = mpiAxisMotorMapGet(axis, &map);
                    msgCHECK(returnValue);

                    /* If axis is attached to motor ... */
                    if (mpiObjectMapBitGET(map, motorIndex)) {

                        /* Get the actual position of the axis */
                        returnValue = mpiAxisActualPositionGet(axis, &position);
                        msgCHECK(returnValue);

                        /* Set command position equal to actual position */
                        returnValue = mpiAxisCommandPositionSet(axis, position);
                        msgCHECK(returnValue);
                    }
                }

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &map);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MEIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(map, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Disable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using
   gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to a motion supervisor */
void motionAmpDisable(MPIMotion motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

    Sets controller to Network mode.  Server is the name of the computer in
    quotes.     Use IP or computer name.

******************************************************************************/

void setIp(MPIControlType       *controlType,
           MPIControlAddress    *controlAddress,
           char                 *server)
{
    controlAddress->type.client.port = 3300;
    controlAddress->type.client.server = server;
    *controlType = MPIControlTypeCLIENT;
}

/**********************************************

    Parsing for apps that need command line arguments (example)

    In this example, you would pass in the default motor number you
    want to use.  parseCommandLine() would then change the motor number
    if the user specified (s)he wanted to use a different motor.

**********************************************/

long    parseCommandLine(long               *motorNumber,
                         int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-motor",   ArgTypeLONG,    motorNumber,    },
        {   NULL,       ArgTypeINVALID, NULL,   }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   controlType,
                   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) {
        fprintf(stderr,"usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/*****************************************************************************

  Perform basic command line parsing. (-control -server -port -trace)

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

******************************************************************************/

/* 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);
    }
}

/************************************************************

  Example of a typical program initialization function:
    A bare minimum object creation for programs of the scope of
    motion1 or so. Designed to work with programCleanup below.

  #define at head of program file:

#define MOTOR_NUMBER    (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                MOTOR_NUMBER,
                &motion,
                &axis,
                &motor);

************************************************************/

long    programInit(MPIControl          *control,
                    MPIControlType      *controlType,
                    MPIControlAddress   *controlAddress,
                    long                motorNumber,
                    MPIMotion           *motion,
                    MPIAxis             *axis,
                    MPIMotor            *motor)
{
    long returnValue;

    /* Obtain a Control handle. */
    *control =
        mpiControlCreate(*controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue = mpiControlInit(*control);
    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "mpiControlInit(0x%x) returns 0x%x: %s\n",
                        *control,
                        returnValue,
                        mpiMessage(returnValue, NULL));

        exit(returnValue);
    }

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

    /* Create axis object */
    *axis =
        mpiAxisCreate(*control,
                      motorNumber);
    msgCHECK(mpiAxisValidate(*axis));

    /* Create motion object */
    *motion =
        mpiMotionCreate(*control,
                        motorNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    return  returnValue;

}

/*********************************************************

  Example of a typical program cleanup function:
    A bare minimum object deletion for programs of the scope of
    motion1 or so. Designed to work with programInit above.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   &motion,
                   &axis,
                   &motor);

*********************************************************/

long    programCleanup(MPIControl       *control,
                       MPIMotion        *motion,
                       MPIAxis          *axis,
                       MPIMotor         *motor)
{
    long returnValue;

    /* Delete the remaining handles */
    returnValue = mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(*control);
    msgCHECK(returnValue);

    return returnValue;
}

/*****************************************************************************

  Create and initialize MPI objects.  [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitSingle(MPIControl           *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    /* Create filter object */
    *filter =
        mpiFilterCreate(*control,
                        filterNumber);
    msgCHECK(mpiFilterValidate(*filter));

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

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [One of each object -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   &motion,
                   &axis,
                   &filter,
                   &motor,
                   &recorder,
                   &sequence,
                   &capture,
                   &compare,
                   &eventMgr,
                   &notify,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupSingle(MPIControl        *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    MPIFilter       *filter,
                    MPIMotor        *motor,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    MPICapture      *capture,
                    MPICompare      *compare,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    Service         *service)
{
    long    returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification object */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    /* Delete compare object */
    returnValue =
        mpiCompareDelete(*compare);
    msgCHECK(returnValue);

    /* Delete capture object */
    returnValue =
        mpiCaptureDelete(*capture);
    msgCHECK(returnValue);

    /* Delete sequencer object */
    returnValue =
        mpiSequenceDelete(*sequence);
    msgCHECK(returnValue);

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete filter object */
    returnValue =
        mpiFilterDelete(*filter);
    msgCHECK(returnValue);

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Create and initialize MPI objects.  [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitMultiple(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [Arrays of some objects -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   motion,
                   numberOfMotions,
                   axis,
                   numberOfAxes,
                   filter,
                   numberOfFilters,
                   motor,
                   numberOfMotors,
                   &recorder,
                   sequence,
                   numberOfSequences,
                   capture,
                   numberOfCaptures,
                   compare,
                   numberOfCompares,
                   &eventMgr,
                   notify,
                   numberOfNotifys,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupMultiple(MPIControl      *control,
                    MPIMotion       *motion,
                    long             numberOfMotions,
                    MPIAxis         *axis,
                    long             numberOfAxes,
                    MPIFilter       *filter,
                    long             numberOfFilters,
                    MPIMotor        *motor,
                    long             numberOfMotors,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    long             numberOfSequences,
                    long             sequencePageSize,
                    MPICapture      *capture,
                    long             numberOfCaptures,
                    MPICompare      *compare,
                    long             numberOfCompares,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    long             numberOfNotifys,
                    Service         *service)
{
    long    index;
    long    returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification objects */
    for (index = 0; index < numberOfNotifys; index++) {
        returnValue =
            mpiNotifyDelete(notify[index]);
        msgCHECK(returnValue);
    }

    /* Delete compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        returnValue =
            mpiCompareDelete(compare[index]);
        msgCHECK(returnValue);
    }

    /* Delete capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        returnValue =
            mpiCaptureDelete(capture[index]);
        msgCHECK(returnValue);
    }

    /* Delete sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        returnValue =
            mpiSequenceDelete(sequence[index]);
        msgCHECK(returnValue);
    }

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        returnValue =
            mpiMotorDelete(motor[index]);
        msgCHECK(returnValue);
    }

    /* Delete filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        returnValue =
            mpiFilterDelete(filter[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion supervisor objects */
    for (index = 0; index < numberOfMotions; index++) {
        returnValue =
            mpiMotionDelete(motion[index]);
        msgCHECK(returnValue);
    }

    /* Delete axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        returnValue =
            mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Create and initialize MPI objects, and place MS's axis map on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitSingleWithMapping(MPIControl            *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    /* Map axis to motion supervisor on XMP */
    returnValue =
        mpiMotionAction(*motion,
                        MEIActionMAP);
    msgCHECK(returnValue);

    /* Create filter object */
    *filter =
        mpiFilterCreate(*control,
                        filterNumber);
    msgCHECK(mpiFilterValidate(*filter));

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

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Create and initialize MPI objects, and place MSs' axis maps on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitMultipleWithMapping(MPIControl          *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));

        /* Map axis to motion supervisor on XMP */
        returnValue =
            mpiMotionAction(motion[index],
                            MEIActionMAP);
        msgCHECK(returnValue);
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*
  Configure Home Limit to be triggered on the Home Input rather than the capture
*/
void homeLimitOnInput(MPIMotor  motor,
                      long      activeHigh)
{
    MEIMotorConfig   motorConfigXmp;    /* XMP motor I/O configuration */
    MEIXmpMotor     *motorXmp;          /* XMP motor memory */
    long             returnValue;       /* return value from library */

    /* Get pointer to Motor memory */
    returnValue =
        mpiMotorMemory(motor,
                       &motorXmp);

    /* Get the XMP Motor configuration*/
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Set the new Home Limit parameters */
    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].SourceAddress =
        &motorXmp->IO.DedicatedIN.IO;

    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].Mask =
        MEIXmpMotorIOMaskHOME;
    /* Set for Active High Home switch */
    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].LimitValue.l =
        (activeHigh) ? MEIXmpMotorIOMaskHOME : 0;

    /* Set the new XMP Motor configuration*/
    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);
}

/*
  enableUserLimit()  configures and enables one user limit.

  A user configured motor limit (user limit) normally uses one of the following
  limit types:

    MEIEventTypeLIMIT_USER0
    MEIEventTypeLIMIT_USER1
    MEIEventTypeLIMIT_USER2
    MEIEventTypeLIMIT_USER3
    MEIEventTypeLIMIT_USER4
    MEIEventTypeLIMIT_USER5
    MEIEventTypeLIMIT_USER6
    MEIEventTypeLIMIT_USER7

  but can also be one of the following types:

    MPIEventTypeAMP_FAULT
    MPIEventTypeHOME
    MPIEventTypeLIMIT_ERROR
    MPIEventTypeLIMIT_HW_NEG
    MPIEventTypeLIMIT_HW_POS
    MPIEventTypeLIMIT_SW_NEG
    MPIEventTypeLIMIT_SW_POS
    MPIEventTypeENCODER_FAULT

  Please read Application note 215 for a detailed discussion about user limits.

*/
void enableUserLimit(MPIMotor       motor,
                     long           enable)
{
    /* Configure user limit zero */
    MEIEventType     limit       = MEIEventTypeLIMIT_USER0;

    MEIXmpLimitData  customLimit;
    MEIXmpData      *firmware;      /* Needed to access general XMP addresses */
    MEIXmpMotor     *motorXmp;      /* Needed to access motor's addresses     */

    long             returnValue;

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &customLimit);
    msgCHECK(returnValue);

    if (enable) {

        /* Get pointer to XMP firmware */
        returnValue =
            mpiControlMemory(mpiMotorControl(motor),
                             &(void *)firmware,
                             NULL);
        msgCHECK(returnValue);

        /* Get pointer to motor's memory */
        returnValue =
            mpiMotorMemory(motor, &(void *)motorXmp);
        msgCHECK(returnValue);

        /* Set up limit condition 0 */
        customLimit.Condition[0].Type         = MEIXmpLimitTypeGE;
        customLimit.Condition[0].SourceAddress= &motorXmp->IO.DedicatedIN.IO;
        customLimit.Condition[0].Mask         = MEIMotorInputAMP_FAULT;
        customLimit.Condition[0].LimitValue.l = MEIMotorInputUSER;

        /* Set up limit condition 1 */
        customLimit.Condition[1].Type         = MEIXmpLimitTypeNE;
        customLimit.Condition[1].SourceAddress= &firmware->MS[0].Action;
        customLimit.Condition[1].Mask         = MEIMotorInputAMP_FAULT;
        customLimit.Condition[1].LimitValue.l = MEIMotorInputHOME;

        /* Set up limit output */
        customLimit.Output.OutputPtr = (void*)&firmware->Axis[0].ActualVelocity;
        customLimit.Output.Enabled   = TRUE;
        customLimit.Output.AndMask   = 0;
        customLimit.Output.OrMask    = 0;

        /* Set up limit logic */
        customLimit.Logic = MEIXmpLogicAND;

        /* Set up the XMP to handle the user limit */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);

    } else {
        /* Set default limit parameters */
        customLimit.Condition[0].Type = MEIXmpLimitTypeFALSE;
        customLimit.Condition[1].Type = MEIXmpLimitTypeFALSE;

        customLimit.Status = MEIXmpStatusLIMIT;
        customLimit.Logic  = MEIXmpLogicNEVER;

        customLimit.Output.AndMask = -1;    /* ALL BITS */
        customLimit.Output.OrMask  = 0;
        customLimit.Output.Enabled = FALSE;

        /* Reset the user limit on the XMP */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);
    }
}

/*
  disableUserLimit()  disables and erases the configuration of one user limit.
*/
void disableUserLimit(MPIMotor      motor,
                      MEIEventType  limit)
{
    MEIXmpLimitData userLimit;
    long            returnValue;

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);

    /* Set default limit parameters */
    userLimit.Condition[0].Type = MEIXmpLimitTypeFALSE;
    userLimit.Condition[1].Type = MEIXmpLimitTypeFALSE;

    userLimit.Status = MEIXmpStatusLIMIT;
    userLimit.Logic  = MEIXmpLogicNEVER;

    userLimit.Output.AndMask = -1;  /* ALL BITS */
    userLimit.Output.OrMask  = 0;
    userLimit.Output.Enabled = FALSE;

    /* Reset the user limit on the XMP */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               (MPIEventType)limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);
}

/*
  userLimitEnable()  enables or disables one user limit.

    This function does not change (most of) the configuration of a user limit.

    Because the function does change the logic to temporarily disable
    a user limit, this function must store the values of the limit's
    logic.
*/
void userLimitEnable(MPIMotor       motor,
                     MEIEventType   limit,
                     long           enable)
{
    static MEIXmpLogic  savedLogic[MEIXmpMAX_Motors][MEIEventTypeMOTOR_LAST];

    MEIXmpLimitData limitData;
    long            motorNumber;
    long            returnValue;

    /* Get the motor number */
    mpiMotorNumber(motor,
                   &motorNumber);

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);

    if (enable) {
        /* Restore logic */
        limitData.Logic = savedLogic[motorNumber][limit];
    }
    else {
        /* Save logic */
        savedLogic[motorNumber][limit] = limitData.Logic;

        /* Set logic to MEIXmpLogicNEVER to disable limit */
        limitData.Logic = MEIXmpLogicNEVER;
    }

    /* Set the new configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);
}

/*
   sequenceCommandAdd() creates a command (MPICommand object) and appends it to
   sequence's list of commands.  This function does return MPI error codes so
   that sequence setup code may be more easily debugged.

   Warning:  sequenceCommandAdd() does not keep track of created command objects
   so it is important that before a sequence object is deleted, that each
   command object on sequence's list is itself deleted.  Otherwise, there will
   be memory leaks.  One can use sequenceProgramDelete() to accomplish this.
*/
long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label)
{
    MPICommand  command;
    long        returnValue;

    command =
        mpiCommandCreate(commandType,
                         commandParams,
                         label);
    returnValue =
        mpiCommandValidate(command);

    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiSequenceCommandAppend(sequence,
                                     command);
    }

    return returnValue;
}

/*
   sequenceProgramCreate() is a prototype function showing how one can create a
   MPISequence program.  This prototype creates a program that simply loops
   continually, much like the statement:

    while(1) {}

   would in C.  This function uses sequenceCommandAdd() to add commands to
   sequence.  One should use sequenceProgramDelete() to delete the sequence
   object and the MPICommand objects on sequence's command list.  Please refer
   to the description of sequenceCommandAdd() for more details.
*/
MPISequence sequenceProgramCreate(MPIControl control)
{
    MPISequence         sequence;
    MPICommandParams    commandParams;
    long                returnValue;

    /* Create sequence object */
    sequence =
        mpiSequenceCreate(control,
                          -1,   /* Use the next available sequence */
                          1);   /* # of commands in sequence */
    msgCHECK(mpiSequenceValidate(sequence));

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Add command to sequence */
    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeBRANCH,
                           &commandParams,
                           "First");
    msgCHECK(returnValue);

    /* Return the new sequence handle */
    return sequence;
}

/*
   sequenceProgramDelete() removes and deletes all command objects on sequence's
   command list and then deletes sequence.  This function does return MPI error
   codes so that sequence setup code may be more easily debugged.
*/
long sequenceProgramDelete(MPISequence *sequence)
{
    MPICommand  command;
    long        returnValue = MPIMessageOK;

    /* Remove and delete command objects on sequence list */
    while(TRUE) {
        command = mpiSequenceCommandLast(*sequence);
        if ((returnValue != MPIMessageOK) ||
            (command==MPIHandleVOID)) {
            break;
        }
        returnValue =
            mpiSequenceCommandRemove(*sequence,
                                     command);

        if (returnValue == MPIMessageOK) {
            returnValue =
                mpiCommandDelete(command);
        }
    }

    /* Delete sequence object */
    returnValue =
        mpiSequenceDelete(*sequence);

    if (returnValue == MPIMessageOK) {
        /* Make it obvious that sequence is no longer a valid object */
        *sequence = MPIHandleVOID;
    }

    return returnValue;
}

/*
   Starts a sequence, waits for the user to press a key and then
   stops the sequence.
*/
void sequenceRun(MPISequence sequence)
{
    long returnValue;

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    fprintf(stderr,"Press any key to stop sequence.\n");
    meiPlatformKey(MPIWaitFOREVER);
    fprintf(stderr,"Exiting ...\n");

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    if ((returnValue != MPIMessageOK) &&
        (returnValue != MPISequenceMessageSTOPPED)) {
        msgCHECK(returnValue);
    }

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Start the XMP's recorder, get data, and stop the recorder

******************************************************************************/

long recordData(MPIRecorder         recorder,
                long                numRecords,
                long                period,
                long                eventCount,
                MPIRecorderRecord  *records)
 {
    long returnValue;
    long recordIndex;
    long recordCountRemaining;
    long countGet;

    /* Start recording the axis */
    returnValue =
        mpiRecorderStart(recorder,
                         numRecords,
                         period,    /* period (milliseconds) */
                         eventCount);
    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);

    return returnValue;
}

/*****************************************************************************

   Example:
    Configure recorder object

   This example records 3 system data variables:
    1) The sample counter -- increments by 1 every servo cycle
    2) The background cycle -- increments by 1 after every background cycle
    3) The "count delta" -- increments by 1 after every background cycle and
            resets to zero after every servo cycle

******************************************************************************/

void configureRecorder(MPIRecorder recorder)
{
    MPIControl          control = mpiRecorderControl(recorder);
    MEIXmpData*         firmware;
    MEIXmpBufferData*   external;

    void    *point[MEIXmpMaxRecSize];

    long    pointCount = 0;
    long    returnValue;

    returnValue =
        mpiControlMemory(control,
                         &firmware,
                         &external);
    msgCHECK(returnValue);

    point[pointCount++] = &firmware->SystemData.SampleCounter;
    point[pointCount++] = &firmware->SystemData.BackgroundCycle;
    point[pointCount++] = &firmware->SystemData.CountDelta;

    meiASSERT(pointCount <= MEIXmpMaxRecSize);

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                MPIRecorderRecordTypePOINT,
                                pointCount,
                                point);
    msgCHECK(returnValue);
}

/*****************************************************************************

   Stops the data recorder ignoring the MPIRecorderMessageSTOPPED message if
    the recorder is already stopped.

******************************************************************************/

void stopRecorder(MPIRecorder recorder)
{
    long returnValue =
        mpiRecorderStop(recorder);

    /* In case the recorder has already stopped */
    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);
}


appslibGood.c --
/**********************************************************************

    A collection of various potentially useful functions. Nothing in here
    approaches supported status.

    Feel free to add, but not remove functions from this file. We only ask
    that you add some comments above each function and add the name and
    one line (or so) description to the following list to make it easy
    for others to use this file.

    After adding something to this file, PLEASE compile a program with it
    to make sure it isn't broke! Make sure to add appropriate #includes.

**********************************************************************/

/***********************************************************************

Listing of functions in this file:

* trapMove()            Commands a simple trap move. It checks for an
                        appropriate state first and returns error codes, if
                        appropriate.

* sCurveMove()      Commands a simple S Curve move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* ptMove()          Commands a pt move. Can be used to make appended lists.

* pvtMove()         Commands a pvt move. Can be used to make appended lists.

* velMove()         Commands a simple vel move. It checks for an appropriate
                    state first and returns error codes, if appropriate.

* isMotionDone()     returns a 1 if the motion is idle, a 0 if it is not.

* waitForMotionDone()   Stalls the program in a 10 msec polling loop until it
                        gets an MPIMotionIDLE

* clearError()          clears all the errors on an MS and enables the amps on that MS.

* motionAxisLoop()      For every axis attached to a motion supervisor (perform some action) [EXAMPLE]

* axisMotorLoop()       For every motor attached to an axis (perform some action) [EXAMPLE]

* motionMotorLoop()     For every motor attached to a motion supervisor (perform some action) [EXAMPLE]

* axisAmpEnable()       Enable the amplifier for every motor attached to an axis

* axisAmpDisable()      Disable the amplifier for every motor attached to an axis

* motionAmpEnable()     Enable the amplifier for every motor attached to a motion supervisor

* motionAmpDisable()    Disable the amplifier for every motor attached to a motion supervisor

* setIp()           configures the program to use a controller at address "server"

* parseCommandLine()    Parsing for apps that need command line arguments (example)

* basicParsing()    Perform basic command line parsing. (-control -server -port -trace)

* programInit() / programCleanup():
    A bare minimum object creation / deletion for programs of the scope of
    motion1 or so.

* programInitSingle()       Create and initialize MPI objects.
                                [One of each object -- Use as a model]

* programCleanupSingle()    Perform certain cleanup actions and delete MPI objects
                                [One of each object -- Use as a model]

* programInitMultiple()     Create and initialize MPI objects.
                                [Arrays of some objects -- Use as a model]

* programCleanupMultiple()  Perform certain cleanup actions and delete MPI objects
                                [Arrays of some objects -- Use as a model]

* programInitSingleWithMapping()    Create and initialize MPI objects, and place MS's axis map on XMP
                                        [One of each object -- Use as a model]

* programInitMultipleWithMapping()  Create and initialize MPI objects, and place MSs' axis maps on XMP
                                        [Arrays of some objects -- Use as a model]

* homeLimitOnInput()    Configure Home Limit to be triggered on the Home Input rather than the capture

* enableUserLimit()     Configures and enables one user limit

* disableUserLimit()    Disables and erases the configuration of one user limit

* userLimitEnable()     Enables or disables one user limit
                            This function does not change (most of) the configuration of a user limit.

* sequenceCommandAdd() Creates a command (MPICommand object) and appends it to
                        sequence's list of commands.

* sequenceProgramCreate()    Shows how one can create a MPISequence program.

* sequenceProgramDelete(MPISequence *sequence)  Removes and deletes all command objects on sequence's
                                                   command list and then deletes sequence.

* sequenceRun()     Starts a sequence, waits for the user to press a key and then
                       stops the sequence.

* recordData()      Start the XMP's recorder, get data, and stop the recorder

* configureRecorder()   Example of how to configure the data recorder object

* stopRecorder()    Stops the data recorder ignoring the MPIRecorderMessageSTOPPED
                        message if the recorder is already stopped.

            ** add yours here **

***********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>

#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"

long    trapMove(MPIMotion      *motion,
                MPITrajectory   *trajectory,
                double          *position);

long    sCurveMove(MPIMotion        *motion,
                    MPITrajectory   *trajectory,
                    double          *position);

long    ptMove(MPIMotion    motion,
               double       point[],
               double       time[],
               long         numPoints,
               long         final);

long    pvtMove(MPIMotion   motion,
                double      point[],
                double      velocity[],
                double      time[],
                long        numPoints,
                long        final);

long    velMove(MPIMotion       *motion,
                MPITrajectory   *trajectory);

long    isMotionDone(MPIMotion      motion);

void    waitForMotionDone(MPIMotion     motion);

long    clearError(MPIMotion    motion);

void    motionAxisLoop(MPIMotion    motion);

void    axisMotorLoop(MPIAxis   axis);

void    motionMotorLoop(MPIMotion   motion);

void    axisAmpEnable(MPIAxis   axis);

void    axisAmpDisable(MPIAxis  axis);

void    motionAmpEnable(MPIMotion   motion);

void    motionAmpDisable(MPIMotion  motion);

void    setIp(MPIControlType    *controlType,
              MPIControlAddress *controlAddress,
              char              *server);

long    parseCommandLine(long               *motorNumber,
                         int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress);

void    basicParsing(int                     argc,
                    char                    *argv[],
                    MPIControlType          *controlType,
                    MPIControlAddress       *controlAddress);

long    programInit(long                motorNumber,
                    MPIControl          *control,
                    MPIMotor            *motor,
                    MPIAxis             *axis,
                    MPIMotion           *motion,
                    MPIControlType      *controlType,
                    MPIControlAddress   *controlAddress);

long    programCleanup(MPIMotion        *motion,
                       MPIAxis          *axis,
                       MPIMotor         *motor,
                       MPIControl       *control);

void    programInitSingle(MPIControl            *control,
                         MPIControlType      controlType,
                         MPIControlAddress  *controlAddress,
                         MPIMotion          *motion,
                         long                motionNumber,
                         MPIAxis            *axis,
                         long                axisNumber,
                         MPIFilter          *filter,
                         long                filterNumber,
                         MPIMotor           *motor,
                         long                motorNumber,
                         MPIRecorder        *recorder,
                         MPISequence        *sequence,
                         long                sequenceNumber,
                         MPICapture         *capture,
                         long                captureNumber,
                         MPICompare         *compare,
                         long                compareNumber,
                         MPIEventMgr        *eventMgr,
                         MPINotify          *notify,
                         Service            *service);

void    programCleanupSingle(MPIControl         *control,
                             MPIMotion          *motion,
                             MPIAxis            *axis,
                             MPIFilter          *filter,
                             MPIMotor           *motor,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             MPICapture         *capture,
                             MPICompare         *compare,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             Service            *service);

void    programInitMultiple(MPIControl          *control,
                             MPIControlType      controlType,
                             MPIControlAddress  *controlAddress,
                             MPIMotion          *motion,
                             long                numberOfMotions,
                             long               *motionNumber,
                             MPIAxis            *axis,
                             long                numberOfAxes,
                             long               *axisNumber,
                             MPIFilter          *filter,
                             long                numberOfFilters,
                             long               *filterNumber,
                             MPIMotor           *motor,
                             long                numberOfMotors,
                             long               *motorNumber,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             long                numberOfSequences,
                             long                sequencePageSize,
                             long               *sequenceNumber,
                             MPICapture         *capture,
                             long                numberOfCaptures,
                             long               *captureNumber,
                             MPICompare         *compare,
                             long                numberOfCompares,
                             long               *compareNumber,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             long                numberOfNotifys,
                             Service            *service);

void    programCleanupMultiple(MPIControl           *control,
                             MPIMotion          *motion,
                             long                numberOfMotions,
                             MPIAxis            *axis,
                             long                numberOfAxes,
                             MPIFilter          *filter,
                             long                numberOfFilters,
                             MPIMotor           *motor,
                             long                numberOfMotors,
                             MPIRecorder        *recorder,
                             MPISequence        *sequence,
                             long                numberOfSequences,
                             long                sequencePageSize,
                             MPICapture         *capture,
                             long                numberOfCaptures,
                             MPICompare         *compare,
                             long                numberOfCompares,
                             MPIEventMgr        *eventMgr,
                             MPINotify          *notify,
                             long                numberOfNotifys,
                             Service            *service);

void    programInitSingleWithMapping(MPIControl         *control,
                                     MPIControlType      controlType,
                                     MPIControlAddress  *controlAddress,
                                     MPIMotion          *motion,
                                     long                motionNumber,
                                     MPIAxis            *axis,
                                     long                axisNumber,
                                     MPIFilter          *filter,
                                     long                filterNumber,
                                     MPIMotor           *motor,
                                     long                motorNumber,
                                     MPIRecorder        *recorder,
                                     MPISequence        *sequence,
                                     long                sequenceNumber,
                                     MPICapture         *capture,
                                     long                captureNumber,
                                     MPICompare         *compare,
                                     long                compareNumber,
                                     MPIEventMgr        *eventMgr,
                                     MPINotify          *notify,
                                     Service            *service);

void    programInitMultipleWithMapping(MPIControl           *control,
                                     MPIControlType      controlType,
                                     MPIControlAddress  *controlAddress,
                                     MPIMotion          *motion,
                                     long                numberOfMotions,
                                     long               *motionNumber,
                                     MPIAxis            *axis,
                                     long                numberOfAxes,
                                     long               *axisNumber,
                                     MPIFilter          *filter,
                                     long                numberOfFilters,
                                     long               *filterNumber,
                                     MPIMotor           *motor,
                                     long                numberOfMotors,
                                     long               *motorNumber,
                                     MPIRecorder        *recorder,
                                     MPISequence        *sequence,
                                     long                numberOfSequences,
                                     long                sequencePageSize,
                                     long               *sequenceNumber,
                                             MPICapture         *capture,
                                     long                numberOfCaptures,
                                     long               *captureNumber,
                                     MPICompare         *compare,
                                     long                numberOfCompares,
                                     long               *compareNumber,
                                     MPIEventMgr        *eventMgr,
                                     MPINotify          *notify,
                                     long                numberOfNotifys,
                                     Service            *service);

void homeLimitOnInput(MPIMotor  motor,
                      long      activeHigh);

void enableUserLimit(MPIMotor       motor,
                     long           enable);

void disableUserLimit(MPIMotor      motor,
                      MEIEventType  limit);

void userLimitEnable(MPIMotor       motor,
                     MEIEventType   limit,
                     long           enable);

long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label);

MPISequence sequenceProgramCreate(MPIControl control);

long sequenceProgramDelete(MPISequence *sequence);

void sequenceRun(MPISequence sequence);

long    recordData(MPIRecorder           recorder,
                   long                  numRecords,
                   long                  period,
                   long                  eventCount,
                   MPIRecorderRecord    *records);

void configureRecorder(MPIRecorder recorder);

void stopRecorder(MPIRecorder recorder);

/*******************************************************

    trapMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory and    position information. It checks for an idle
    state before it commands the move. If it gets something an idle state, it
    commands a motionStart, if it gets a moving state, it commands a
    motionModify. If it gets something else, no move is commanded and an error
    code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE,MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long    trapMove(MPIMotion      *motion,
                MPITrajectory   *trajectory,
                double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.trapezoidal.trajectory   = trajectory;
    params.trapezoidal.position     = position;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeTRAPEZOIDAL,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeTRAPEZOIDAL | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/*******************************************************

    sCurveMove commands a simple trap move to the specified motion supervisor
    with the specified trajectory and position information. It checks for an
    idle state before it commands the move. If it gets something an idle state,
    it commands a motionStart, if it gets a moving state, it commands a
    motionModify.  If it gets something else, no move is commanded and an error
    code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long     sCurveMove(MPIMotion       *motion,
                    MPITrajectory   *trajectory,
                    double          *position)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.sCurve.trajectory    = trajectory;
    params.sCurve.position      = position;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeS_CURVE,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeS_CURVE | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != (MPIMotionMessageAUTO_START || MPIMotionMessageIDLE))msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/******************************************************************************

    ptMove commands a PT move

******************************************************************************/

long    ptMove(MPIMotion    motion,
               double       point[],
               double       time[],
               long         numPoints,
               long         final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pt.pointCount = numPoints;   /* Number of time points */
    params.pt.position = point;     /* Position array */
    params.pt.time = time;          /* Time array */
    params.pt.point.retain = 0;     /* Flush frame buffer after execution */
    params.pt.point.final = final;      /* Last point */
    params.pt.point.emptyCount = 5; /* Start E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}

/******************************************************************************

    pvtMove commands a PVT move

******************************************************************************/

long    pvtMove(MPIMotion   motion,
                double      point[],
                double      velocity[],
                double      time[],
                long        numPoints,
                long        final)

{
    MPIMotionParams     params;         /* Motion parameters */

    long    returnValue = MPIMessageOK;

    /* Initialize motion params structure */
    params.pvt.pointCount = numPoints;  /* Number of time points */
    params.pvt.position = point;        /* Position array */
    params.pvt.velocity = velocity;
    params.pvt.time = time;         /* Time array */
    params.pvt.point.retain = 0;        /* Flush frame buffer after execution */
    params.pvt.point.final = final;     /* Last point */
    params.pvt.point.emptyCount = 5;    /* E-Stop if frames left to execute */
                                    /* is less than this limit. -1 disables  */

    if(!isMotionDone(motion))
    {
        returnValue =
            mpiMotionModify(motion,
                           (MPIMotionTypePVT | MPIMotionAttrMaskAPPEND),
                           &params);
        msgCHECK(returnValue);
        printf("\nappend\n");
    }

    else{
        /* Start motion */
        returnValue =
            mpiMotionStart(motion,
                           (MPIMotionTypePVT),
                           &params);
        msgCHECK(returnValue);
    }

    return returnValue;
}

/*******************************************************

    velMove commands a simple trap move to the specified motion supervisor with
    the specified trajectory    information. It checks for an idle state before
    it commands the move. If it gets something an idle state, it commands a
    motionStart, if it gets a moving state, it commands a motionModify.  If it
    gets something else, no move is commanded and an error code is returned.

    Error code      description

    0               No Error (MPIStateMoving, MPIStateIDLE, MPIStateSTOPPING)
    1               MPIStateERROR
    2               None of the above

*******************************************************/

long    velMove(MPIMotion       *motion,
                MPITrajectory   *trajectory)
{
    MPIMotionParams     params;         /* Motion parameters */
    MPIStatus           status;         /* Status handle */

    long returnValue = MPIMessageOK;

    params.velocity.trajectory  = trajectory;

    returnValue =
        mpiMotionStatus(*motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    switch (status.state)   /* Check state and take the appropriate action */
    {
        case MPIStateIDLE:  /* IDLE is OK, start a move. */
        {
            /* Start motion */
            returnValue =
                mpiMotionStart(*motion,
                               MPIMotionTypeVELOCITY,
                               &params);
            msgCHECK(returnValue);

            break;
        }

        case MPIStateSTOPPING:  /* STOPPING is OK, modify a move. */
        {
            /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateMOVING:    /* MOVING is OK, modify a move. */
        {
                /* Modify the executing motion profile */
            returnValue =
                mpiMotionModify(*motion,
                                MPIMotionTypeVELOCITY | MPIMotionAttrMaskAUTO_START,
                                &params);
            if(returnValue != MPIMotionMessageAUTO_START)msgCHECK(returnValue);

            break;
        }

        case MPIStateERROR: /* ERROR is not OK. */
        {
            returnValue = MPIMotionMessageERROR;

            break;
        }

        default:    /* Don't know what happened. */
        {
            returnValue = MPIMessageFATAL_ERROR;
            break;
        }
    }

    return returnValue;
}

/*********************************************************************

    isMotionDone() returns a 1 if the motion is idle, a 0 if it is not.

**********************************************************************/

long    isMotionDone(MPIMotion      motion)
{
    MPIStatus   status;

    long    returnValue = FALSE;

    returnValue =
    mpiMotionStatus(motion,
                    &status,
                    NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateIDLE)
    {
        returnValue = TRUE;
    }

    return returnValue;
}

/*********************************************************************

 waitForMotionDone() polls motion to see if the axis is in an idle or error
 state every 10ms. When it gets an MPIStateIdle, MPIStateERROR, or
 MPIStateSTOPPING_ERROR then the waitForMotionDone() exits.

**********************************************************************/
void waitForMotionDone(MPIMotion motion)
{
    MPIStatus   status;
    long        motionDone;
    long        returnValue = MPIMessageOK;

    /* Poll status until motion done */
    motionDone = FALSE;
    while (motionDone == FALSE) {

        /* Get the motion supervisor status */
        returnValue =
            mpiMotionStatus(motion,
                            &status,
                            NULL);
        msgCHECK(returnValue);

        switch (status.state) {
            case MPIStateSTOPPING:
            case MPIStateMOVING: {
                /* Sleep for 10ms and give up control to other threads */
                meiPlatformSleep(10);
                break;
            }
            case MPIStateIDLE:
            case MPIStateERROR:
            case MPIStateSTOPPING_ERROR: {
                /* Motion is done */
                motionDone = TRUE;
                break;
            }
            default: {
                /* Unknown State */
                fprintf(stderr, "Unknown state from mpiMotionStatus.\n");
                msgCHECK(MPIMessageFATAL_ERROR);
                break;
            }
        }
    }
}

/******************************************************************************

 clearError() clears all the errors on an MS and enables the amps on that MS.
 It does this by commanding a mpiMotionAction(reset) and then waits a couple
 smaples, tries again if it needs to, then waits a couple samples and makes
 sure it happened, returning an error if it didn't, and enables all the amps on
 the MS using motionAmpEnable().

******************************************************************************/

long    clearError(MPIMotion motion)
{
    MPIStatus           status;         /* Status handle */

    long returnValue;

    returnValue = mpiMotionAction(motion, MPIActionRESET);
    msgCHECK(returnValue);

    meiControlSampleWait(mpiMotionControl(motion), 2);

    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateERROR)
    {
        returnValue = mpiMotionAction(motion, MPIActionRESET);
        msgCHECK(returnValue);
    }

    meiControlSampleWait(mpiMotionControl(motion), 2);

    returnValue =
        mpiMotionStatus(motion,
                        &status,
                        NULL);
    msgCHECK(returnValue);

    if(status.state == MPIStateERROR)
    {
        returnValue = MPIMotionMessageERROR;
    }

    motionAmpEnable(motion);

    return returnValue;
}

/*****************************************************************************

  For every axis attached to a motion supervisor (perform some action)

  This is a model for any MPI Object that has other MPI objects attached to
   it via a linked list. (i.e. there exists mpiXxxYyyFirst(...) and
   mpiXxxYyyNext(...) functions.)

******************************************************************************/

/* For every axis attached to a motion supervisor ... */
void motionAxisLoop(MPIMotion   motion)
{
    MPIAxis axis;

    /* For every axis attached to a motion ... */
    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Place your code here */
    }
}

/*****************************************************************************

  For every motor attached to an axis (perform some action).  This is useful
   when motor objects haven't been created or when someone is using gantry code.

  This is a model for any MPI Object that has other MPI objects attached to
   it via object maps.  (i.e. there exits an mpiXxxYyyMap(...) function.)

******************************************************************************/

/* For every motor attached to an axis ... */
void axisMotorLoop(MPIAxis  axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(map, motorIndex)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  For every motor attached to a motion supervisor (perform some action)

  This is a model for any MPI Object (Father) that has other MPI objects
   (Children) attached to it indirectly in the following way:

    MPIFather --(linked list)--> MPIIntermediate --(object map)-> MPIChild

******************************************************************************/

/* For every motor attached to a motion supervisor ... */
void motionMotorLoop(MPIMotion  motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Place your code here */

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Enable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.
   This code also sets the command position equal to the actual position and
   resets the integrator before enabling the amplifiers so that the motors will
   not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to an axis */
void axisAmpEnable(MPIAxis  axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    axisMotorMap;
    MPIObjectMap    motorFilterMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &axisMotorMap);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(axisMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* Get the actual position of the axis */
                returnValue = mpiAxisActualPositionGet(axis, &position);
                msgCHECK(returnValue);

                /* Set the command position equal to the actual position */
                returnValue = mpiAxisCommandPositionSet(axis, position);
                msgCHECK(returnValue);

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &motorFilterMap);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MEIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(motorFilterMap, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Disable the amplifier for every motor attached to an axis.  This is useful
   when motor objects haven't been created or when someone is using gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to an axis */
void axisAmpDisable(MPIAxis axis)
{
    MPIControl      control;
    MPIMotor        motor;
    MPIObjectMap    map;
    long            motorNumber;
    long            returnValue;

    /* Get the controller handle */
    control = mpiAxisControl(axis);

    /* Get the object map for the motors */
    returnValue = mpiAxisMotorMapGet(axis, &map);
    msgCHECK(returnValue);

    /* For every motor ... */
    for (motorNumber = 0; motorNumber < MEIXmpMAX_Motors; motorNumber++) {

        if (map & (1<<motorNumber)) {
            /* Create motor handle */
            motor = mpiMotorCreate(control, motorNumber);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Enable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using
   gantry code.  This code also sets the command position equal to the actual
   position and resets the integrator before enabling the amplifiers so that
   the motors will not "jump."

******************************************************************************/

/* Enable the amplifier for every motor attached to a motion supervisor */
void motionAmpEnable(MPIMotion  motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIFilter       filter;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            filterIndex;
    long            returnValue;
    double          position;
    long            enableState;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Get the state of the amplifier */
            returnValue = mpiMotorAmpEnableGet(motor, &enableState);
            msgCHECK(returnValue);

            /* If the amplifier is disabled ... */
            if (enableState == FALSE) {

                /* For every axis */
                for (axis =  mpiMotionAxisFirst(motion);
                     axis != MPIHandleVOID;
                     axis =  mpiMotionAxisNext(motion, axis)) {

                    /* Get the object map for the motors */
                    returnValue = mpiAxisMotorMapGet(axis, &map);
                    msgCHECK(returnValue);

                    /* If axis is attached to motor ... */
                    if (mpiObjectMapBitGET(map, motorIndex)) {

                        /* Get the actual position of the axis */
                        returnValue = mpiAxisActualPositionGet(axis, &position);
                        msgCHECK(returnValue);

                        /* Set command position equal to actual position */
                        returnValue = mpiAxisCommandPositionSet(axis, position);
                        msgCHECK(returnValue);
                    }
                }

                /* Get the object map for the filters */
                returnValue = mpiMotorFilterMapGet(motor, &map);
                msgCHECK(returnValue);

                /* For every filter ... */
                for (filterIndex = 0;
                     filterIndex < MEIXmpMAX_Filters;
                     filterIndex++) {

                    if (mpiObjectMapBitGET(map, filterIndex)) {

                        /* Create filter handle */
                        filter = mpiFilterCreate(control, filterIndex);
                        msgCHECK(mpiFilterValidate(filter));

                        /* Reset integrator */
                        returnValue = mpiFilterIntegratorReset(filter);
                        msgCHECK(returnValue);

                        /* Delete filter handle */
                        returnValue = mpiFilterDelete(filter);
                        msgCHECK(returnValue);
                    }
                }

                /* Enable the amplifier */
                returnValue = mpiMotorAmpEnableSet(motor, TRUE);
                msgCHECK(returnValue);
            }

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

  Disable the amplifier for every motor attached to a motion supervisor.  This
   is useful when motor objects haven't been created or when someone is using
   gantry code.

******************************************************************************/

/* Disable the amplifier for every motor attached to a motion supervisor */
void motionAmpDisable(MPIMotion motion)
{
    MPIControl      control;
    MPIAxis         axis;
    MPIMotor        motor;
    MPIObjectMap    map;
    MPIObjectMap    motionMotorMap;
    long            motorIndex;
    long            returnValue;

    /* Get the controller handle */
    control = mpiMotionControl(motion);

    for (axis =  mpiMotionAxisFirst(motion);
         axis != MPIHandleVOID;
         axis =  mpiMotionAxisNext(motion, axis)) {

        /* Get the object map for the motors */
        returnValue = mpiAxisMotorMapGet(axis, &map);
        msgCHECK(returnValue);

        /* Add map to motionMotorMap */
        motionMotorMap |= map;
    }

    /* For every motor ... */
    for (motorIndex = 0; motorIndex < MEIXmpMAX_Motors; motorIndex++) {

        if (mpiObjectMapBitGET(motionMotorMap, motorIndex)) {

            /* Create motor handle */
            motor = mpiMotorCreate(control, motorIndex);
            msgCHECK(mpiMotorValidate(motor));

            /* Disable the amplifier */
            returnValue = mpiMotorAmpEnableSet(motor, FALSE);
            msgCHECK(returnValue);

            /* Delete motor handle */
            returnValue = mpiMotorDelete(motor);
            msgCHECK(returnValue);
        }
    }
}

/*****************************************************************************

    Sets controller to Network mode.  Server is the name of the computer in
    quotes.     Use IP or computer name.

******************************************************************************/

void setIp(MPIControlType       *controlType,
           MPIControlAddress    *controlAddress,
           char                 *server)
{
    controlAddress->type.client.port = 3300;
    controlAddress->type.client.server = server;
    *controlType = MPIControlTypeCLIENT;
}

/**********************************************

    Parsing for apps that need command line arguments (example)

    In this example, you would pass in the default motor number you
    want to use.  parseCommandLine() would then change the motor number
    if the user specified (s)he wanted to use a different motor.

**********************************************/

long    parseCommandLine(long               *motorNumber,
                         int                argc,
                         char               *argv[],
                         MPIControlType     *controlType,
                         MPIControlAddress  *controlAddress)
{
    long    argIndex;

    /* Command line arguments and defaults */
    Arg argList[] =
    {
        {   "-motor",   ArgTypeLONG,    motorNumber,    },
        {   NULL,       ArgTypeINVALID, NULL,   }
    };

    /* Parse command line for Control type and address */
    argIndex =
        argControl(argc,
                   argv,
                   controlType,
                   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) {
        fprintf(stderr,"usage: %s %s\n"
                           "\t\t[-motor # (0 .. %d)]\n"
                            argv[0],
                            ArgUSAGE,
                            MEIXmpMAX_Motors);
        exit(MPIMessageARG_INVALID);
    }

    return 0;
}

/*****************************************************************************

  Perform basic command line parsing. (-control -server -port -trace)

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

******************************************************************************/

/* 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);
    }
}

/************************************************************

  Example of a typical program initialization function:
    A bare minimum object creation for programs of the scope of
    motion1 or so. Designed to work with programCleanup below.

  #define at head of program file:

#define MOTOR_NUMBER    (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                MOTOR_NUMBER,
                &motion,
                &axis,
                &motor);

************************************************************/

long    programInit(MPIControl          *control,
                    MPIControlType      *controlType,
                    MPIControlAddress   *controlAddress,
                    long                motorNumber,
                    MPIMotion           *motion,
                    MPIAxis             *axis,
                    MPIMotor            *motor)
{
    long returnValue;

    /* Obtain a Control handle. */
    *control =
        mpiControlCreate(*controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

    /* Initialize the controller */
    returnValue = mpiControlInit(*control);
    if (returnValue != MPIMessageOK) {
        fprintf(stderr, "mpiControlInit(0x%x) returns 0x%x: %s\n",
                        *control,
                        returnValue,
                        mpiMessage(returnValue, NULL));

        exit(returnValue);
    }

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

    /* Create axis object */
    *axis =
        mpiAxisCreate(*control,
                      motorNumber);
    msgCHECK(mpiAxisValidate(*axis));

    /* Create motion object */
    *motion =
        mpiMotionCreate(*control,
                        motorNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    return  returnValue;

}

/*********************************************************

  Example of a typical program cleanup function:
    A bare minimum object deletion for programs of the scope of
    motion1 or so. Designed to work with programInit above.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   &motion,
                   &axis,
                   &motor);

*********************************************************/

long    programCleanup(MPIControl       *control,
                       MPIMotion        *motion,
                       MPIAxis          *axis,
                       MPIMotor         *motor)
{
    long returnValue;

    /* Delete the remaining handles */
    returnValue = mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    returnValue = mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    returnValue = mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    returnValue = mpiControlDelete(*control);
    msgCHECK(returnValue);

    return returnValue;
}

/*****************************************************************************

  Create and initialize MPI objects.  [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitSingle(MPIControl           *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    /* Create filter object */
    *filter =
        mpiFilterCreate(*control,
                        filterNumber);
    msgCHECK(mpiFilterValidate(*filter));

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

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [One of each object -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   &motion,
                   &axis,
                   &filter,
                   &motor,
                   &recorder,
                   &sequence,
                   &capture,
                   &compare,
                   &eventMgr,
                   &notify,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupSingle(MPIControl        *control,
                    MPIMotion       *motion,
                    MPIAxis         *axis,
                    MPIFilter       *filter,
                    MPIMotor        *motor,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    MPICapture      *capture,
                    MPICompare      *compare,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    Service         *service)
{
    long    returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification object */
    returnValue =
        mpiNotifyDelete(*notify);
    msgCHECK(returnValue);

    /* Delete compare object */
    returnValue =
        mpiCompareDelete(*compare);
    msgCHECK(returnValue);

    /* Delete capture object */
    returnValue =
        mpiCaptureDelete(*capture);
    msgCHECK(returnValue);

    /* Delete sequencer object */
    returnValue =
        mpiSequenceDelete(*sequence);
    msgCHECK(returnValue);

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor object */
    returnValue =
        mpiMotorDelete(*motor);
    msgCHECK(returnValue);

    /* Delete filter object */
    returnValue =
        mpiFilterDelete(*filter);
    msgCHECK(returnValue);

    /* Delete motion supervisor object */
    returnValue =
        mpiMotionDelete(*motion);
    msgCHECK(returnValue);

    /* Delete axis object */
    returnValue =
        mpiAxisDelete(*axis);
    msgCHECK(returnValue);

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Create and initialize MPI objects.  [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitMultiple(MPIControl         *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Perform certain cleanup actions and delete MPI objects
        [Arrays of some objects -- Use as a model]

  Note: Rename function to programCleanup(...) and delete what you don't need.

  Call function as:

    /* Perform certain cleanup actions and delete MPI objects *
    programCleanup(&control,
                   motion,
                   numberOfMotions,
                   axis,
                   numberOfAxes,
                   filter,
                   numberOfFilters,
                   motor,
                   numberOfMotors,
                   &recorder,
                   sequence,
                   numberOfSequences,
                   capture,
                   numberOfCaptures,
                   compare,
                   numberOfCompares,
                   &eventMgr,
                   notify,
                   numberOfNotifys,
                   &service);

******************************************************************************/

/* Perform certain cleanup actions and delete MPI objects */
void programCleanupMultiple(MPIControl      *control,
                    MPIMotion       *motion,
                    long             numberOfMotions,
                    MPIAxis         *axis,
                    long             numberOfAxes,
                    MPIFilter       *filter,
                    long             numberOfFilters,
                    MPIMotor        *motor,
                    long             numberOfMotors,
                    MPIRecorder     *recorder,
                    MPISequence     *sequence,
                    long             numberOfSequences,
                    long             sequencePageSize,
                    MPICapture      *capture,
                    long             numberOfCaptures,
                    MPICompare      *compare,
                    long             numberOfCompares,
                    MPIEventMgr     *eventMgr,
                    MPINotify       *notify,
                    long             numberOfNotifys,
                    Service         *service)
{
    long    index;
    long    returnValue;

    /* Delete service thread */
    returnValue =
        serviceDelete(*service);
    msgCHECK(returnValue);

    /* Delete event manager object */
    returnValue =
        mpiEventMgrDelete(*eventMgr);
    msgCHECK(returnValue);

    /* Delete event notification objects */
    for (index = 0; index < numberOfNotifys; index++) {
        returnValue =
            mpiNotifyDelete(notify[index]);
        msgCHECK(returnValue);
    }

    /* Delete compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        returnValue =
            mpiCompareDelete(compare[index]);
        msgCHECK(returnValue);
    }

    /* Delete capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        returnValue =
            mpiCaptureDelete(capture[index]);
        msgCHECK(returnValue);
    }

    /* Delete sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        returnValue =
            mpiSequenceDelete(sequence[index]);
        msgCHECK(returnValue);
    }

    /* Delete recorder object */
    returnValue =
        mpiRecorderDelete(*recorder);
    msgCHECK(returnValue);

    /* Delete motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        returnValue =
            mpiMotorDelete(motor[index]);
        msgCHECK(returnValue);
    }

    /* Delete filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        returnValue =
            mpiFilterDelete(filter[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion supervisor objects */
    for (index = 0; index < numberOfMotions; index++) {
        returnValue =
            mpiMotionDelete(motion[index]);
        msgCHECK(returnValue);
    }

    /* Delete axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        returnValue =
            mpiAxisDelete(axis[index]);
        msgCHECK(returnValue);
    }

    /* Delete motion controller object */
    returnValue =
        mpiControlDelete(*control);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Create and initialize MPI objects, and place MS's axis map on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [One of each object -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  #define at head of program file:

#define MOTION_NUMBER   (0)
#define AXIS_NUMBER     (0)
#define FILTER_NUMBER   (0)
#define MOTOR_NUMBER    (0)
#define SEQUENCE_NUMBER (0)
#define CAPTURE_NUMBER  (0)
#define COMPARE_NUMBER  (0)

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion;
    MPIAxis             axis;
    MPIFilter           filter;
    MPIMotor            motor;
    MPISequence         sequence;
    MPICapture          capture;
    MPICompare          compare;
    MPINotify           notify;
    MPIEventMgr         eventMgr;

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                &motion,
                MOTION_NUMBER,
                &axis,
                AXIS_NUMBER,
                &filter,
                FILTER_NUMBER,
                &motor,
                MOTOR_NUMBER,
                &recorder,
                &sequence,
                SEQUENCE_NUMBER,
                &capture,
                CAPTURE_NUMBER,
                &compare,
                COMPARE_NUMBER,
                &eventMgr,
                &notify,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitSingleWithMapping(MPIControl            *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                motionNumber,
                 MPIAxis            *axis,
                 long                axisNumber,
                 MPIFilter          *filter,
                 long                filterNumber,
                 MPIMotor           *motor,
                 long                motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                sequenceNumber,
                 MPICapture         *capture,
                 long                captureNumber,
                 MPICompare         *compare,
                 long                compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

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

    /* Create motion supervisor object with axis */
    *motion =
        mpiMotionCreate(*control,
                        motionNumber,
                        *axis);
    msgCHECK(mpiMotionValidate(*motion));

    /* Map axis to motion supervisor on XMP */
    returnValue =
        mpiMotionAction(*motion,
                        MEIActionMAP);
    msgCHECK(returnValue);

    /* Create filter object */
    *filter =
        mpiFilterCreate(*control,
                        filterNumber);
    msgCHECK(mpiFilterValidate(*filter));

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

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer object */
    *sequence =
        mpiSequenceCreate(*control,
                          sequenceNumber,
                          -1);  /* Allocate all remaining sequencer space */
    msgCHECK(mpiSequenceValidate(*sequence));

    /* Create capture object */
    *capture =
        mpiCaptureCreate(*control,
                         captureNumber);
    msgCHECK(mpiCaptureValidate(*capture));

    /* Create compare object */
    *compare =
        mpiCompareCreate(*control,
                         compareNumber);
    msgCHECK(mpiCompareValidate(*compare));

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification object for NULL (all objects) */
    *notify =
        mpiNotifyCreate(eventMask,
                        NULL);
    msgCHECK(mpiNotifyValidate(*notify));

    /* Append notify to event manager */
    returnValue =
        mpiEventMgrNotifyAppend(*eventMgr,
                                *notify);
    msgCHECK(returnValue);

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*****************************************************************************

  Create and initialize MPI objects, and place MSs' axis maps on XMP.
    Use this function instead of programInitMultiple() if your program
    calls some mpiMotion method that times out b/c the axis maps on the XMP
    do not match those on the host.
    [Arrays of some objects -- Use as a model]

  Note: Rename function to programInit(...) and delete what you don't need.

  Declare at head of main():

int main(int     argc,
         char   *argv[])
{
    MPIControl          control;
    MPIControlType      controlType;
    MPIControlAddress   controlAddress;
    MPIMotion           motion[];
    MPIAxis             axis[];
    MPIFilter           filter[];
    MPIMotor            motor[];
    MPISequence         sequence[];
    MPICapture          capture[];
    MPICompare          compare[];
    MPINotify           notify[];
    MPIEventMgr         eventMgr;
    long                numberOfMotions;
    long                numberOfAxes;
    long                numberOfFilters;
    long                numberOfMotors;
    long                numberOfSequences;
    long                numberOfCaptures;
    long                numberOfCompares;
    long                numberOfNotifys;
    long                motionNumber[];
    long                axisNumber[];
    long                filterNumber[];
    long                motorNumber[];
    long                sequenceNumber[];
    long                captureNumber[];
    long                compareNumber[];

  Call function as:

    /* Perform basic command line parsing. (-control -server -port -trace) *
    basicParsing(argc,
                 argv,
                 &controlType,
                 &controlAddress);

    /* Create and initialize MPI objects *
    programInit(&control,
                controlType,
                &controlAddress,
                motion,
                numberOfMotions,
                motionNumber,
                axis,
                numberOfAxes,
                axisNumber,
                filter,
                numberOfFilters,
                filterNumber,
                motor,
                numberOfMotors,
                motorNumber,
                &recorder,
                sequence,
                numberOfSequences,
                sequenceNumber,
                capture,
                numberOfCaptures,
                captureNumber,
                compare,
                numberOfCompares,
                compareNumber,
                &eventMgr,
                notify,
                numberOfNotifys,
                &service);

******************************************************************************/

/* Create and initialize MPI objects */
void programInitMultipleWithMapping(MPIControl          *control,
                 MPIControlType      controlType,
                 MPIControlAddress  *controlAddress,
                 MPIMotion          *motion,
                 long                numberOfMotions,
                 long               *motionNumber,
                 MPIAxis            *axis,
                 long                numberOfAxes,
                 long               *axisNumber,
                 MPIFilter          *filter,
                 long                numberOfFilters,
                 long               *filterNumber,
                 MPIMotor           *motor,
                 long                numberOfMotors,
                 long               *motorNumber,
                 MPIRecorder        *recorder,
                 MPISequence        *sequence,
                 long                numberOfSequences,
                 long                sequencePageSize,
                 long               *sequenceNumber,
                 MPICapture         *capture,
                 long                numberOfCaptures,
                 long               *captureNumber,
                 MPICompare         *compare,
                 long                numberOfCompares,
                 long               *compareNumber,
                 MPIEventMgr        *eventMgr,
                 MPINotify          *notify,
                 long                numberOfNotifys,
                 Service            *service)
{
    MPIEventMask    eventMask;
    long            index;
    long            returnValue;

    /* Create motion controller object */
    *control =
        mpiControlCreate(controlType,
                         controlAddress);
    msgCHECK(mpiControlValidate(*control));

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

    /* Create axes objects */
    for (index = 0; index < numberOfAxes; index++) {
        axis[index] =
            mpiAxisCreate(*control,
                          axisNumber[index]);
        msgCHECK(mpiAxisValidate(axis[index]));
    }

    /* Create motion supervisor objects with axis[] */
    for (index = 0; index < numberOfMotions; index++) {
        motion[index] =
            mpiMotionCreate(*control,
                            motionNumber[index],
                            axis[index]);
        msgCHECK(mpiMotionValidate(motion[index]));

        /* Map axis to motion supervisor on XMP */
        returnValue =
            mpiMotionAction(motion[index],
                            MEIActionMAP);
        msgCHECK(returnValue);
    }

    /* Create filter objects */
    for (index = 0; index < numberOfFilters; index++) {
        filter[index] =
            mpiFilterCreate(*control,
                            filterNumber[index]);
        msgCHECK(mpiFilterValidate(filter[index]));
    }

    /* Create motor objects */
    for (index = 0; index < numberOfMotors; index++) {
        motor[index] =
            mpiMotorCreate(*control,
                            motorNumber[index]);
        msgCHECK(mpiMotorValidate(motor[index]));
    }

    /* Create recorder object */
    *recorder =
        mpiRecorderCreate(*control);
    msgCHECK(mpiRecorderValidate(*recorder));

    /* Create sequencer objects */
    for (index = 0; index < numberOfSequences; index++) {
        sequence[index] =
            mpiSequenceCreate(*control,
                              sequenceNumber[index],
                              sequencePageSize);
        msgCHECK(mpiSequenceValidate(sequence[index]));
    }

    /* Create capture objects */
    for (index = 0; index < numberOfCaptures; index++) {
        capture[index] =
            mpiCaptureCreate(*control,
                             captureNumber[index]);
        msgCHECK(mpiCaptureValidate(capture[index]));
    }

    /* Create compare objects */
    for (index = 0; index < numberOfCompares; index++) {
        compare[index] =
            mpiCompareCreate(*control,
                             compareNumber[index]);
        msgCHECK(mpiCompareValidate(compare[index]));
    }

    /* Create event manager object */
    *eventMgr =
        mpiEventMgrCreate(*control);
    msgCHECK(mpiEventMgrValidate(*eventMgr));

    /* Request notification of ALL events from motion */
    mpiEventMaskCLEAR(eventMask);
    mpiEventMaskALL(eventMask);
    meiEventMaskALL(eventMask);

    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */
    /* Should call mpiXxxEventNotifySet(...) so that events will be reported */

    /* Create event notification objects for NULL (all objects) */
    for (index = 0; index < numberOfNotifys; index++) {
        notify[index] =
            mpiNotifyCreate(eventMask,
                            NULL);
        msgCHECK(mpiNotifyValidate(notify[index]));

        /* Append notify to event manager */
        returnValue =
            mpiEventMgrNotifyAppend(*eventMgr,
                                    notify[index]);
        msgCHECK(returnValue);
    }

    /* Create service thread */
    *service =
        serviceCreate(*eventMgr,
                      -1,   /* default (max) priority */
                      -1);  /* -1 => enable interrupts */
    if (*service != NULL) {
        msgCHECK(MPIMessageHANDLE_INVALID);
    }
}

/*
  Configure Home Limit to be triggered on the Home Input rather than the capture
*/
void homeLimitOnInput(MPIMotor  motor,
                      long      activeHigh)
{
    MEIMotorConfig   motorConfigXmp;    /* XMP motor I/O configuration */
    MEIXmpMotor     *motorXmp;          /* XMP motor memory */
    long             returnValue;       /* return value from library */

    /* Get pointer to Motor memory */
    returnValue =
        mpiMotorMemory(motor,
                       &motorXmp);

    /* Get the XMP Motor configuration*/
    returnValue =
        mpiMotorConfigGet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);

    /* Set the new Home Limit parameters */
    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].SourceAddress =
        &motorXmp->IO.DedicatedIN.IO;

    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].Mask =
        MEIXmpMotorIOMaskHOME;
    /* Set for Active High Home switch */
    motorConfigXmp.Limit[MEIXmpLimitHOME].Condition[0].LimitValue.l =
        (activeHigh) ? MEIXmpMotorIOMaskHOME : 0;

    /* Set the new XMP Motor configuration*/
    returnValue =
        mpiMotorConfigSet(motor,
                          NULL,
                          &motorConfigXmp);
    msgCHECK(returnValue);
}

/*
  enableUserLimit()  configures and enables one user limit.

  A user configured motor limit (user limit) normally uses one of the following
  limit types:

    MEIEventTypeLIMIT_USER0
    MEIEventTypeLIMIT_USER1
    MEIEventTypeLIMIT_USER2
    MEIEventTypeLIMIT_USER3
    MEIEventTypeLIMIT_USER4
    MEIEventTypeLIMIT_USER5
    MEIEventTypeLIMIT_USER6
    MEIEventTypeLIMIT_USER7

  but can also be one of the following types:

    MPIEventTypeAMP_FAULT
    MPIEventTypeHOME
    MPIEventTypeLIMIT_ERROR
    MPIEventTypeLIMIT_HW_NEG
    MPIEventTypeLIMIT_HW_POS
    MPIEventTypeLIMIT_SW_NEG
    MPIEventTypeLIMIT_SW_POS
    MPIEventTypeENCODER_FAULT

  Please read Application note 215 for a detailed discussion about user limits.

*/
void enableUserLimit(MPIMotor       motor,
                     long           enable)
{
    /* Configure user limit zero */
    MEIEventType     limit       = MEIEventTypeLIMIT_USER0;

    MEIXmpLimitData  customLimit;
    MEIXmpData      *firmware;      /* Needed to access general XMP addresses */
    MEIXmpMotor     *motorXmp;      /* Needed to access motor's addresses     */

    long             returnValue;

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &customLimit);
    msgCHECK(returnValue);

    if (enable) {

        /* Get pointer to XMP firmware */
        returnValue =
            mpiControlMemory(mpiMotorControl(motor),
                             &(void *)firmware,
                             NULL);
        msgCHECK(returnValue);

        /* Get pointer to motor's memory */
        returnValue =
            mpiMotorMemory(motor, &(void *)motorXmp);
        msgCHECK(returnValue);

        /* Set up limit condition 0 */
        customLimit.Condition[0].Type         = MEIXmpLimitTypeGE;
        customLimit.Condition[0].SourceAddress= &motorXmp->IO.DedicatedIN.IO;
        customLimit.Condition[0].Mask         = MEIMotorInputAMP_FAULT;
        customLimit.Condition[0].LimitValue.l = MEIMotorInputUSER;

        /* Set up limit condition 1 */
        customLimit.Condition[1].Type         = MEIXmpLimitTypeNE;
        customLimit.Condition[1].SourceAddress= &firmware->MS[0].Action;
        customLimit.Condition[1].Mask         = MEIMotorInputAMP_FAULT;
        customLimit.Condition[1].LimitValue.l = MEIMotorInputHOME;

        /* Set up limit output */
        customLimit.Output.OutputPtr = (void*)&firmware->Axis[0].ActualVelocity;
        customLimit.Output.Enabled   = TRUE;
        customLimit.Output.AndMask   = 0;
        customLimit.Output.OrMask    = 0;

        /* Set up limit logic */
        customLimit.Logic = MEIXmpLogicAND;

        /* Set up the XMP to handle the user limit */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);

    } else {
        /* Set default limit parameters */
        customLimit.Condition[0].Type = MEIXmpLimitTypeFALSE;
        customLimit.Condition[1].Type = MEIXmpLimitTypeFALSE;

        customLimit.Status = MEIXmpStatusLIMIT;
        customLimit.Logic  = MEIXmpLogicNEVER;

        customLimit.Output.AndMask = -1;    /* ALL BITS */
        customLimit.Output.OrMask  = 0;
        customLimit.Output.Enabled = FALSE;

        /* Reset the user limit on the XMP */
        returnValue =
            mpiMotorEventConfigSet(motor,
                                   (MPIEventType)limit,
                                   NULL,
                                   &customLimit);
        msgCHECK(returnValue);
    }
}

/*
  disableUserLimit()  disables and erases the configuration of one user limit.
*/
void disableUserLimit(MPIMotor      motor,
                      MEIEventType  limit)
{
    MEIXmpLimitData userLimit;
    long            returnValue;

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);

    /* Set default limit parameters */
    userLimit.Condition[0].Type = MEIXmpLimitTypeFALSE;
    userLimit.Condition[1].Type = MEIXmpLimitTypeFALSE;

    userLimit.Status = MEIXmpStatusLIMIT;
    userLimit.Logic  = MEIXmpLogicNEVER;

    userLimit.Output.AndMask = -1;  /* ALL BITS */
    userLimit.Output.OrMask  = 0;
    userLimit.Output.Enabled = FALSE;

    /* Reset the user limit on the XMP */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               (MPIEventType)limit,
                               NULL,
                               &userLimit);
    msgCHECK(returnValue);
}

/*
  userLimitEnable()  enables or disables one user limit.

    This function does not change (most of) the configuration of a user limit.

    Because the function does change the logic to temporarily disable
    a user limit, this function must store the values of the limit's
    logic.
*/
void userLimitEnable(MPIMotor       motor,
                     MEIEventType   limit,
                     long           enable)
{
    static MEIXmpLogic  savedLogic[MEIXmpMAX_Motors][MEIEventTypeMOTOR_LAST];

    MEIXmpLimitData limitData;
    long            motorNumber;
    long            returnValue;

    /* Get the motor number */
    mpiMotorNumber(motor,
                   &motorNumber);

    /* Get the user limit configuration */
    returnValue =
        mpiMotorEventConfigGet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);

    if (enable) {
        /* Restore logic */
        limitData.Logic = savedLogic[motorNumber][limit];
    }
    else {
        /* Save logic */
        savedLogic[motorNumber][limit] = limitData.Logic;

        /* Set logic to MEIXmpLogicNEVER to disable limit */
        limitData.Logic = MEIXmpLogicNEVER;
    }

    /* Set the new configuration */
    returnValue =
        mpiMotorEventConfigSet(motor,
                               limit,
                               NULL,
                               &limitData);
    msgCHECK(returnValue);
}

/*
   sequenceCommandAdd() creates a command (MPICommand object) and appends it to
   sequence's list of commands.  This function does return MPI error codes so
   that sequence setup code may be more easily debugged.

   Warning:  sequenceCommandAdd() does not keep track of created command objects
   so it is important that before a sequence object is deleted, that each
   command object on sequence's list is itself deleted.  Otherwise, there will
   be memory leaks.  One can use sequenceProgramDelete() to accomplish this.
*/
long sequenceCommandAdd(MPISequence          sequence,
                        MPICommandType       commandType,
                        MPICommandParams    *commandParams,
                        const char          *label)
{
    MPICommand  command;
    long        returnValue;

    command =
        mpiCommandCreate(commandType,
                         commandParams,
                         label);
    returnValue =
        mpiCommandValidate(command);

    if (returnValue == MPIMessageOK) {
        returnValue =
            mpiSequenceCommandAppend(sequence,
                                     command);
    }

    return returnValue;
}

/*
   sequenceProgramCreate() is a prototype function showing how one can create a
   MPISequence program.  This prototype creates a program that simply loops
   continually, much like the statement:

    while(1) {}

   would in C.  This function uses sequenceCommandAdd() to add commands to
   sequence.  One should use sequenceProgramDelete() to delete the sequence
   object and the MPICommand objects on sequence's command list.  Please refer
   to the description of sequenceCommandAdd() for more details.
*/
MPISequence sequenceProgramCreate(MPIControl control)
{
    MPISequence         sequence;
    MPICommandParams    commandParams;
    long                returnValue;

    /* Create sequence object */
    sequence =
        mpiSequenceCreate(control,
                          -1,   /* Use the next available sequence */
                          1);   /* # of commands in sequence */
    msgCHECK(mpiSequenceValidate(sequence));

    /* Branch to the first command of the sequence */
    commandParams.branch.label      = "First";  /* First command */
    commandParams.branch.expr.oper  = MPICommandOperatorALWAYS;

    /* Add command to sequence */
    returnValue =
        sequenceCommandAdd(sequence,
                           MPICommandTypeBRANCH,
                           &commandParams,
                           "First");
    msgCHECK(returnValue);

    /* Return the new sequence handle */
    return sequence;
}

/*
   sequenceProgramDelete() removes and deletes all command objects on sequence's
   command list and then deletes sequence.  This function does return MPI error
   codes so that sequence setup code may be more easily debugged.
*/
long sequenceProgramDelete(MPISequence *sequence)
{
    MPICommand  command;
    long        returnValue = MPIMessageOK;

    /* Remove and delete command objects on sequence list */
    while(TRUE) {
        command = mpiSequenceCommandLast(*sequence);
        if ((returnValue != MPIMessageOK) ||
            (command==MPIHandleVOID)) {
            break;
        }
        returnValue =
            mpiSequenceCommandRemove(*sequence,
                                     command);

        if (returnValue == MPIMessageOK) {
            returnValue =
                mpiCommandDelete(command);
        }
    }

    /* Delete sequence object */
    returnValue =
        mpiSequenceDelete(*sequence);

    if (returnValue == MPIMessageOK) {
        /* Make it obvious that sequence is no longer a valid object */
        *sequence = MPIHandleVOID;
    }

    return returnValue;
}

/*
   Starts a sequence, waits for the user to press a key and then
   stops the sequence.
*/
void sequenceRun(MPISequence sequence)
{
    long returnValue;

    /* Start sequence */
    returnValue =
        mpiSequenceStart(sequence,
                         MPIHandleVOID);
    msgCHECK(returnValue);

    fprintf(stderr,"Press any key to stop sequence.\n");
    meiPlatformKey(MPIWaitFOREVER);
    fprintf(stderr,"Exiting ...\n");

    /* Stop sequence */
    returnValue = mpiSequenceStop(sequence);
    if ((returnValue != MPIMessageOK) &&
        (returnValue != MPISequenceMessageSTOPPED)) {
        msgCHECK(returnValue);
    }

    returnValue = mpiSequenceDelete(sequence);
    msgCHECK(returnValue);
}

/*****************************************************************************

  Start the XMP's recorder, get data, and stop the recorder

******************************************************************************/

long recordData(MPIRecorder         recorder,
                long                numRecords,
                long                period,
                long                eventCount,
                MPIRecorderRecord  *records)
 {
    long returnValue;
    long recordIndex;
    long recordCountRemaining;
    long countGet;

    /* Start recording the axis */
    returnValue =
        mpiRecorderStart(recorder,
                         numRecords,
                         period,    /* period (milliseconds) */
                         eventCount);
    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);

    return returnValue;
}

/*****************************************************************************

   Example:
    Configure recorder object

   This example records 3 system data variables:
    1) The sample counter -- increments by 1 every servo cycle
    2) The background cycle -- increments by 1 after every background cycle
    3) The "count delta" -- increments by 1 after every background cycle and
            resets to zero after every servo cycle

******************************************************************************/

void configureRecorder(MPIRecorder recorder)
{
    MPIControl          control = mpiRecorderControl(recorder);
    MEIXmpData*         firmware;
    MEIXmpBufferData*   external;

    void    *point[MEIXmpMaxRecSize];

    long    pointCount = 0;
    long    returnValue;

    returnValue =
        mpiControlMemory(control,
                         &firmware,
                         &external);
    msgCHECK(returnValue);

    point[pointCount++] = &firmware->SystemData.SampleCounter;
    point[pointCount++] = &firmware->SystemData.BackgroundCycle;
    point[pointCount++] = &firmware->SystemData.CountDelta;

    meiASSERT(pointCount <= MEIXmpMaxRecSize);

    returnValue =
        mpiRecorderRecordConfig(recorder,
                                MPIRecorderRecordTypePOINT,
                                pointCount,
                                point);
    msgCHECK(returnValue);
}

/*****************************************************************************

   Stops the data recorder ignoring the MPIRecorderMessageSTOPPED message if
    the recorder is already stopped.

******************************************************************************/

void stopRecorder(MPIRecorder recorder)
{
    long returnValue =
        mpiRecorderStop(recorder);

    /* In case the recorder has already stopped */
    if (returnValue == MPIRecorderMessageSTOPPED) {
        returnValue = MPIMessageOK;
    }
    msgCHECK(returnValue);
}


MPX Sample Applications

.

LabView
Sub-VIs
Event Wait
Event Wait From Multiple
Remote Connect

VIs
Settling

Visual Basic
 AxisIo
EventView
Home1
PID Tuner

Visual Basic Script
ControllerInfo
Version


MPX Sample Application: Event Wait

MEI Home
.

Name: Event Wait

Description:

Similar to LabVIEW's standard Wait on ActiveX Event VI, except this VI returns event information in individual variables rather than packed into an array.

Download

MPX Event Wait.vi


MPX Sample Application: Event Wait From Multiple VIs

MEI Home
.

Name: Event Wait From Multiple VIs

Description:

Similar to LabVIEW's standard Wait on ActiveX Event From Multiple VI, except this VI returns event information in individual variables rather than packed into an array.

Download

MPX Event Wait From Multiple VIs.vi


MPX Sample Application: MPX Remote Connect

MEI Home
.

Name: MPX Remote Connect

Description:

This VI allows an MPX control to connect to a controller on a remote computer.

Notes

This VI simplifies diagrams by allowing all connection information to specified in a single function block - normally, one would need to set all connection information through separate ActiveX properties.

Download

MPX Remote Connect.vi


MPX Sample Application: Settling

MEI Home
.

Name: Settling

Description:

This VI demonstrates how one can use MPX events to track how long it takes an axis to settle at the end of a motion.

Notes

This VI displays a histogram of settling times for a particular axis. The number of histogram intervals may be changed by the user while the VI is executing.

Download

Settling.vi


MPX Sample Application: AxisIo

MEI Home
.

Name: AxisIo

Description:

This application allows a user to view an axis' digital inputs and outputs as well as change the state of the axis' digital outputs.

Download

AxisIo.zip

Includes the following files:
AxisIo.frm
AxisIo.frx
AxisIo.vbp


MPX Sample Application: EventView

MEI Home
.

Name: EventView

Description:

This application will display all the events generated by a controller.

Notes

This application is useful for diagnostics and as a general MPX example. It is not meant to run for extended periods of time, because it will consume too much system memory in an attempt to keep a full log of events.

Download

EventView.zip

Includes the following files:
EventView.frm
EventView.frx
EventView.vbp


MPX Sample Application: Home1

MEI Home
.

Name: Home1

Description:

This application shows an example of how to home an axis.

Notes

This application does not contain a general purpose homing routine. It assumes that the home location is located at the rising edge of the home input and requires the user to specify what direction to move the axis.

Download

Home1.zip

Includes the following files:
Home1.frm
Home1.frx
Home1.vbp


MPX Sample Application: PIDTuner

MEI Home
.

Name: PIDTuner

Description:

This application allows the user to enter PID tuning parameters for an axis.

Download

PIDTuner.zip

Includes the following files:
PIDTuner.frm
PIDTuner.frx
PIDTuner.vbp


MPX Sample Application: ControllerInfo

MEI Home
.

Name: ControllerInfo

Description:

This script displays a variety of information about the controller through a popup window.

Download

ControllerInfo.vbs


MPX Sample Application: Version

MEI Home
.

Name: Version

Description:

This script displays version information about the controller through a popup window.

Download

Version.vbs


MPX Software Concepts

.

Topics
Flash Memory
Initialization
Objects Structure
Point-to-Point Motion
Position Units
Servo Configuration
Servo Control
Variant Data Types
Velocity Motion
Errors
Synchronized Attributes

Events
 Events Overview
Event Handlers
Event Sequence
Motion Related Events
 Event Descriptions

FAQs
 - What is the MPX?
- What is the difference between the MPI and the MPX?
- more >>


Errors

MEI Home
.

Errors

When using the methods or properties of MEI's MPX control, many checks are performed on the supplied data, internal configuration, and state of the motion controller. Examples of such errors are, trying to set a read only property such as Motion.State. If any of these checks fail, the MPX control will generate an error. These errors are returned using the conventions of ActiveX controls that allow languages such as Visual Basic to use their native error handling schemes. For example, it is not necessary to check the error codes returned after every call to the MPX control.

Events also report some error conditions that are detected and reported independently of what the host application is doing. The Events section describes these errors in more detail.

When errors are reported an error number is reported along with a brief textual description of the error. You should use the meiError enumeration if you want to test for a specific error, not the actual value, since the numbers used for the error codes may be different with different versions.

See Also

meiError


Amplifier Fault

MEI Home
.

Amplifier Fault

Description

Every axis has an amplifier fault event which is generated when the drive is in a fault state.

On SynqNet drive nodes this signal is internal to the drive unit and is not available as a physical I/O line, for all other cases the amplifier fault is a dedicated digital input. The sense of the input that generates the amplifier fault is specified by the Axis.AmpFaultInvert property and the Axis.AmpFaultDuration property allows you to change how long the amplifier fault has to be present before the event is generated.

Axis.Status (meiStatusAmpFault) will return TRUE after this event has been generated. Once this event has been generated, it cannot be generated again until a Motion.Reset command has been issued.

Event Info

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 AmpFaultInvert
AmpFaultDuration
Status

Motion Object
Reset


Event Descriptions

.

Event Descriptions

Amplifier Fault
Encoder Fault

Home

Negative Hardware Limit
Negative Software Limit

Position Error Limit
Positive Hardware Limit
Positive Software Limit
Power Fail Event


Encoder Fault

MEI Home
.

Encoder Fault

Description

The encoder interface on XMP controllers is able to detect several different problems with the connection to the encoder. The Axis.EncoderFaultTrigger property allows the different conditions to be disabled when generating this event. When this event is generated, Axis.EncoderFaultAction specifies which action is automatically performed.

Axis.Status(meiStatusEncoderFault) will return TRUE after this event has been generated. Once this event has been generated it cannot be generated again until a Motion.Reset command has been issued.

Event Info

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 EncoderFaultAction
EncoderFaultTrigger
Status

Motion Object
Reset


Event Handlers

MEI Home
.

Event Handlers

The MPX control provides three event handlers that allow code to be executed when an event has been generated.

  • OnAnyEvent
  • OnErrorEvent
  • OnMotionEvent

All events will call the OnAnyEvent handler, and may call either the OnErrorEvent or OnMotionEvent handlers, depending on the type of event.

For example, the following function created in a Visual Basic program will be executed on every event that is generated on the controller.

Sub Controller_OnAnyEvent(ByVal EventType As MPX.meiEventType,
ByVal Number As Long,
ByVal Info As Variant)

'Any instructions here is executed after an event is generated.
EndSub

The event code receives three arguments that give the type of event that has been generated, the number of the axis or motion object that generated the event and an array of integers. The array of ten extra Info numbers are a set of numbers captured when the original event was detected. The data captured in the Info array is different for each type of event and is described in the description of each event.

The Info array holds data captured when the event was generated. The data captured and copied into this array is different for each type of event as described in that event's documentation.

See Also

Event Descriptions

Controller Object
OnAnyEvent
OnErrorEvent
OnMotionEvent


Home

MEI Home
.

Home

Description

The home event is designed to be used along with the other commands to create a homing sequence. Each axis has a digital input that is dedicated to being used as a home input.

The home event is generated either by the hardware home input or in response to the hardware capture unit. Axis.HomeSource is used to select which source is used. The sense of the input that generates the home event is specified by the Axis.HomeInvert property. The Axis.HomeDuration property allows you to change how long the home input must be present before the event is generated.

Axis.Status(meiStatusHome) will return TRUE after this event has been generated.

Event Info

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 HomeSource
HomeInvert
HomeDuration
Status


Motion Related Events

MEI Home
.

Motion Related Events

Description

There are five motion related events--two generated by the Motion object and three generated by the Axis object:

Event | Object
meiEventTypeAtTarget | Axis
meiEventTypeInCoarsePosition | Axis
meiEventTypeSettled | Axis
meiEventTypeDone | Motion
meiEventTypeAtVelocity | Motion

The event meiEventTypeAtTarget is generated near the end of a move when an axis's command position has stopped changing at the end of a move (when the command position has reached the target position and is no longer changing).

The event meiEventTypeInCoarsePosition is generated the first time the condition is satisfied during a move.

The event, meiEventTypeSettled is generated any time an axis changes from a non-settled state to a settled state. An axis is considered to be settled when:

  • The absolute value of PositionError is less than or equal to TolerancePositionFine
  • The absolute value of ActualVelocity is less than or equal to the ToleranceVelocity
  • Both of the above criteria has been satisfied for the settling time. Whenever either of the above criteria is not satisfied, the Fine Position Status is cleared and the settling timer is reset.

After a move is commanded, the event meiEventTypeSettled is first generated when the motion is complete.

The event meiEventTypeSettled is generated the when all axes associated with a Motion object have finished commanding motion and have settled. If events of type meiEventTypeSettled are enabled, then one can expect an meiEventTypeSettled event to be generated at the same time as a meiEventTypeDone event.

The event meiEventTypeAtVelocity is generated when all axes associated with a Motion object have settled at the final velocity of a velocity move. meiEventTypeAtVelocity can be thought of as "meiEventTypeDone for velocity moves."

See Also

SettlingTime
TolerancePositionCoarse
TolerancePositionFine
ToleranceVelocity


Negative Hardware Limit

MEI Home
.

Negative Hardware Limit

Description

Every axis has two digital inputs that are dedicated to being used for hardware over-travel inputs. The motion controller generates the positive and negative hardware limit events independently using these digital inputs and the velocity of the axis.

The negative hardware limit is generated when the digital input detects the over-travel and the command velocity is less than zero for a time specified by Axis.LimitHwNegDuration. The velocity test can be disabled by clearing the Axis.LimitHwNegDirectionSensitive property. When this event is generated Axis.LimitHwNegAction specifies which action is automatically performed.

Axis.Status(meiStatusLimitHwPos) will return TRUE after this event has been generated.

Info Data

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 LimitHwNegDuration
LimitHwNegDirectionSensitive
LimitHwNegAction
Status


Negative Software Limit

MEI Home
.

Negative Software Limit

Description

Every axis can generate two software limits. These are similar to the hardware limits, but use the position of the axis instead of a physical hardware switch. These limits are used in many situations where hardware switches are not fitted and an end-of-travel needs to be ensured.

A negative software limit is generated when the position for the axis is less than the position threshold set by Axis.LimitSwNeg and the Command Velocity is less than zero for a time specified by Axis.LimitSwNegDuration. The velocity test can be disabled by clearing the Axis.LimitSwNegDirectionSensitive property. When this event is generated, Axis.LimitSwNegAction specifies which action is automatically performed.

Axis.Status(meiStatusLimitSwNeg) will return TRUE after this event has been generated.

Info Data

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 LimitSwNeg
LimitSwNegDuration
LimitSwNegDirectionSensitive
LimitSwNegAction
Status


Events Overview

MEI Home
.

Events Overview

Events are asynchronous (can be generated at any time, independently of what the main program is doing) conditions that are generated by the firmware executing on the motion controller.

  • Event Sequence
  • Event Handlers

The following table lists all the different type of events that can be generated by a controller:

Event Name | Enumeration | Source | Event Handler | Configurable?
Position Error Limit | meiEventTypeLimitPositionError | Axis | OnErrorEvent | Yes
Positive Hardware Limit | meiEventTypeLimitHwPos | Axis | OnErrorEvent | Yes
Negative Hardware Limit | meiEventTypeLimitHwNeg | Axis | OnErrorEvent | Yes
Positive Software Limit | meiEventTypeLimitSwPos | Axis | OnErrorEvent | Yes
Negative Software Limit | meiEventTypeLimitSwNeg | Axis | OnErrorEvent | Yes
Amplifier Fault | meiEventTypeAmpFault | Axis | OnErrorEvent | Yes
Encoder Fault | meiEventTypeEncoderFault | Axis | OnErrorEvent | Yes
Home | meiEventTypeHome | Axis | OnMotionEvent | Yes
In Coarse Position Tolerance | meiEventTypeInPositionCoarse | Axis | OnMotionEvent | Yes
Axis Settled | meiEventTypeSettled | Axis | OnMotionEvent | Yes
At Target | meiEventTypeAtTarget | Axis | OnMotionEvent | Yes
Motion Done | meiEventTypeDone | Motion | OnMotionEvent | Yes
Axis at Final Velocity | meiEventTypeAtVelocity | Motion | OnMotionEvent | Yes
Supply Voltage Low | meiEventTypePowerFault | Controller | OnAllEvents | Yes

Event Name | Enumeration | Source | Event Handler | Configurable?
Torque Limit | meiEventTypeLimitTorque | Axis | On All Events | No
User Limit 0 | meiEventTypeUserLimit0 | Axis | On All Events | No
User Limit 1 | meiEventTypeUserLimit1 | Axis | On All Events | No
User Limit 2 | meiEventTypeUserLimit2 | Axis | On All Events | No
User Limit 3 | meiEventTypeUserLimit3 | Axis | On All Events | No
User Limit 4 | meiEventTypeUserLimit4 | Axis | On All Events | No
User Limit 5 | meiEventTypeUserLimit5 | Axis | On All Events | No
User Limit 6 | meiEventTypeUserLimit6 | Axis | On All Events | No
User Limit 7 | meiEventTypeUserLimit7 | Axis | On All Events | No
Frame Event | meiEventTypeFrame | Motion | On All Events | No
Out of Frames | meiEventTypeOutOfFrames | Motion | On All Events | No
Recorder Full | meiEventTypeRecorderFull | Recorder | On All Events | No
Recorder Done | meiEventTypeRecorderDone | Recorder | On All Events | No
External Event | meiEventTypeExternal | Controller | On All Events | No

See Also

Controller Object
Axis Object
Motion Object

Event Sequence
Event Handlers


Positive Hardware Limit

MEI Home
.

Positive Hardware Limit

Every axis has two digital inputs that are dedicated to being used for hardware over-travel inputs. The motion controller generates the positive and negative hardware limit events independently using these digital inputs and the velocity of the axis.

The positive hardware limit is generated when the digital input detects the over-travel and the command velocity is greater than zero for a time specified by Axis.LimitHwPosDuration. The velocity test can be disabled by clearing the Axis.LimitHwPosDirectionSensitive property. When this event is generated, Axis.LimitHwPosAction specifies which action is automatically performed.

Axis.Status(meiStatusLimitHwPos) will return TRUE after this event has been generated.

Info Data

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 LimitHwPosDuration
LimitHwPosDirectionSensitive
LimitHwPosAction
Status


Positive Software Limit

MEI Home
.

Positive Software Limit

Description

Every axis can generate two software limits: positive and negative. These are similar to the hardware limits but use the position of the axis instead of a physical hardware switch as one of the triggering conditions. These limits are used in many situations where hardware switches are not fitted and an end-of-travel needs to be ensured.

A positive software limit is generated when the position for the axis exceeds the position threshold set by Axis.LimitSwPos and the Command Velocity is greater than zero for a time specified by Axis.LimitSwPosDuration. The velocity test can be disabled by clearing the Axis.LimitSwPosDirectionSensitive property. When this event is generated, Axis.LimitSwPosAction specifies which action is automatically performed.

Axis.Status(meiStatusLimitSwPos) will return TRUE after this event has been generated.

Info Data

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 LimitSwPos
LimitSwPosDuration
LimitSwPosDirectionSensitive
LimitSwPosAction
Status


Position Error Limit

MEI Home
.

Position Error Limit

Description

The position error event is generated when the absolute value of the position error exceeds the LimitPositionError threshold for a duration set by Axis.LimitPositionErrorDuration. When this event is generated, Axis.LimitPositionErrorAction specifies what action is automatically performed.

Axis.Status(meiStatusLimitPositionError) will return true after this event has been generated. Once this event has been generated, it cannot be generated again until a Motion.Reset command has been issued.

Info Data

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 | Encoder Position
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 LimitPositionErrorDuration
LimitPositionErrorAction
Status

Motion Object
Reset


Power Fail Event

MEI Home
.

Power Fail Event

Description

This event is generated when the power supply monitor on the controller senses that either the +12V or -12V on either the main or any optional expansion cards is less than 10V. These voltages are provided by the backplane and this fault commonly indicates a problem with the host's power supply or the interconnections to the motion controller.

Axis.Status(meiStatusPowerFault) will return TRUE after this event has been generated. Once this event has been generated, it can only be cleared by powering down the controller.

Event Info

The following table summarizes the extra event info that is recorded when this event is generated.

Index | Description
0 | Sample Counter
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |

See Also

Axis Object
 Status


Events Sequence

MEI Home
.

Events Sequence

  1. The motion controller's firmware detects a condition that will trigger an event.
  2. The EventState for this event is immediately set. The event state will remain set until it is cleared. This property can be periodically monitored to know if an event has happened without needing any of the subsequent steps.
  3. If this event has a default action property then the appropriate object will perform the specified default action changing the motion object's state. This allows the motion controller to react to events very quickly without needing to perform any operations on the host.
  4. Each event has an "Event Enable" property. If this enable property is true then the notification of this event is sent to the MPX control. It is common to only enable events that are required in the users application, thereby reducing the processor loading on the host (by not handling unused events). The MPX control will send a message to the host program allowing it to interrupt the task it is currently performing and make the appropriate action.
  5. The MEI's MPX control will call the users OnErrorEvent, OnMotionEvent functions.

See Also

Controller.OnMotionEvent
Controller.OnErrorEvent
Controller.OnAnyEvent

Motion.State


Flash Memory

MEI Home
.

Flash Memory

Every MEI motion controller contains flash memory. Flash memory is a non-volatile (preserves its contents when the power is removed) memory technology that can be reprogrammed without removing it from the controller. The XMP controller family uses the flash memory to store:

  • The firmware that the processor on the motion controller card uses. The configuration of each of the objects.
  • The configuration held in flash is the configuration that each object starts with once the controller is powered on.

The controller methods FirmwareUpload and FirmwareDownload allow the complete firmware image and configuration to be uploaded from or download to a .bin file on the host. This allows the firmware to be changed in the field with needing to physically touch the card.

Each object has a FlashSave method that saves the current configuration of that object to flash memory. After an object's FlashSave method has been called every time the controller powers up or the Controller object's Reset method is executed, the object will have the same configuration as when the FlashSave was originally executed. For example, all an axis objects gains are preserved.

The controller object has the FlashSaveAll method that allows the complete configuration of the controller object and all its axis and motion objects preserved to flash memory.

See Also

Controller Object
FirmwareUpload
FirmwareDownload
FlashSave
FlashSaveAll
Reset

Axis Object
FlashSave

Motion Object
FlashSave


Initialization

MEI Home
.

Initialization

The controller properties Type, Number, Address, and Port specify which XMP each controller object addresses. The default controller is controller zero on the local machine.

Where there are multiple motion controller cards in a system, multiple MPX Controller objects would be created to address each of the motion controller cards individually.

When programming using Visual Basic, you are able to modify these properties using the properties list window when you are designing your program. When the Visual Basic program starts to execute the controller automatically, it uses the type, number, address and port properties specified in the properties page to communicate with the controller.

When your program is executing, you are able to modify the Type, Number, Address and Port properties, but these new values will not be used until the Init method is called. For example, the following piece of Visual Basic shows how you would change to using the controller number 1 on the local machine.

Controller.Type = meiControllerTypeLocal
Controller.Number = 1
Controller.Init

See Also

Controller Object
Address
Number
Port
Type
Init


MPX Object Structure

MEI Home
.

MPX Structure - Objects

MPX is implemented as a hierarchy of objects. These objects group together related methods (the ActiveX term for a function) and properties (the ActiveX term for a variable) to simplify the access to the control.

The Controller

At the top of this hierarchy is the Controller object. This encompasses the motion controller providing methods and properties to start using an MEI motion controller and configure quantities affecting the whole controller such as the sample rate. The controller object contains multiple Axis and Motion objects.

The Axis Object

Axis objects represent the drive interfaces (the DAC, encoder, digital inputs, and digital outputs) and the associated software to control the single motor (control algorithm). There is one axis object per set of physical hardware signals.

The Motion Object

Motion objects group single or multiple axes together allowing coordinated motion to be performed on the axes and error conditions to be shared between the axes. The motion objects provide all the methods to start any motion and also methods and properties to monitor and control axes as a group.

The Relationship Between Axis and Motion Objects

Before any motion can be initiated, a motion object has to be instructed which axis or axes it is going to coordinate. The following diagram shows Motion(0) using Axis(0), and Motion(1) using Axes(1) and Axis(2).

The Motion.Axes property is used to specify which axes a motion object uses.

For example, the following two Visual Basic instructions set up the motion controller as shown in the previous diagram.

Controller.Motion(0).Axes = 0
Controller.Motion(1).Axes = Array(1,2)
Controller.Motion(2).Axes = Empty

In this example if an error occurs on one of the axes causing an error state then then Motion(1) will propagate this new state to all the other axes. The sharing of state allows automatic actions, such as hardware limits that EStop one axis will immediately EStop all the other associated axes.


Point-to-Point Motion

MEI Home
.

Point-to-Point Motion

Point to point motion will start a move on all the axes mapped to the Motion object from the current command position to a new position. There are three different methods that will start start a point-to-point motion, each taking a different set of arguments and generating different velocity profiles as the axis/axes are moving.

Trapezoidal | The type of motion has a trapezoidal shape for the velocity with constant acceleration and deceleration phases.
SCurve | This type of move has an "S" shape to the acceleration and deceleration phases. This method uses the JerkPercent argument to decide how much of the acceleration and deceleration phases is curved. A JerkPercent of zero produces a trapezoidal profile.
SCurveJerk | This type of move has an "S" shape to the acceleration and deceleration phases. This is the same velocity profile as the SCurve move but this method has arguments to specify the jerk that is to be used during the acceleration and deceleration phases.

Trapezoidal

SCurve

SCurveJerk

The following table summarizes the arguments that each of the methods take. The Position argument is always required, but all the other arguments are optional.

 | Position | Speed | Accel | Decel | JerkPercent | AccelJerk | DecelJerk | Attributes
Trapezoidal | * | x | x | x | . | . | . | x
SCurve | * | x | x | x | x | . | . | x
SCurveJerk | * | x | x | x | . | x | x | x

If an optional argument is omitted then the value used is taken from the corresponding properties starting with Default in either the Axis or Motion objects.

The Attributes argument modifies the default behavior of each of these motions enabling a great many variations of the basic motion to be generated. The Attributes argument does not have a corresponding default property and must be specified for each motion.

For example

Before a motion object can be used for any motion it needs to be mapped to an axis (or axes). This can be done with the following Visual Basic instruction to allow Motion object 0 to use axis 0.

Controller.Motion(0).Axes = 0

Default properties are zero at controller initialization and need to be given values before any motion will start. The following code sets up the default motion parameters for a trapezoidal move. These instructions only need to be issued once, commonly as the Visual Basic program starts, and are used by all the subsequent motion commands.

Controller.Motion(0).DefaultSpeed = 10000
Controller.Motion(0).DefaultAccel = 100000
Controller.Motion(0).DefaultDecel = 100000

The following Visual Basic code will start a trapezoidal move on the axis mapped to motion object 0.

Controller.Motion(0).Trapezoidal 1000

The default motion parameters can be overwritten for specific move using the following type of instruction.

Controller.Motion(0).Trapezoidal 2000, Speed:=20000

The attributes argument can be used to modify the motion, the following command changes the motion to a relative move.

Controller.Motion(0).Trapezoidal 500, _
Attributes=meiMoveAttrRelative

See Also

Motion.Trapezoidal
Motion.SCurve
Motion.SCurveJerk


Position Units

MEI Home
.

Position Units

MPX uses the unit of counts as its basic unit of position. A count is the smallest unit of position that can be used and is directly related to the type of encoder interface that is used.

Quadrature Encoders

When standard quadrature encoders are being used, the following diagram shows the relationship between the A and B signals from the encoder and the counts used by the controller. For MEI products, the positive count direction is when A leads B (A rising, B rising, A falling etc.) by default, but this can be reversed using a software flag.

Analog Encoders

An optional add-on module can be fitted to an XMP controller which allows it to interface to analog encoder signals. This is the Sinusoidal / Scale Interpolation module (SIM). For more information please see the SIM4 Application Note.

Analog encoder interfaces are commonly used on linear scales and interferometers, but are also used on some rotary encoders. This type of encoder interface supplies two sinusoidal signals with a phase difference of 90°. With this type of encoder signal, the position count is extracted from the analog signals giving 4096 counts per cycle.


Servo Configuration

MEI Home
.

Servo Configuration

All the axes on an MEI motion controller close their servo loops at the same rate. This rate is configured with the SampleRate property.

Two controller properties, AxisCountMax and MotionCountMax, return the maximum number of axes and motion objects that the motion controller can support. In some applications not all the axes or motion objects are required and the number of active axis or motion objects can be reduced. Reducing the number of active objects on a controller reduces the number of control loop computations that need to be performed each servo loop period and can allow the sample rate to be increased.

The controller properties, AxisCount and MotionCount are used to change the number of active servo loops. The controller only uses the axis object 0 to AxisCount -1 and motion objects 0 to MotionCount -1. Trying to use axis or motion objects whose number is greater than or equal to AxisCount or MotionCount will not work correctly.

See Also

AxisCount
AxisCountMax
MotionCount
MotionCountMax
SampleRate


Servo Control

MEI Home
.

Servo Control

Each axis object executes a servo loop at a constant rate. The following diagram represents the calculations being performed in each of these loop periods.

The following steps briefly summarize the sequence of operations that are performed each servo loop period:

  1. The encoder interface calculates the actual position and velocity of the axis using the information captured from the position sensor.
  2. A new command position and velocity is calculated from the trajectory data from a Motion object.
  3. A position error is calculated from the difference between the Command and Actual positions.
  4. A filter algorithm calculates the demand signal that is applied to the drive.

See Also

Axis.FilterAlgorithm
Axis.FilterCoeff


Synchronized Attributes

MEI Home
.

Synchronized Attributes

The motion of each axis is defined with separate arguments, with individual speeds, accelerations etc. These arguments for the Trapezoidal, SCurve, SCurveJerk, Velocity and VelocityJerk methods now require arrays of speeds etc. specifying the speeds etc. for each axis. If any of these speed, accel etc. arguments are omitted then the default values are read from the DefaultSpeed, DefaultAccel etc. properties of the connected axes.

Use of the meiMoveAttrSyncEnd attribute is not allowed for Velocity and VelocityJerk moves.

Sync Start ‡ | Sync End ‡‡ | Trajectory Parameter Data Types ‡‡‡ | Defaults from | Description
 |  | Double | motion object | A new axis (labeled x' in the diagram below) is defined by the start and end point of the motion. A Cartesian coordinate system is assumed. All trajectory parameters (speed, accel, decel, ...) are used to produce motion on this axis. That is why only one value is needed for each trajectory parameter.
Yes |  | Array of Double | axis objects | All the axes start at the same time.
 | Yes | Array of Double | axis objects | All the axes stop at the same time.
Yes | Yes | Array of Double | axis objects | All the axes start and stop at the same time; the faster axes are slowed down to match the time of the slowest axis. Axes whose motion completes too quickly are slowed down so that all axes will complete their motion at the same time.
 |  |  | ‡ - meiMoveAttrSynqStart ‡‡ - meiMoveAttrSynqEnd ‡‡‡ - include Speed, Accel, Decel, JerkPercent, AccelJerk, and DecelJerk.

Trajectory Examples

Visual Basic Example

The following code will move axes 3 and 4 to position 1000,2000.

Controller1.Motion(3).Axes = Array(3,4)
Controller1.Motion(3).Trapezoidal Array(1000,2000),
Attribues = meiMoveAttrSyncStart


Variant Data Types

MEI Home
.

Variant Data Types

The MPX control makes use of the variant data type. Variant data is part of the ActiveX standard and any language that supports ActiveX controls, (including Visual Basic and LabView) also supports the variant data type.

A variable that is defined as variant does not have an predetermined type (integer, double, string). Rather, it adapts as it is being used. Consider a variant variable X defined with:

Dim X

This variable can store any type of data depending on how it is used. The following code snippet shows X first being used as an integer and then as a string.

X = 2
Y = X + 2

X = "MEI"
Text1.Text = X

The MPX control uses variant data to simplify properties and methods. For example, the Motion.Axes property of the motion object is a variant type and can either be a single integer, an array of integers or Empty (a special type indicating that the property contains no data).


Velocity Motion

MEI Home
.

Velocity Motion

Velocity motion accelerates the axis/axes to a specified velocity. The axes will continue to move at the specified velocity until a new velocity is commanded (by calling the method again with the meiMoveAttrModify attribute). The move is finished by using the Motion.Stop command.

Velocity | This type of move has an "S" shape to the acceleration phase. This method uses the JerkPercent argument to decide how much of the acceleration phase is curved. A JerkPercent of zero produces a trapezoidal velocity profile.
VelocityJerk | This type of move has an "S" shape to the acceleration phase. This is the same velocity profile as the Velocity move but this method method has arguments to specify the jerk that is to be used during the acceleration phase.

The following table summarizes the arguments that each of the methods take. The Velocity argument is always required but all the other arguments are optional.

 | Velocity | Accel | JerkPercent | AccelJerk | Attributes
Velocity | * | x | x |  | x
VelocityJerk | * | x |  | x | x

If an optional argument is omitted, the value used is taken from the corresponding properties starting with Default in either the Axis or the Motion objects.

The Attributes argument modifies the default behavior of each of these motions enabling a wide range of variations of the basic motion to be generated. The Attributes argument does not have a corresponding default property and must be specified for each motion.

For example

Before a motion object can be used for any motion it must first be mapped to an axis (or axes). This can be done with the following Visual Basic instruction to allow Motion object 0 to use axis 0.

Controller1.Motion(0).Axes = 0

Initially, the default speed, accel etc. are all zero and need to be given values before any motion will start. The following code sets up the default motion parameters for a velocity move. These instructions only need to be issued once, commonly as the Visual Basic program starts, and are used by all the subsequent motion commands.

Controller1.Motion(0).DefaultAccel = 100000
Controller1.Motion(0).JerkPercent = 50

The following Visual Basic code will start a velocity move on the axis mapped to motion object 0.

Controller1.Motion(0).Velocity 1000

The speed can be changed at any time by issuing the command again using the modify attribute. The acceleration and Jerk Percent used for this change in speed are the defaults set up previously.

Controller1.Motion(0).Velocity 500, attributes:=meiMoveAttrModify

The following stop command will bring the axis to a standstill before terminating the velocity motion. The stop command could be used by itself but the Motion.StopTime property would determine the deceleration.

Controller1.Motion(0).Velocity 0, attributes:=meiMoveAttrModify
Controller1.Motion(0).Stop

See Also

Motion.Velocity
Motion.VelocityJerk
Motion.Stop
Motion.StopTime

meiMoveAttr


MPX Software Documentation Object Home

.

The MEI ActiveX control (MPX) provides a hierarchy of objects. These objects group together related methods (the ActiveX term for a function) and properties (the ActiveX term for a variable) to simplify the access to the control. See the overview of each object for more details.

Controller
 | Axis
 | Motion
 | Map
 | Recorder
Enumerations


Axis Object

.

Axis Object

The Axis object represents the software responsible for controlling a single physical motor. The following figure shows the functionality that the Axis object performs.

Trajectory / Positions
 | ActualPosition ActualVelocity CommandAccel CommandJerk CommandPosition CommandVelocity PositionError Origin
Filter Algorithm
 | FilterAlgorithm FilterCoeff GainTable
Amplifier Enable
 | AmpEnable AmpEnableInvert *
Capture
 | CaptureArm CaptureEdge CaptureIsGlobalTrigger CapturePosition CaptureReset CaptureSourceEnable CaptureSourceLevel CaptureState
Demand
 | DemandLevel
Default Motion Parameters
 | DefaultAccel DefaultDecel DefaultAccelJerk DefaultDecelJerk DefaultJerkPercent DefaultSpeed

Status
 | Status
Events
 | EventEnable EventEnableAll EventEnableNone
I/O
 | DigitalIn DigitalOut DigitalOutInvert IoConfig
Settling
 | SettlingTime TolerancePositionCoarse TolerancePositionFine ToleranceVelocity
Motor
 | MotorType StepLoopback* StepPulseWidth*
Encoder
 | SimEnable *
Flash
 | FlashSave

Limits
 | AmpFaultAction AmpFaultDuration AmpFaultInvert EncoderFaultAction EncoderFaultTrigger * HomeAction HomeSource HomeDuration HomeInvert LimitHwNegAction LimitHwNegDirectionSensitive LimitHwNegDuration LimitHwNegInvert LimitHwPosAction LimitHwPosDirectionSensitive LimitHwPosDuration LimitHwPosInvert LimitPositionError LimitPositionErrorAction LimitPositionErrorDuration LimitSwNeg LimitSwNegAction LimitSwNegDirectionSensitive LimitSwNegDuration LimitSwPos LimitSwPosAction LimitSwPosDirectionSensitive LimitSwPosDuration
 | * - Currently not supported in SynqNet Phase II.


Axis.AmpEnable

MEI Home
.

Axis.AmpEnable

Description

The state of the axis' amplifier enable output. AmpEnable is also changed indirectly by the an Abort call from a Motion object or an Abort action in response to an event.

This property cannot be saved to flash memory.

Type

Boolean

AmpEnable | Description
False | Axis' amplifier is not enabled
True | Axis' amplifier is enabled

Visual Basic Example

Controller.Axis(0).AmpEnable = True

x = Controller.Axis(0).AmpEnable

Syntax

Visual Basic

Property AmpEnable As Boolean
IDL Interface

[propget] HRESULT AmpEnable([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT AmpEnable([in] VARIANT_BOOL newVal)

See Also

AmpEnableInvert

Motion Object
Abort
AmpEnable


Axis.AmpEnableInvert

MEI Home
.

Axis.AmpEnableInvert

Description

Determines whether the controller should invert the logic of the amplifier enable output signal.

AmpEnableInvert | Meaning
False | Normal
True | Inverted

Type

Boolean

Visual Basic Example

x = Controller.Axis(0).AmpEnableInvert

Controller.Axis(0).AmpEnableInvert = True

Syntax

Visual Basic

AmpEnableInvert As Boolean
IDL Interface

[propget] HRESULT AmpEnableInvert([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT AmpEnableInvert([in] VARIANT_BOOL newVal)

See Also

AmpEnable


Axis.CaptureArm

MEI Home
.

Axis.CaptureArm

Description

Specifies whether the axis is ready to capture an encoder position.

This property cannot be saved to flash memory.

For more information about position captures, refer to the Position Capture section of the Encoder Inputs page. See below for link.

Arguments

Argument | Description | Default Value
captureNumber | The number of the capture whose arm state is accessed | 0

Type

Boolean

Visual Basic Example

Controller.Axis(0).CaptureArm Syntax

Syntax

Visual Basic

Property CaptureArm(captureNumber As Long = 0) As Boolean
IDL Interface

HRESULT CaptureArm([in, defaultvalue(0)] long captureNumber,
[out, defaultvalue(0)] VARIANT_BOOL *pVal)

HRESULT CaptureArm([in] boolean newVal,
[in, defaultvalue(0)] long captureNumber)

See Also

CaptureState

Encoder Inputs: Postion Capture


Axis.CaptureEdge

MEI Home
.

Axis.CaptureEdge

Description

Sets the the edge of the capture trigger state on which the capture engine will record the encoder position. See diagram below.

Arguments

Argument | Description | Default Value
captureNumber | The number of the capture to be accessed. | 0

Type

meiCaptureEdge

Visual Basic Example

Controller.Axis(0).CaptureEdge = meiCaptureEdgeRising

Syntax

Visual Basic

Property CaptureEdge(captureNumber As Long = 0) As meiCaptureEdgeRising
IDL Interface

[propget] HRESULT CaptureEdge([in, defaultvalue(0)] long captureNumber,
[out, retval] meiCaptureEdge *pVal)

[propput] HRESULT CaptureEdge([in, defaultvalue(0)] long captureNumber,
[in] meiCaptureEdge newVal)

See Also

CaptureSourceEnable
CaptureSourceLevel
CaptureReset


Axis.CaptureIsGlobalTrigger

MEI Home
.

Axis.CaptureIsGlobalTrigger

Description

Determines whether the global trigger bit is determined from the capture trigger state. See diagram below.

Arguments

Argument | Description | Default Value
captureNumber | The number of the capture to be accessed | 0

Type

Boolean

Visual Basic Example

Controller.Axis(0).CaptureIsGlobalTrigger = True

Syntax

Visual Basic

Property CaptureEdge(captureNumber As Long = 0) As Boolean
IDL Interface

[propget] HRESULT CaptureIsGlobalTrigger([in, defaultvalue(0)] long captureNumber,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT CaptureIsGlobalTrigger([in, defaultvalue(0)] long captureNumber,
[in] VARIANT_BOOL newVal)

See Also

CaptureReset


Axis.CapturePosition

MEI Home
.

Axis.CapturePosition

Description

The encoder position value that was captured when the axis' position capture conditions were met. The captured encoder position can be used in conjunction with the Origin property to:

  • set a the zero position (home position)
  • calculate the ActualPosition value corresponding to the captured encoder position

This property cannot be saved to flash memory.

For more information about position captures, refer to the Position Capture section of the Encoder Inputs page. See below for link.

Arguments

Argument | Description | Default Value
captureNumber | The number of the capture whose position is to be read | 0

Type

Double (read only)

Visual Basic Example

x = Controller.Axis(0).CapturePosition

Syntax

Visual Basic

Property CapturePosition(captureNumber As Long = 0) As Double
IDL Interface

[propget] HRESULT CapturePosition([in, defaultvalue(0)]long captureNumber,
[out, retval] double *pVal)

See Also

CaptureState
Origin

Encoder Inputs: Postion Capture


Axis.CaptureReset

MEI Home
.

Axis.CaptureReset

Description

CaptureReset perfoms the following:

  • Disarms the capture
  • If enabled, disables the triggering of the global trigger bit
  • Sets all capture source levels to false
  • Disables all capture sources
  • Sets the capture edge to meiCaptureEdgeRising

Arguments

Argument | Description | Default Value
captureNumber | The number of the capture to be reset. | 0

Visual Basic Example

Controller.Axis(0).CaptureReset

Syntax

Visual Basic

CaptureReset(captureNumber As Long = 0)
IDL Interface

HRESULT CaptureReset([in, defaultvalue(0)] long captureNumber)

See Also

CaptureArm
CaptureEdge
CaptureSourceEnable
CaptureSourceLevel
CaptureIsGlobalTrigger


Axis.CaptureSourceEnable

MEI Home
.

Axis.CaptureSourceEnable

Description

Enables or disables a particular capture source. See diagram below.

Arguments

Argument | Description | Default Value
meiCaptureSource | The capture source to be accessed. | N/A
captureNumber | The number of the capture to be accessed | 0

Type

Boolean

Visual Basic Example

Controller.Axis(0).CaptureSourceEnable(meiCaptureSourceHome) = True

Syntax

Visual Basic

Property CaptureEdge(meiCaptureSource source, captureNumber As Long = 0) As Boolean
IDL Interface

[propget] HRESULT CaptureSourceEnable([in] meiCaptureSource source,
[in, defaultvalue(0)] long captureNumber,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT CaptureSourceEnable([in] meiCaptureSource source,
[in, defaultvalue(0)] long captureNumber,
[in] VARIANT_BOOL newVal)

See Also

meiCaptureSource

CaptureEdge
CaptureReset


Axis.CaptureSourceLevel

MEI Home
.

Axis.CaptureSourceLevel

Description

Sets the level a particular capture source contributes to the capture trigger state. See diagram below.

Arguments

Argument | Description | Default Value
meiCaptureSource | The capture source to be accessed. | N/A
captureNumber | The number of the capture to be accessed. | 0

Type

Boolean

Visual Basic Example

Controller.Axis(0).CaptureSourceLevel(meiCaptureSourceHome) = True

Syntax

Visual Basic

Property CaptureEdge(meiCaptureSource source, captureNumber As Long = 0) As Boolean
IDL Interface

[propget] HRESULT CaptureSourceLevel([in] meiCaptureSource source,
[in, defaultvalue(0)] long captureNumber,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT CaptureSourceLevel([in] meiCaptureSource source,
[in, defaultvalue(0)] long captureNumber,
[in] VARIANT_BOOL newVal)

See Also

meiCaptureSource

CaptureEdge
CaptureSourceEnable
CaptureReset


Axis.CaptureState

MEI Home
.

Axis.CaptureState

Description

The state of an axis' position capture engine.

This property cannot be saved to flash memory.

For more information about position captures, refer to the Position Capture section of the Encoder Inputs page. See below for link.

Arguments

Argument | Description | Default Value
captureNumber | The capture number whose state is to be read | 0

Type

meiCaptureState (read only)

Visual Basic Example

x = Controller.Axis(0).CaptureState
axis.CaptureState = x

Syntax

Visual Basic

Property CaptureState(captureNumber As Long = 0) As meiCaptureState

IDL Interface

[propget] HRESULT CaptureState([in, defaultvalue(0)] long captureNumber,
[out, retval] meiCaptureState *pVal)

See Also

CaptureArm
meiCaptureState

Encoder Inputs: Postion Capture


Axis.DefaultAccel

MEI Home
.

Axis.DefaultAccel

Description

The default acceleration for an axis during synchronized moves.

This property cannot be saved to flash memory.

Units

counts/sec2

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultAccel = 50000.0

Syntax

Visual Basic

Property DefaultAccel As Double
IDL Interface

[propget] HRESULT DefaultAccel([out, retval] double *pVal)

[propput] HRESULT DefaultAccel([in] double newVal)

See Also

Motion Object:
SCurve
SCurveJerk
Trapezoidal
Velocity
VelocityJerk

Axis Object:
DefaultSpeed
DefaultDecel
DefaultJerkPercent
DefaultAccelJerk
DefaultDecelJerk


Axis.DefaultAccelJerk

MEI Home
.

Axis.DefaultAccelJerk

Description

The default acceleration jerk for an axis during synchronized SCurveJerk and VelocityJerk moves.

This property cannot be saved to flash memory.

Units

counts/sec3

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultAccelJerk = 50000.0

Syntax

Visual Basic

Property DefaultAccelJerk As Double
IDL Interface

[propget] HRESULT DefaultAccelJerk([out, retval] double *pVal)

[propput] HRESULT DefaultAccelJerk([in] double newVal)

See Also

Axis Object:
DefaultSpeed
DefaultAccel
DefaultDecel
DefaultJerkPercent
DefaultDecelJerk

Motion Object:
SCurveJerk
VelocityJerk


Axis.DefaultDecel

MEI Home
.

Axis.DefaultDecel

Description

The default deceleration for an axis during synchronized Trapezoidal, SCurve, and SCurveJerk moves.

This property cannot be saved to flash memory.

Units

counts/sec2

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultDecel = 50000.0

Syntax

Visual Basic

Property DefaultDecel As Double
IDL Interface

[propget] HRESULT DefaultDecel([out, retval] double *pVal)

[propput] HRESULT DefaultDecel([in] double newVal)

See Also

Axis Object:
DefaultSpeed
DefaultAccel
DefaultJerkPercent
DefaultAccelJerk
DefaultDecelJerk

Motion Object:
SCurve
SCurveJerk
Trapezoidal


Axis.DefaultDecelJerk

MEI Home
.

Axis.DefaultDecelJerk

Description

The default deceleration jerk for an axis during synchronized SCurveJerk moves.

This property cannot be saved to flash memory.

Units

counts/sec3

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultDecelJerk = 50000.0

Syntax

Visual Basic

Property EncoderFaultTrigger(trigger As meiEncoderFaultTrigger) As Boolean
IDL Interface

[propget] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[out, retval] bool *pVal)

[propput] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[in] bool newVal)

See Also

Axis Object:
DefaultSpeed
DefaultAccel
DefaultDecel
DefaultJerkPercent
DefaultAccelJerk

Motion Object:
SCurveJerk


Axis.DefaultJerkPercent

MEI Home
.

Axis.DefaultJerkPercent

Description

The default jerk percent for an axis during synchronized SCurve and Velocity moves. The valid range for DefaultJerkPercent is [0, 100].

This property cannot be saved to flash memory.

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultJerkPercent = 50.0

Syntax

Visual Basic

Property DefaultJerkPercent As Double
IDL Interface

[propget] HRESULT DefaultJerkPercent([out, retval] double *pVal)

[propput] HRESULT DefaultJerkPercent([in] double newVal)

See Also

Axis Object:
DefaultSpeed
DefaultAccel
DefaultDecel
DefaultAccelJerk
DefaultDecelJerk

Motion Object:
SCurve
Velocity


Axis.DefaultSpeed

MEI Home
.

Axis.DefaultSpeed

Description

The default maximum speed for an axis during single axis and synchronized Trapezoidal, SCurve, and SCurveJerk moves.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Double

Default

0.0

Visual Basic Example

Controller.Axis(0).DefaultSpeed = 5000.0

Syntax

Visual Basic

Property EncoderFaultTrigger(trigger As meiEncoderFaultTrigger) As Boolean
IDL Interface

[propget] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[out, retval] bool *pVal)

[propput] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[in] bool newVal)

See Also

Axis Object:
DefaultAccel
DefaultDecel
DefaultJerkPercent
DefaultAccelJerk
DefaultDecelJerk

Motion Object:
SCurve
SCurveJerk
Trapezoidal


Axis.DemandLevel

MEI Home
.

Axis.DemandLevel

Description

The range of the demand output is [-32768, 32767].

This property cannot be saved to flash memory.

Units

1/3276.8 Volt for analog controllers.

Arguments

Argument | Type | Description
demand | meiDemand | The demand output to reset

Type

Double (read only)

Sample Code

x = Controller.Axis(0).DemandLevel

Syntax

Visual Basic

Property DemandLevel(demand = meiDemandOutput As meiDemand) As Double
IDL Interface

[propget] HRESULT DemandLevel(
[in, defaultvalue(meiDemandOutput)] meiDemand demand,
[out, retval] double *pVal)

See Also

meiDemand


Axis.SimEnable

MEI Home
.

Axis.SimEnable

Description

Specifies whether the Sim4 (an optional sinusoidal interpolation module for encoders) is enabled. When a Sim module is enabled, the encoder position is determined from the Sim module, not the controller's quadrature decoder.

Please refer to the SIM4 Application Note for more information on the operation of a SIM4 module.

Type

Boolean

Visual Basic Example

' Enable Sim Module
Controller.Axis(0).SimEnable = True

Syntax

Visual Basic

Property SimEnable As Boolean
IDL Interface

[propget] HRESULT SimEnable([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT SimEnable([in] VARIANT_BOOL pVal)

See Also

SIM4 Application Note


Axis.EventEnable

MEI Home
.

Axis.EventEnable

Description

Enables or disables any of the events that are generated by the axis object from being reported to the host. Please refer to the events overview section for a list of events generated by the axis object.

Arguments

Argument | Type | Description
eventType | meiEventType | The type of event to be accessed

Type

Boolean

Visual Basic Example

Controller.Axis(0).EventEnable(meiEventTypeLimitHwPos) = True

Syntax

Visual Basic

Property EventEnable(eventType As meiEventType) As Boolean
IDL Interface

[propget] HRESULT EventEnable([in] meiEventType eventType,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT EventEnable([in] meiEventType eventType,
[in] VARIANT_BOOL newVal)

See Also

EventEnableAll
EventEnableNone

meiEventType

Events Overview


Axis.EventEnableAll

MEI Home
.

Axis.EventEnableAll

Description

Enables reporting of all events generated by the axis object to the host. Please refer to the events overview section for a list of events generated by the axis object.

Visual Basic Example

Controller.Axis(0).EventEnableAll

Syntax

Visual Basic

Sub EventEnableAll
IDL Interface

HRESULT EventEnableAll()

See Also

EventEnable
EventEnableNone

meiEventType

Events Overview


Axis.EventEnableNone

MEI Home
.

Axis.EventEnableNone

Description

Disables reporting of all events generated by the axis object to the host. Please refer to the events overview section for a list of events generated by the axis object.

Visual Basic Example

Controller.Axis(0).EventEnableNone

Syntax

Visual Basic

Sub EventEnableNone
IDL Interface

HRESULT EventEnableNone()

See Also

EventEnable
EventEnableAll

meiEventType

Events Overview


Axis.FilterAlgorithm

MEI Home
.

Axis.FilterAlgorithm

Description

The servo filter algorithm of an axis. Servo filter algorithms require a number of user specified parameters. Systems must be tuned to find the proper parameters for a particular algorithm. Please refer to the Servo Algorithm Overview and Tuning Guides for more information.

Value | Description
meiFilterAlgorithmNone | No control algorithm. Can use with stepper motors.
meiFilterAlgorithmPID | PID algorithm
meiFilterAlgorithmPIV | PIV algorithm
meiFilterAlgorithmUser | User algorithm implemented with the Firmware Development Kit

Type

meiFilterAlgorithm

Visual Basic Example

Controller.Axis(0).FilterAlgorithm = meiFilterAlgorithmPID

x = Controller.Axis(0).FilterAlgorithm

Syntax

Visual Basic

Property FilterAlgorithm As meiFilterAlgorithm
IDL Interface

[propget] HRESULT FilterAlgorithm([out, retval] meiFilterAlgorithm *pVal)

[propput] HRESULT FilterAlgorithm([in] meiFilterAlgorithm newVal)

See Also

FilterCoeff
GainTable

meiFilterAlgorithm

XMP Servo Algorithms


Axis.FilterCoeff

MEI Home
.

Axis.FilterCoeff

Description

Specifies the value for a particular control algorithm coefficient of an axis. Systems must be tuned to find the proper parameters for a particular algorithm. Please refer to the Servo Algorithm Overview and Tuning Guides for more information.

Arguments

Argument | Type | Description
coeff | meiFilterCoeff | The algorithm coefficient to be accessed
gainTable | Long | The gain table of the coefficient to be accessed

Type

Double

Visual Basic Example

x = Controller.Axis(0).FilterCoeff(meiFilterCoeffPidKp)

Controller.Axis(0).FilterCoeff(meiFilterCoeffPidKp) = x

Syntax

Visual Basic

Property FilterCoeff(coeff As meiFilterCoeff,
gainTable As Long = 0) As Double

IDL Interface

[propget] HRESULT FilterCoeff([in] meiFilterCoeff coeff,
[in, defaultvalue(0)] long gainTable,
[out, retval] double *pVal)

[propput] HRESULT FilterCoeff([in] meiFilterCoeff coeff,
[in] double newVal,
[in, defaultvalue(0)] long gainTable)

See Also

FilterAlgorithm
GainTable

meiFilterCoeff

XMP Servo Algorithms


Axis.GainTable

MEI Home
.

Axis.GainTable

Description

Specifies the table of gains to be used by the PID and PIV filter algorithm. Please refer to the Servo Algorithm Overview and Tuning Guides for more information.

Type

Long

Visual Basic Example

oldTable = Controller.Axis(0).GainTable

Controller.Axis(0).GainTable = newTable

Syntax

Visual Basic

Property GainTable As Long
IDL Interface

[propget] HRESULT GainTable([out, retval] long *pVal)

[propput] HRESULT GainTable([in] long newVal)

See Also

FilterAlgorithm
FilterCoeff

XMP Servo Algorithms

Tuning Overview


Axis.FlashSave

MEI Home
.

Axis.FlashSave

Description

Saves the current axis object settings to flash memory. This configuration will be loaded onto the controller during the next power up or controller reset.

Visual Basic Example

Controller.Axis(0).FlashSave

Syntax

Visual Basic

Sub FlashSave()
IDL Interface

HRESULT FlashSave()

See Also

Controller Object:
FlashSave
FlashSaveAll

Motion Object:
FlashSave


Axis.DigitalIn

MEI Home
.

Axis.DigitalIn

Description

The state of an axis input.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description
bit | meiInput | The axis input bit whose state is to be read

Type

Boolean (read only)

Sample Code

x = Controller.Axis(0).DigitalIn(meiInputIo3)

Syntax

Visual Basic

Property DigitalIn(bit As meiInput) As Boolean

IDL Interface

[propget] HRESULT DigitalIn([in] meiInput bit,
[out, retval] VARIANT_BOOL *pVal)

See Also

DigitalOut
DigitalOutInvert
IoConfig

meiInput


Axis.DigitalOut

MEI Home
.

Axis.DigitalOut

Description

The state of an axis output.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description
bit | meiOutput | The axis output bit whose state is to be accessed

Type

Boolean

Sample Code

Controller.Axis(0).DigitalOut(meiOutputIo3) = False

Syntax

Visual Basic

Property DigitalOut(bit As meiOutput) As Boolean
IDL Interface

[propget] HRESULT DigitalOut([in] meiOutput bit,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT DigitalOut([in] meiOutput bit,
[in] VARIANT_BOOL newVal)

See Also

DigitalIn
DigitalOutInvert
XcvrConfig

meiOutput


Axis.DigitalOutInvert

MEI Home
.

Axis.DigitalOutInvert

Description

Determines whether the controller should invert the logic of the specified output signal.

DigitalOutInvert | Meaning
False | signal not inverted
True | signal inverted

Arguments

Argument | Type | Description
bit | meiOutput | The axis output bit whose inverted state is to be accessed

Type

Boolean

Visual Basic Example

Controller.Axis(0).DigitalOutInvert(meiOutputIo0) = False

Syntax

Visual Basic

Property DigitalOutInvert(bit As meiOutput) As Boolean
IDL Interface

[propget] HRESULT DigitalOutInvert([in] meiOutput bit,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT DigitalOutInvert([in] meiOutput bit,
[in] VARIANT_BOOL newVal)

See Also

DigitalIn
DigitalOut


Axis.IoConfig

MEI Home
.

Axis.IoConfig

Description

Specifies the configuration of general purpose motor I/O.

Arguments

Argument | Type | Meaning
bit | meiMotorIo | The I/O bit whose configuration is to be read or written

Type

meiIoConfig

Visual Basic Example

Controller.Axis(0).IoConfig(meiMotorIo0) = x

x = Controller.Axis(0).IoConfig(meiMotorIo0)

Syntax

Visual Basic

Property IoConfig(bit As meiMotorIo) As meiIoConfig
IDL Interface

[propget] HRESULT IoConfig([in] meiMotorIo bit,
[out, retval] meiXcvrConfig *pVal)

[propput] HRESULT IoConfig([in] meiMotorIo bit,
[in] meiIoConfig newVal)

See Also

DigitalIn
DigitalOut
DigitalOutInvert

meiMotorIo
meiIoConfig


Axis.AmpFaultAction

MEI Home
.

Axis.AmpFaultAction

Description

The action to be taken when AmpFault status changes from false to true.

Type

meiAction

Sample Code

' Make sure amplifier fault action
        is not none
If Controller.Axis(0).AmpFaultAction = meiActionNone
Then Controller.Axis(0).AmpFaultAction = meiActionAbort
End If

Syntax

Visual Basic

Property AmpFaultAction As meiAction
IDL Interface

[propget] HRESULT AmpFaultAction([out, retval] meiAction *pVal)

[propput] HRESULT AmpFaultAction([in] meiAction newVal)

See Also

meiAction


Axis.AmpFaultDuration

MEI Home
.

Axis.AmpFaultDuration

Description

The amount of time that the amplifier fault input must be true before AmpFault status becomes true and an event of type meiEventTypeAmpFault is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).AmpFaultDuration = .05

Syntax

Visual Basic

Property AmpFaultDuration As Double
IDL Interface

[propget] HRESULT AmpFaultDuration([out, retval] double *pVal)

[propput] HRESULT AmpFaultDuration([in] double newVal)

See Also

AmpFaultAction


Axis.AmpFaultInvert

MEI Home
.

Axis.AmpFaultInvert

Description

Determines whether the controller should invert the logic of the amplifier fault input signal.

AmpFaultInvert | Meaning
True | Inverted
False | Normal

Type

Boolean

Visual Basic Example

Controller.Axis(0).AmpFaultInvert = True
x = Controller.Axis(0).AmpFaultInvert

Syntax

Visual Basic

Property AmpFaultInvert As Boolean
IDL Interface

[propget] HRESULT AmpFaultInvert([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT AmpFaultInvert([in] VARIANT_BOOL newVal)

See Also

AmpFaultAction


Axis.EncoderFaultAction

MEI Home
.

Axis.EncoderFaultAction

Description

The action to be taken when EncoderFault status changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).EncoderFaultAction = meiActionAbort

Syntax

Visual Basic

Property EncoderFaultAction As meiAction
IDL Interface

[propget] HRESULT EncoderFaultAction([out, retval] meiAction *pVal)

[propput] HRESULT EncoderFaultAction([in] meiAction newVal)

See Also

meiAction


Axis.EncoderFaultTrigger

MEI Home
.

Axis.EncoderFaultTrigger

Description

Specifies which encoder events will generate an encoder fault event.

Arguments

trigger | Description
meiEncoderFaultTriggerBrokenWire | Determines whether one of the encoder lines is broken or not connected to either the encoder of controller
meiEncoderFaultTriggerIllegalState | Determines whether the states of the A and B encoder signals change simultaneously
meiEncoderFaultTriggerAbsolute | Determines whether an absolute encoder has produced a fault

Type

Boolean

Visual Basic Example

xAxis.EncoderFaultTrigger(meiEncoderFaultTriggerAbsolute) = False

Syntax

Visual Basic

Property EncoderFaultTrigger(trigger As meiEncoderFaultTrigger) As Boolean

IDL Interface

[propget] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT EncoderFaultTrigger([in]meiEncoderFaultTrigger trigger,
[in] VARIANT_BOOL newVal)

See Also

EncoderFaultAction

meiEncoderFaultTrigger


Axis.HomeAction

MEI Home
.

Axis.HomeAction

Description

The action to be taken when Home status changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).HomeAction = meiActionEStop

Syntax

Visual Basic

Property HomeAction As meiAction
IDL Interface

[propget] HRESULT HomeAction([out, retval] meiAction *pVal)

[propput] HRESULT HomeAction([in] meiAction newVal)

See Also

HomeSource

meiAction


Axis.HomeDuration

MEI Home
.

Axis.HomeDuration

Description

The amount of time that home event condition must be true before Home status becomes true and an event of type meiEventTypeHome is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).HomeDuration = .05

Syntax

Visual Basic

Property HomeDuration As Double

IDL Interface

[propget] HRESULT HomeDuration([out, retval] double *pVal)

[propput] HRESULT HomeDuration([in] double newVal)

See Also

HomeAction


Axis.HomeInvert

MEI Home
.

Axis.HomeInvert

Description

Determines whether the controller should invert the logic of the home input signal.

HomeInvert | Meaning
False | Normal
True | Inverted

NOTE: HomeInvert cannot be set to fasle when HomeSource = meiHomeSourceCapture.

Type

Boolean

Visual Basic Example

Controller.Axis(0).HomeInvert = False

Syntax

Visual Basic

Property HomeInvert As Boolean
IDL Interface

[propget] HRESULT HomeInvert([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT HomeInvert([in] VARIANT_BOOL newVal)

See Also

HomeAction


Axis.HomeSource

MEI Home
.

Axis.HomeSource

Description

Specifies whether the home status should be determined from the home input or the capture state.

Configuration | Description
meiHomeSourceCapture | Home status is synonymous to CaptureState. HomeInvert has no effect in this configuration.
meiHomeSourceIo | Home status is determined from the home input and HomeInvert.

NOTE: Setting HomeSource to meiHomeSourceCapture will set HomeInvert to true.

Type

meiHomeSource

Visual Basic Example

Controller.Axis(0).HomeSource = meiHomeSourceIo

Syntax

Visual Basic

Property HomeSource As meiHomeSource
IDL Interface

[propget] HRESULT HomeSource([out, retval] meiHomeSource *pVal)

[propput] HRESULT HomeSource([in] meiHomeSource newVal)

See Also

CaptureState
HomeAction


Axis.LimitHwNegAction

MEI Home
.

Axis.LimitHwNegAction

Description

The action to be taken when LimitHwNeg status changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).LimitHwNegAction = meiActionEStopAbort

Syntax

Visual Basic

Property LimitHwNegAction As meiAction

IDL Interface

[propget] HRESULT LimitHwNegAction([out, retval] meiAction *pVal)

[propput] HRESULT LimitHwNegAction([in] meiAction newVal)

See Also

meiAction


Axis.LimitHwNegDirectionSensitive

MEI Home
.

Axis.LimitHwNegDirectionSensitive

Description

Determines whether the negative hardware limit should be direction sensitive. If LimitHwNegDirectionSensitive is False, then LimitHwNegAction will need to be set to meiActionNone in order to back out of the negative hardware limit.

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitHwNegDirectionSensitive = False

Syntax

Visual Basic

Property LimitHwNegDirectionSensitive As Boolean
IDL Interface

[propget] HRESULT LimitHwNegDirectionSensitive([out, retval]
VARIANT_BOOL *pVal)

[propput] HRESULT LimitHwNegDirectionSensitive([in] VARIANT_BOOL newVal)

See Also

LimitHwNegAction
LimitHwNegInvert


Axis.LimitHwNegDuration

MEI Home
.

Axis.LimitHwNegDuration

Description

The amount of time that the negative hardware limit input must be true before LimiHwNeg status becomes true and an event of type meiEventTypeLimitHwNeg is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).LimitHwNegDuration = .05

Syntax

Visual Basic

Property LimitHwNegDuration As Double
IDL Interface

[propget] HRESULT LimitHwNegDuration([out, retval] double *pVal)

[propput] HRESULT LimitHwNegDuration([in] double newVal)

See Also

LimitHwNegAction


Axis.LimitHwNegInvert

MEI Home
.

Axis.LimitHwNegInvert

Description

Determines whether the controller should invert the logic of the negative hardware limit input signal.

LimitHwNegInvert | Meaning
False | Normal
True | Inverted

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitHwNegInvert = True

Syntax

Visual Basic

Property LimitHwNegInvert As Boolean
IDL Interface

[propget] HRESULT LimitHwNegInvert([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT LimitHwNegInvert([in] VARIANT_BOOL newVal)

See Also

LimitHwNegAction


Axis.LimitHwPosAction

MEI Home
.

Axis.LimitHwPosAction

Description

The action to be taken when LimitHwPos status changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).LimitHwPosAction = meiActionEStopAbort

Syntax

Visual Basic

Property LimitHwPosAction As meiAction
IDL Interface

[propget] HRESULT LimitHwPosAction([out, retval] meiAction *pVal)

[propput] HRESULT LimitHwPosAction([in] meiAction newVal)

See Also

meiAction


Axis.LimitHwPosDirectionSensitive

MEI Home
.

Axis.LimitHwPosDirectionSensitive

Description

Determines whether the positive hardware limit should be direction sensitive.

If LimitHwPosDirectionSensitive is False, then LimitHwPosAction will need to be set to meiActionNone in order to back out of the positive hardware limit.

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitHwPosDirectionSensitive = False

Syntax

Visual Basic

Property LimitHwPosDirectionSensitive As Boolean
IDL Interface

[propget] HRESULT LimitHwPosDirectionSensitive([out, retval]
VARIANT_BOOL *pVal)

[propput] HRESULT LimitHwPosDirectionSensitive([in] VARIANT_BOOL newVal)

See Also

LimitHwPosAction
LimitHwPosInvert


Axis.LimitHwPosDuration

MEI Home
.

Axis.LimitHwPosDuration

Description

The amount of time that the positive hardware limit input must be true before LimitHwNeg status becomes true and an event of type meiEventTypeLimitHwNeg is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).LimitHwPosDuration = .05

Syntax

Visual Basic

Property LimitHwPosDuration As Double
IDL Interface

[propget] HRESULT LimitHwPosDuration([out, retval] double *pVal)

[propput] HRESULT LimitHwPosDuration([in] double newVal)

See Also

LimitHwNegAction


Axis.LimitHwPosInvert

MEI Home
.

Axis.LimitHwPosInvert

Description

Determines whether the controller should invert the logic of the positive hardware limit input signal.

LimitHwPosInvert | Meaning
False | Normal
True | Inverted

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitHwPosInvert = True

Syntax

Visual Basic

Property LimitHwPosInvert As Boolean
IDL Interface

[propget] HRESULT LimitHwPosInvert([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT LimitHwPosInvert([in] VARIANT_BOOL newVal)

See Also

LimitHwPosAction


Axis.LimitPositionError

MEI Home
.

Axis.LimitPositionError

Description

The magnitude limit of valid values for PositionError. If the absoluter value of PositionError exceeds this value, then LimitPositionError status is true, otherwise LimitPositionError status is false.

Type

Double

Visual Basic Example

Controller.Axis(0).LimitPositionError = 5000.0

Syntax

Visual Basic

Property LimitPositionError As Double
IDL Interface

[propget] HRESULT LimitPositionError([out, retval] double *pVal)

[propput] HRESULT LimitPositionError([in] double newVal)

See Also

LimitPositionErrorAction
PositionError


Axis.LimitPositionErrorAction

MEI Home
.

Axis.LimitPositionErrorAction

Description

The action to be taken when LimitPositionError status changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).LimitPositionErrorAction = meiActionEStopAbort

Syntax

Visual Basic

Property LimitPositionErrorAction As meiAction
IDL Interface

[propget] HRESULT LimitPositionErrorAction([out, retval] meiAction *pVal)

[propput] HRESULT LimitPositionErrorAction([in] meiAction newVal)

See Also

LimitPositionError

meiAction


Axis.LimitPositionErrorDuration

MEI Home
.

Axis.LimitPositionErrorDuration

Description

The amount of time that PositionError must exceed LimitPositionError before LimitPositionError status becomes true and an event of type meiEventTypeLimitError is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).LimitPositionErrorDuration = .05

Syntax

Visual Basic

Property LimitPositionErrorDuration As Double
IDL Interface

[propget] HRESULT LimitPositionErrorDuration([out, retval] double *pVal)

[propput] HRESULT LimitPositionErrorDuration([in] double newVal)

See Also

LimitPositionErrorAction


Axis.LimitSwNeg

MEI Home
.

Axis.LimitSwNeg

Description

The lower limit of valid values for ActualPosition. If ActualPosition exceeds this value, then LimitSwNeg status is true, otherwise LimitSwNeg status is false.

Type

Double

Visual Basic Example

Controller.Axis(0).LimitSwNeg = -50000000.0

Syntax

Visual Basic

Property LimitSwNeg As Double
IDL Interface

[propget] HRESULT LimitSwNeg([out, retval] double *pVal)

[propput] HRESULT LimitSwNeg([in] double newVal)

See Also

ActualPosition
LimitSwNegAction


Axis.LimitSwNegAction

MEI Home
.

Axis.LimitSwNegAction

Description

The action to be taken when LimitSwNegState changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).LimitSwNegAction = meiActionEStopAbort

Syntax

Visual Basic

Property LimitSwNegAction As meiAction
IDL Interface

[propget] HRESULT LimitSwNegAction([out, retval] meiAction *pVal)

[propput] HRESULT LimitSwNegAction([in] meiAction newVal)

See Also

LimitSwNeg
meiAction


Axis.LimitSwNegDirectionSensitive

MEI Home
.

Axis.LimitSwNegDirectionSensitive

Description

Determines whether the negative software limit should be direction sensitive.

If LimitSwNegDirectionSensitive is False, then LimitHwNegAction will need to be set to meiActionNone in order to back out of the negative software limit.

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitSwNegDirectionSensitive = False

Syntax

Visual Basic

Property LimitSwNegDirectionSensitive As Boolean
IDL Interface

[propget] HRESULT LimitSwNegDirectionSensitive([out, retval]
VARIANT_BOOL *pVal)

[propput] HRESULT LimitSwNegDirectionSensitive([in] VARIANT_BOOL newVal)

See Also

LimitSwNegAction


Axis.LimitSwNegDuration

MEI Home
.

Axis.LimitSwNegDuration

Description

The amount of time that ActualPosition must exceed LimitSwNeg before LimitSwNegState becomes true and an event of type meiEventTypeLimitSwNeg is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).LimitSwNegDuration = .05

Syntax

Visual Basic

Property LimitSwNegDuration As Double
IDL Interface

[propget] HRESULT LimitSwNegDuration([out, retval] double *pVal)

[propput] HRESULT LimitSwNegDuration([in] double newVal)

See Also

LimitSwNegAction


Axis.LimitSwPos

MEI Home
.

Axis.LimitSwPos

Description

The upper limit of valid values for ActualPosition.

If ActualPosition exceeds this value, then LimitSwPos status is true, otherwise LimitSwPos status is false.

Type

Double

Visual Basic Example

Controller.Axis(0).LimitSwPos = 50000000.0

Syntax

Visual Basic

Property LimitSwPos As Double
IDL Interface

[propget] HRESULT LimitSwPos([out, retval] double *pVal)

[propput] HRESULT LimitSwPos([in] double newVal)

See Also

ActualPosition
LimitSwPosAction


Axis.LimitSwPosAction

MEI Home
.

Axis.LimitSwPosAction

Description

The action to be taken when LimitSwPosState changes from false to true.

Type

meiAction

Visual Basic Example

Controller.Axis(0).LimitSwPosAction = meiActionEStopAbort

Syntax

Visual Basic

Property LimitSwPosAction As meiAction
IDL Interface

[propget] HRESULT LimitSwPosAction([out, retval] meiAction *pVal)

[propput] HRESULT LimitSwPosAction([in] meiAction newVal)

See Also

LimitSwPos

meiAction


Axis.LimitSwPosDirectionSensitive

MEI Home
.

Axis.LimitSwPosDirectionSensitive

Description

Determines whether the positive software limit should be direction sensitive.

If LimitSwPosDirectionSensitive is False, then LimitHwNegAction will need to be set to meiActionNone in order to back out of the positive software limit.

Type

Boolean

Visual Basic Example

Controller.Axis(0).LimitSwPosDirectionSensitive = False

Syntax

Visual Basic

Property EncoderFaultTrigger(trigger As meiEncoderFaultTrigger) As Boolean
IDL Interface

[propget] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[in] VARIANT_BOOL newVal)

See Also

LimitSwPosAction


Axis.LimitSwPosDuration

MEI Home
.

Axis.LimitSwPosDuration

Description

The amount of time that ActualPosition must exceed LimitSwPos before LimitSwPos status becomes true and an event of type meiEventTypeLimitSwPos is generated.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).LimitSwPosDuration = .05

Syntax

Visual Basic

Property LimitSwPosDuration As Double
IDL Interface

[propget] HRESULT LimitSwPosDuration([out, retval] double *pVal)

[propput] HRESULT LimitSwPosDuration([in] double newVal)

See Also

LimitSwPosAction


Axis.MotorType

MEI Home
.

Axis.MotorType

Description

The type of motor to be controlled Servo motors must be tuned and sercos drives configured before they will function properly. Configuring an axis for use as a stepper motor in step loopback mode is a useful way of simulating an axis without a motor. When MotorType is set to meiMotorTypeStepper, any axis control algorithm will still execute sending the output to the DACs on analog controllers.

NOTE: Having the control algorithm still running does not affect the stepper motor outputs. Please refer to the tuning overview, the overview of stepper motor connections, and the Sercos application note for more information.

Type

meiMotorType

Visual Basic Example

' Configure axis to use a stepper motor
Controller.Axis(0).MotorType = meiMotorTypeStepper

Syntax

Visual Basic

Property MotorType As meiMotorType
IDL Interface

[propget] HRESULT MotorType([out, retval] meiMotorType *pVal)

[propput] HRESULT MotorType([in] meiMotorType newVal)

See Also

StepLoopback
StepPulseWidth

meiMotorType

Tuning Overview
Overview of Stepper Motor Connections
Sercos Application Note


Axis.StepLoopback

MEI Home
.

Axis.StepLoopback

Description

Specifies whether the controller will use the stepper motor outputs as virtual encoder feedback. Configuring an axis for use as a stepper motor in step loopback mode is a useful way of simulating an axis without a motor.

Please refer to the overview of stepper motor connections for more information.

Type

Boolean

Visual Basic Example

' Configure axis to use stepper motor loopback
Controller.Axis(0).StepLoopback = True

Syntax

Visual Basic

Property StepLoopback As Boolean
IDL Interface

[propget] HRESULT StepLoopback([out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT StepLoopback([in] VARIANT_BOOL newVal)

See Also

MotorType
StepPulseWidth

Overview of Stepper Motor Connections


Axis.StepPulseWidth

MEI Home
.

Axis.StepPulseWidth

Description

Specifies the pulse widths of stepper clockwise, counter-clockwise, and step outputs.

Please see the specifications for Step/Dir & CW/CCW pulses for more information.

Type

Double

Visual Basic Example

' Configure axis to use a stepper pulse width of 1us
Controller.Axis(0).StepPulseWidth = .000001;

Syntax

Visual Basic

Property StepPulseWidth As Double
IDL Interface

[propget] HRESULT StepPulseWidth([out, retval] double *pVal)

[propput] HRESULT StepPulseWidth([in] double newVal)

See Also

MotorType
StepLoopback

Stepper Motor Pulse Specifications


Axis.SettlingTime

MEI Home
.

Axis.SettlingTime

Description

The time for which all settling conditions must be met before a motion for an axis is considered complete.

Units

seconds

Type

Double

Visual Basic Example

Controller.Axis(0).SettlingTime = .005 '5 milliseconds

Syntax

Visual Basic

Property SettlingTime As Double
IDL Interface

[propget] HRESULT SettlingTime([out, retval] double *pVal)

[propput] HRESULT SettlingTime([in] double newVal)

See Also

TolerancePositionCoarse
TolerancePositionFine
ToleranceVelocity

Motion Related Events


Axis.TolerancePositionCoarse

MEI Home
.

Axis.TolerancePositionCoarse

Description

An axis will generate an event of type meiEventTypeInPositionCoarse when the absolute value of PositionError is less than or equal to TolerancePositionCoarse.

Units

counts

Type

Double

Visual Basic Example

Controller.Axis(0).TolerancePositionCoarse = 200

Syntax

Visual Basic

Property TolerancePositionCoarse As Double
IDL Interface

[propget] HRESULT TolerancePositionCoarse([out, retval] double *pVal)

[propput] HRESULT TolerancePositionCoarse([in] double newVal)

See Also

TolerancePositionFine
ToleranceVelocity

Motion Related Events


Axis.TolerancePositionFine

MEI Home
.

Axis.TolerancePositionFine

Description

An axis will generate an event of type meiEventTypeSettled when the absolute value of PositionError is less than or equal to TolerancePositionCoarse and ActualVelocity is less than or equal to ToleranceVelocity.

Units

counts

Type

Double

Visual Basic Example

Controller.Axis(0).TolerancePositionFine = 100

Syntax

Visual Basic

Property TolerancePositionFine As Double
IDL Interface

[propget] HRESULT TolerancePositionFine([out, retval] double *pVal)

[propput] HRESULT TolerancePositionFine([in] double newVal)

See Also

TolerancePositionCoarse
ToleranceVelocity

Motion Related Events


Axis.ToleranceVelocity

MEI Home
.

Axis.ToleranceVelocity

Description

The maximum velocity at which:

  • An axis can report an in fine position event
  • An axis can settle

Units

counts/sec

Type

Double

Visual Basic Example

Controller.Axis(0).ToleranceVelocity = 5000.0

Syntax

Visual Basic

Property ToleranceVelocity As Double
IDL Interface

[propget] HRESULT ToleranceVelocity([out, retval] double *pVal)

[propput] HRESULT ToleranceVelocity([in] double newVal)

See Also

TolerancePositionCoarse
TolerancePositionFine

Motion Related Events


Axis.Status

MEI Home
.

Axis.Status

Description

Reports whether the conditions necessary for generating the specified event are met or have been met. The status of some events latch meaning that Status will report if the event's conditions have been met. The status of other events are real time meaning that Status will report if the event's conditions are currently being met.

NOTE: Many events have actions associated with them. Event reporting does not have to be enabled in order for these actions to be generated on the controller. In other words, it is possible to not report a home event, but to generate a STOP command when the home event's conditions are met.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description
Type | meiStatus | The type of event whose related status bit is being read.

Type

Boolean (read only)

Visual Basic Example

x = Controller.Axis(3).Status(meiStatusHome)

Syntax

Visual Basic

Property Status(Type As meiStatus) As Boolean
IDL Interface

[propget] HRESULT Status([in] meiStatus Type,
[out, retval] VARIANT_BOOL *pVal)

See Also

EventEnable

meiStatus


Axis.ActualPosition

MEI Home
.

Axis.ActualPosition

Description

The position feedback of the axis. When one writes to ActualPosition, the Origin is changed to produce the desired result. This way the position error will remain constant.

This property cannot be saved to flash memory.

Units

Counts

Type

Double

Visual Basic Example

' Set the current position to 0 (Home)
Controller.Axis(0).ActualPosition = 0

' Update display
lblActualPosition.Caption = Controller.Axis(0).ActualPosition

Syntax

Visual Basic

Property ActualPosition As Double
IDL Interface

[propget] HRESULT ActualPosition([out, retval] double *pVal)

[propput] HRESULT ActualPosition([in] double newVal)

See Also

CommandPosition
PositionError


Axis.ActualVelocity

MEI Home
.

Axis.ActualVelocity

Description

The velocity feedback of an axis. This quantity is defined as the change in ActualPosition between servo cycles multiplied by the sample rate.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Double (read only)

Visual Basic Example

' Update display
lblActualVelocity.Caption = Controller.Axis(0).ActualVelocity

Syntax

Visual Basic

Property ActualPosition As Double
IDL Interface

[propget] double ActualVelocity([out, retval] double *pVal)

See Also

ActualPosition
CommandVelocity


Axis.CommandAccel

MEI Home
.

Axis.CommandAccel

Description

The command acceleration of an axis.

This property cannot be saved to flash memory.

Units

counts/sec2

Type

Double (read only)

Visual Basic Example

' Update display
lblCommandAccel.Caption = Controller.Axis(0).CommandAccel

Syntax

Visual Basic

Property CommandAccel As Double
IDL Interface

[propget] HRESULT CommandAccel([out, retval] double *pVal)

See Also

CommandJerk
CommandVelocity


Axis.CommandJerk

MEI Home
.

Axis.CommandJerk

Description

The command jerk of an axis.

This property cannot be saved to flash memory.

Units

counts/sec3

Type

Double (read only)

Visual Basic Example

' Update display
lblCommandJerk.Caption = Controller.Axis(0).CommandJerk

Syntax

Visual Basic

Property CommandJerk As Double
IDL Interface

[propget] HRESULT CommandJerk([out, retval] double *pVal)

See Also

CommandAccel


Axis.CommandPosition

MEI Home
.

Axis.CommandPosition

Description

The commanded position of the axis. This quantity represents the current desired position of the axis. It does not represent the target (end) position of a move. When one writes to CommandPosition, it results in a step change of CommandPosition and PositionError.

This property cannot be saved to flash memory.

Units

counts

Type

Double

Visual Basic Example

' Update display
lblCommandPosition.Caption = Controller.Axis(0).CommandPosition

Syntax

Visual Basic

Property CommandPosition As Double
IDL Interface

[propget] HRESULT CommandPosition([out, retval] double *pVal)

[propput] HRESULT CommandPosition([in] double newVal)

See Also

ActualPosition
PositionError


Axis.CommandVelocity

MEI Home
.

Axis.CommandVelocity

Description

The command velocity of an axis.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Double (read only)

Visual Basic Example

' Update display
lblCommandVelocity.Caption = Controller.Axis(0).CommandVelocity

Syntax

Visual Basic

Property CommandVelocity As Double
IDL Interface

[propget] HRESULT CommandVelocity([out, retval] double *pVal)

See Also

CommandPosition
CommandJerk


Axis.Origin

MEI Home
.

Axis.Origin

Description

The encoder position where the actual position reads zero. Settting Origin will result in changes to both ActualPosition and CommandPosition, but will not result in any change of PositionError. Please refer to the origin overview in the software manual for more information.

This property cannot be saved to flash memory.

Units

counts

Type

Double

Visual Basic Example

' Have the actual position be identical to the encoder position Controller.Axis(0).Origin = 0

Syntax

Visual Basic

Property Origin As Double
IDL Interface

[propget] HRESULT Origin([out, retval] double *pVal)

[propput] HRESULT Origin([in] double newVal)

See Also

ActualPosition
CapturePosition


Axis.PositionError

MEI Home
.

Axis.PositionError

Description

The difference between the current command and actual positions.

This property cannot be saved to flash memory.

Units

counts

Type

Double (read only)

Visual Basic Example

lblPositionError.Caption = Controller.Axis(0).PositionError

Syntax

Visual Basic

Property PositionError As Double
IDL Interface

[propget] HRESULT PositionError([out, retval] double *pVal)

See Also

ActualPosition
CommandPosition


Controller Object

.

Controller Object

Each instance of a Controller object represents a single MEI motion controller card. This object has a number of properties and methods that affect the controller as a whole. The Axis and Motion sub-objects provide the properties and methods used to configure and generate motion on the axes.

Initialization
 | Address Number Port Type Init Reset
Configuration
 | SampleRate AxisCount AxisCountMax MotionCount MotionCountMax RecoderCount RecorderCountMax FlashSave FlashSaveAll

Actions
 | Abort EStop EStopAbort
Firmware
 | MPIVersion FirmwareVersion FirmwareUpload FirmwareDownload

Events
 | OnAnyEvent OnErrorEvent OnMotionEvent OnRecorderBufferDone
Sub-objects
 | Axis Map Motion Recorder Axis Object Documentation Map Object Documentation Motion Object Documentation Recorder Object Documentation


Controller.Abort

MEI Home
.

Controller.Abort

Description

Performs an Abort command on all the motion sub-objects of the controller.

Visual Basic Example

Controller.Abort

Syntax

Visual Basic

Sub Abort(
IDL Interface

HRESULT Abort()

See Also

Motion Object:
Abort


Controller.EStop

MEI Home
.

Controller.EStop

Description

Performs an EStop command on all the motion sub-objects of the controller.

Visual Basic Example

Controller.Abort

Syntax

Visual Basic

Sub EStop()
IDL Interface

HRESULT EStop()

See Also

Motion Object:
Estop


Controller.EStopAbort

MEI Home
.

Controller.EStopAbort

Description

This method will perform an EStopAbort command on all the motion sub-objects on this Controller.

Visual Basic Example

Controller.EStopAbort

Syntax

Visual Basic

Sub EStopAbort( )
IDL Interface

HRESULT EStopAbort()

See Also

Motion Object:
EStopAbort


Controller.AxisCount

MEI Home
.

Controller.AxisCount

Description

The number of axes this controller is currently controlling.

The motion controller closes the control loops on axes zero through (AxisCount - 1) All the other axes are not controlled. The maximum value this property can take is AxisCountMax.

This property is commonly used to reduce the number of axes being controlled to allow the controller's sample rate to be increased.

Type

Long

Visual Basic Example

x = Controller.AxisCount

Controller.AxisCount = 5

Syntax

Visual Basic

Property AxisCount As Long
IDL Interface

[propget] HRESULT AxisCount([out, retval] long *pVal)

[propput] HRESULT AxisCount([in] long newVal)

See Also

AxisCountMax

Axis Object


Controller.AxisCountMax

MEI Home
.

Controller.AxisCountMax

Description

The maximum number of axis software objects the controller can support.

This property may be larger than the actual number of axes that can be connected to the controller.

This property cannot be saved to flash memory.

Type

Long (read only)

Visual Basic Example

x = Controller.AxisCountMax

Syntax

Visual Basic

Property AxisCountMax As Long
IDL Interface

[propget] HRESULT AxisCountMax([out, retval] long *pVal)

See Also

AxisCount

Axis Object


Controller.FlashSave

MEI Home
.

Controller.FlashSave

Description

Saves the current controller object settings to flash memory. This configuration will be loaded onto the controller during the next power up or controller reset.

This method saves only the configuration properties of the controller object. To save the configuration of the controller object and all sub-objets, use the FlashSaveAll method.

Visual Basic Example

Controller.FlashSave

Syntax

Visual Basic

Sub FlashSave()
IDL Interface

HRESULT FlashSave()

See Also

FlashSaveAll

Axis Object:
FlashSave

Motion Object:
FlashSave


Controller.FlashSaveAll

MEI Home
.

Controller.FlashSaveAll

Description

Saves the current settings of the controller object and all sub-objects to flash memory. This configuration will be loaded onto the controller during the next power up or controller reset.

Visual Basic Example

Controller.FlashSaveAll

Syntax

Visual Basic

Property EncoderFaultTrigger(trigger As meiEncoderFaultTrigger) As Boolean
IDL Interface

[propget] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[out, retval] bool *pVal)

[propput] HRESULT EncoderFaultTrigger([in] meiEncoderFaultTrigger trigger,
[in] bool newVal)

See Also

FlashSave

Axis Object:
FlashSave

Motion Object:
FlashSave


Controller.MotionCount

MEI Home
.

Controller.MotionCount

Description

The number of motion objects currently being controlled.

The motion controller uses motion objects zero through (MotionCount - 1) All the other motion objects are not controlled. The maximum value this property can take is MotionCountMax.

This property is commonly used to reduce the number of motion objects being controlled to allow the controller's sample rate to be increased.

Type

Long

Visual Basic Example

x = Controller.MotionCount

Controller.MotionCount = 5

Syntax

Visual Basic

Property MotionCount As Long
IDL Interface

[propget] HRESULT MotionCount([out, retval] long *pVal)

[propput] HRESULT MotionCount([in]long newVal)

See Also

MotionCountMax


Controller.MotionCountMax

MEI Home
.

Controller.MotionCountMax

Description

The maximum number of motion software objects the controller can support.

This property cannot be saved to flash memory.

Type

Long (read only)

Visual Basic Example

x = Controller.MotionCountMax

Syntax

Visual Basic

Property MotionCountMax As Long
IDL Interface

[propget] HRESULT MotionCountMax([out, retval] long *pVal)

See Also

MotionCount


Controller.RecorderCount

MEI Home
.

Controller.RecorderCount

Description

The number of recorders currently allowed to be configured and started on the controller.

The motion controller will only use recorders zero through (RecorderCount - 1). All the other recorders are not controlled. The maximum value this property can take is RecorderCountMax.

NOTE: For the XMP family of controllers, this property is fixed at a value of 1 and cannot be changed. This property is included for compatibility with future controllers that may support more than one recorder object.

Type

Long

Visual Basic Example

x = Controller.RecorderCount

Syntax

Visual Basic

Property RecorderCount As Long
IDL Interface

[propget] HRESULT RecorderCount([out, retval] long *pVal)

[propput] HRESULT RecorderCount([in] long newVal)

See Also

RecorderCountMax

Recorder Object


Controller.RecorderCountMax

MEI Home
.

Controller.RecorderCountMax

Description

The maximum number of recorder software objects the controller can support.

This property cannot be saved to flash memory.

Type

Long (read only)

Visual Basic Example

x = Controller.RecorderCountMax

Syntax

Visual Basic

Property RecorderCountMax As Long
IDL Interface

[propget] HRESULT RecorderCountMax([out, retval] long *pVal)

See Also

RecorderCount

Recorder Object


Controller.SampleRate

MEI Home
.

Controller.SampleRate

Description

Specifies the servo rate for all axes on the motion controller.

NOTE: The Init method must be called to connect to a motion controller after the properties Address, Number, Port, and/or Type have been changed.

Units

Hertz

Type

Double

Visual Basic Example

x = Controller.SampleRate

Controller.SampleRate = 4000.0

Syntax

Visual Basic

Property SampleRate As Double

IDL Interface

[propget] HRESULT SampleRate([out, retval] double* pVal)

[propput] HRESULT SampleRate([in] double newVal)


Controller.OnAnyEvent

MEI Home
.

Controller.OnAnyEvent

Description

A callback method that is automatically called in response to events from the controller.

This method needs to be defined by the user.

Arguments

Argument | Type | Description
Type | meiEventType | The type of event generated by the Controller.
Number | Long | This is the number of the axis or motion object that generated an event.
Info | Array of Long | Captured event data. The information that is captured is different for the different types of events. Please refer to the event descriptions for information about what data is captured.

Visual Basic Example

Sub Controller_OnAnyEvent( Type, Number, Info )
' Actions
End Sub

Syntax

Visual Basic

Sub OnAnyEvent(EventType As meiEventType,
Number As Long,
Info() As Long)
IDL Interface

HRESULT OnAnyEvent([in] meiEventType EventType,
[in] long Number,
[in] SAFEARRAY(long) Info)

See Also

Events


Controller.OnErrorEvent

MEI Home
.

Controller.OnErrorEvent

Description

A callback method that is automatically called in response to error events from the controller.

This method needs to be defined by the user.

Arguments

Argument | Type | Description
Type | meiEventType | The type of event generated by the Controller.
Number | Long | This is the number of the axis or motion object that generated an event.
Info | Array of Long | Captured event data. The information that is captured is different for the different types of events. Please refer to the event descriptions for information about what data is captured.

Visual Basic Example

Sub Controller_OnErrorEvent(Type, Number, Info)
' Actions
End Sub

Syntax

Visual Basic

Sub OnErrorEvent(EventType As meiEventType,
Number As Long,
Info() As Long)
IDL Interface

HRESULT OnErrorEvent([in] meiEventType EventType,
[in] long Number,
[in] SAFEARRAY(long) Info)

See Also

Events Overview


Controller.OnMotionEvent

MEI Home
.

Controller.OnMotionEvent

Description

A callback method that is automatically called in response to motion events from the controller.

This method needs to be defined by the user.

Arguments

Argument | Type | Description
Type | meiEventType | The type of event generated by the Controller.
Number | Long | This is the number of the axis or motion object that generated an event.
Info | Array of Long | Captured event data. The information that is captured is different for the different types of events. Please refer to the event descriptions for information about what data is captured.

Visual Basic Example

Sub Controller_OnMotionEvent(Type, Number, Info)
' Actions
End Sub

Syntax

Visual Basic

Sub OnMotionEvent(EventType As meiEventType,
Number As Long,
Info() As Long)
IDL Interface

HRESULT OnMotionEvent([in] meiEventType EventType,
[in] long Number,
[in] SAFEARRAY(long) Info)

See Also

Events


Controller.OnRecorderBufferDone

MEI Home
.

Controller.OnRecorderBufferDone

Description

A callback method that returns a buffer of data filled by a recorder object. Returned with the buffer is a message that describes any events associated with the buffer. For example, when the last buffer is filled, the message variable will be set equal to meiRecorderMessageStopped indicating that the recorder object has stopped recording data.

This method needs to be defined by the user.

Arguments

Argument | Type | Description
message | meiRecorderMessage | Recorder message associated with the buffer.
number | long | The object number of the recorder that is returning a buffer.
buffer | Variant | The buffer of data being returned.
validSamples | long | The number of valid samples the returned buffer contains.

Type

Boolean

Visual Basic Example

Sub Controller_OnRecorderBufferDone(message, number, buffer, validSamples)
' Actions
End Sub

Syntax

Visual Basic

Sub OnRecorderBufferDone(message As meiRecorderMessage,
number As long
buffer As Variant
validSamples As long)
IDL Interface

HRESULT OnRecorderBufferDone([in] meiRecorderMessage message,
[in] long number,
[in] VARIANT* buffer,
[in] long validSasmples)

See Also

meiRecorderMessage

Recorder Object:
AddBuffer
Start
Stop


Controller.FirmwareDownload

MEI Home
.

Controller.FirmwareDownload

Description

Downloads firmware and FPGA files from the host computer to the motion controller's flash memory.

Arguments

Argument | Type | Description
filename | String | The name of the file which contains the the firmware image to be downloaded.
fpga1 | String | The name of an optional FPGA image file.
fpga2 | String | The name of an optional second FPGA image file.
fpga3 | String | The name of an optional third FPGA image file.

Visual Basic Example

Controller.FirmwareDownload "firmware.bin"

Syntax

Visual Basic

Sub FirmwareDownload(fileName As String,
fpga1 As String = Empty,
fpga2 As String = Empty,
fpga3 As String = Empty)
IDL Interface

HRESULT FirmwareDownload([in] BSTR fileName,
[in, defaultvalue("")] BSTR fpga1,
[in, defaultvalue("")] BSTR fpga2,
[in, defaultvalue("")] BSTR fpga3)

See Also

FirmwareUpload
FirmwareVersion


Controller.FirmwareUpload

MEI Home
.

Controller.FirmwareUpload

Description

Uploads a copy of the controller's firmware and flash memory settings to a file on the host.

Arguments

Argument | Type | Description
fileName | String | The name of the file where the firmware image will be stored

Visual Basic Example

Controller.FirmwareUpload "firmware.bin"

Syntax

Visual Basic

Sub FirmwareUpload(fileName As String)
IDL Interface

HRESULT FirmwareUpload([in] BSTR fileName)

See Also

FirmwareDownload
FirmwareVersion


Controller.FirmwareVersion

MEI Home
.

Controller.FirmwareVersion

Description

Returns the version of the firmware of the controller.

The string returned will include the version, revision, sub-revision and option of the current firmware, for example "341A5."

This property cannot be saved to flash memory.

Type

String (read only)

Visual Basic Example

x = Controller.FirmwareVersion

Syntax

Visual Basic

Property FirmwareVersion As String
IDL Interface

[propget] HRESULT FirmwareVersion([out, retval] BSTR *pVal)

See Also

FirmwareDownload
FirmwareUpload


Controller.MPIVersion

MEI Home
.

Controller.MPIVersion

Description

This property returns the version of the MPI DLL used to communicate with the controller.

This property cannot be saved to flash memory.

Type

String (read only)

Visual Basic Example

x = Controller.MPIVersion

Syntax

Visual Basic

Property MPIVersion As String
IDL Interface

[propget] HRESULT MPIVersion([out, retval] BSTR *pVal)

See Also

FirmwareVersion


Controller.Address

MEI Home
.

Controller.Address

Description

Specifies the name or IP address of the server where the motion controller card is located.

NOTE: The Init method must be called to connect to a motion controller after the properties Address, Number, Port, and/or Type have been changed.

Address is used with the Port and Number properties when the Type property is set to meiControlTypeRemote.

This property cannot be saved to flash memory.

Type

String

Visual Basic Example

x = Controller.Address

Controller.Address = "1.2.3.4"

Syntax

Visual Basic

Property Address As String
IDL Interface

[propget] HRESULT Address([out, retval] BSTR* pVal)

[propput] HRESULT Address([in] BSTR newVal)

See Also

Type
Number
Port


Controller.Init

MEI Home
.

Controller.Init

Description

Initializes the interface between the host computer and the motion controller. For SynqNet systems, this will also attempt to initialize the SynqNet protocol if the controller is not in "synq" mode.

When a Controller object is created, this method will automatically be called. In Visual Basic programs you would only need to use this property if you wanted to change the controller being used by changing the Type, Number, Address or Port properties.

This property cannot be saved to flash memory.

Visual Basic Example

Controller.Init

Syntax

Visual Basic

Sub Init
IDL Interface

HRESULT Init()

See Also

Type
Number
Address

Controller Initialization Overview


Controller.Number

MEI Home
.

Controller.Number

Description

Specifies the ID number of the motion controller card to use.

NOTE: The Init method must be called to connect to a motion controller after the properties Address, Number, Port, and/or Type have been changed.

The MEI device driver assigns unique numbers to each controller on a host machine. The first controller is numbered 0 and other controllers are numbered sequentially from this.

This property cannot be saved to flash memory.

Type

Long

Default

0

Visual Basic Example

x = Controller.Number

Controller.Number = 1

Syntax

Visual Basic

Property Number As Long
IDL Interface

[propget] HRESULT Number([out, retval] long *pVal)

[propput] HRESULT Number([in]long newVal)

See Also

Type
Address
Port


Controller.Port

MEI Home
.

Controller.Port

Description

Specifies the TCP port to be used when connecting to a remote server.

NOTE: The Init method must be called to connect to a motion controller after the properties Address, Number, Port, and/or Type have been changed.

Port is used with the Address and Number properties when the Type property is set to meiControlTypeRemote.

This property cannot be saved to flash memory.

Type

Long

Default

3300

Visual Basic Example

x = Controller.Port

Controller.Port = 3301

Syntax

Visual Basic

Property Port As Long
IDL Interface

[propget] HRESULT Port([out, retval] long *pVal)

[propput] HRESULT Port([in] long newVal)

See Also

Type
Number
Address


Controller.Reset

MEI Home
.

Controller.Reset

Description

Resets the motion controller, putting the controller into the same state it would assume immediately after it powers up.

Visual Basic Example

Controller.Reset

Syntax

Visual Basic

Sub Reset()
IDL Interface

HRESULT Reset()

See Also

Controller Initialization Overview


Controller.Type

MEI Home
.

Controller.Type

Description

Specifies whether the motion controller card is in the local computer or a remote computer.

NOTE: The Init method must be called to connect to a motion controller after the properties Address, Number, Port, and/or Type have been changed.

  • meiControllerTypeLocal - The controller is in the local computer
  • meiControllerTypeRemote - The controller is in a remote computer

The following table shows which other properties are required for each of the controller types.

Type | Number | Address | Port
meiControllerTypeLocal | Required | Ignored | Ignored
meiControllerTypeRemote | Required | Required | Required

This property cannot be saved to flash memory.

Type

meiControllerType

Default

meiControllerTypeLocal

Visual Basic Sample

Controller.Type = meiControllerTypeLocal

Syntax

Visual Basic

Property Type As meiControllerType
IDL Interface

[propget] HRESULT Type([out, retval] meiControllerType *pVal)

[propput] HRESULT Type([in] meiControllerType newVal)

See Also

Number
Address
Port


Controller.Axis

MEI Home
.

Controller.Axis

Description

An axis sub-object of the controller.

This property cannot be saved to flash memory.

Arguments

Argument | Description
Index | The index of the axis object to be accessed

Type

MPX Axis (read only)

Visual Basic Example

Set xAxis = Controller.Axis(0)

Syntax

Visual Basic

Property Axis(Index As Long) As MPXCtl.Axis
IDL Interface

[propget] HRESULT Axis([in] long Index,
[out, retval] IAxis** ppAxis)

See Also

Axis Object


Controller.Map

MEI Home
.

Controller.Map

Description

The map sub-object of the controller.

This property cannot be saved to flash memory.

Arguments

Argument | Description
Index | The of the map object to be accessed

Type

MPX Map (read only)

Visual Basic Example

Set map = Controller.Map

Syntax

Visual Basic

Property Map(Index As Long) As MPXCtl.Map

IDL Interface

[propget] HRESULT Map([in] long Index,
[out, retval] IMap** ppMap)

See Also

Map Object


Controller.Motion

MEI Home
.

Controller.Motion

Description

A motion sub-object of the controller.

This property cannot be saved to flash memory.

Arguments

Argument | Description
Index | The of the motion object to be accessed

Type

MPX Motion (read only)

Visual Basic Example

Set xMotion = Controller.Motion(0)

Syntax

Visual Basic

Property Motion(Index As Long) As MPXCtl.Motion
IDL Interface

[propget] HRESULT Motion([in] long Index,
[out, retval] IMotion** ppMotion)

See Also

Motion Object


Controller.Recorder

MEI Home
.

Controller.Recorder

Description

A recorder sub-object of the controller.

This property cannot be saved to flash memory.

Arguments

Argument | Description
Index | The of the recorder object to be accessed

Type

MPX Recorder (read only)

Visual Basic Example

Set recorder0 = Controller.Recorder(0)

Syntax

Visual Basic

Property Recorder(Index As Long) As MPXCtl.Recorder
IDL Interface

[propget] HRESULT Recorder([in] long Index,
[out, retval] IRecorder** ppRecorder)

See Also

Recorder Object


Enumerations Home

.

Enumerations

meiAction
meiCaptureEdge
meiCaptureSource
meiCaptureState
meiControllerType
meiDemand
meiEncoderFaultTrigger
meiError
meiEventType
meiFilterAlgorithm
meiFilterCoeff
meiHomeSource
meiInput
meiIoConfig
meiMap
meiMotorIo
meiMotorType
meiMoveAttr
meiOutput
meiRecorderMessage
meiState
meiStatus


meiAction

MEI Home
.

meiAction

The meiAction enumeration values represent actions for Motion objects.

meiAction | Meaning
meiActionAbort | Makes all axes' amplifiers associated with a Motion object inactive and places the Motion object in an error state
meiActionStop | Brings a Motion object to a stop in StopTime seconds
meiActionEStop | Brings a Motion object to a stop in EStopTime seconds and places the Motion object in an error state
meiActionEStopAbort | Performs an EStop action followed by an Abort action
meiActionResume | Causes a Motion object that has been stopped to resume motion
meiActionReset | Clears the error state of a Motion object
meiActionNone | Performs no action

See Also

Motion Object:
Abort
Stop
EStop
EStopAbort
Resume
Reset

Axis Object:
AmpFaultAction
EncoderFaultAction
HomeAction
LimitHwNegAction
LimitHwPosAction
LimitPositionErrorAction
LimitSwNegAction
LimitSwPosAction


meiCaptureEdge

MEI Home
.

meiCaptureEdge

The meiCaptureEdge enumeration values represent the edge of trigger state upon which the capture engine will record the encoder value. Please see the diagram below for more information.

meiCaptureEdge | Description
meiCaptureEdgeRising | Encoder Position recorded on the rising edge of the trigger state.
meiCaptureEdgeFalling | Encoder Position recorded on the falling edge of the trigger state.
meiCaptureEdgeTransition | Encoder Position recorded on any transition of the trigger state.
meiCaptureEdgeNone | Encoder Position never recorded.

See Also

Axis Object:
CaptureEdge


meiCaptureSource

MEI Home
.

meiCaptureSource

The meiCaptureSource enumeration values represent sources for the capture engine trigger. Please see diagram below for more information.

meiCaptureSource | Description | Related I/O
meiCaptureSourceHome | The home input | meiInputHome
meiCaptureSourceIndex | The index input | meiInputIndex
meiCaptureSourceHwNeg | The positive hardware limit | meiInputHwPos
meiCaptureSourceHwPos | The negative hardware limit | meiInputHwNeg
meiCaptyureSourceIo0 | Node-specific input 0 | meiInputIo0
meiCaptyureSourceIo1 | Node-specific input 1 | meiInputIo1
meiCaptyureSourceIo2 | Node-specific input 2 | meiInputIo2
meiCaptyureSourceIo3 | Node-specific input 3 | meiInputIo3
meiCaptyureSourceIo4 | Node-specific input 4 | meiInputIo4
meiCaptyureSourceIo5 | Node-specific input 5 | meiInputIo5
meiCaptyureSourceIo6 | Node-specific input 6 | meiInputIo6
meiCaptyureSourceIo7 | Node-specific input 7 | meiInputIo7
meiCaptureSourceGlobal | The global capture bit | N/A

See Also

meiInput

Axis Object:
CaptureSourceEnable
CaptureSourceLevel


meiCaptureState

MEI Home
.

meiCaptureState

The meiCaptureState enumeration values represent states of an axis' high speed position capturing engine.

meiCaptureState | Description
meiCaptureStateIdle | The capture engine is not armed. An encoder position has not yet been caputred.
meiCaptureStateArmed | The capture engine is armed.
meiCaptureStateCaptured | An encoder position has been captured and stored in CapturePosition. The engine is ready to be rearmed.

See Also

Axis Object:
CaptureState


meiControllerType

MEI Home
.

meiControllerType

Description

This enumeration defines the two different types of location where a controller can exist.

Enumeration | Description
meiControllerTypeLocal | The controller is on this machine
meiControllerTypeRemote | The controller is on another machine and we will use the MEI TCP/IP protocol to communicate to it.

See Also

Type


meiDemand

MEI Home
.

meiDemand

The meiDemand enumeration values represent axis demand outputs.

meiDemandValue | Meaning
meiDemandOutput | The demand ouput of the axis' filter algorithm
meiDemandPrimary | The primary demand output
meiDemandAuxiliary | The auxiliary demand output

See Also

Axis Object:
DemandLevel


meiEncoderFaultTrigger

MEI Home
.

meiEncoderFaultTrigger

The meiEncoderFaultTrigger enumeration values represent possible triggers for encoder fault detection.

meiEncoderFaultTrigger | Description
meiEncoderFaultTriggerBrokenWire | Determines whether one of the encoder lines is broken or not connected to either the encoder of controller
meiEncoderFaultTriggerIllegalState | Determines whether the states of the A and B encoder signals change simultaneously
meiEncoderFaultTriggerAbsolute | Determines whether an absolute encoder has produced a fault

See Also

Axis Object:
EncoderFaultTrigger


meiError

MEI Home
.

meiError

This enumeration defines the different motion states of a motion object.

Enumeration | Description
meiErrorNone | No error
meiErrorMpiMpxMismatch | MPI dll does not match MPX ActiveX control
meiErrorArgument | Argument invalid
meiErrorParameter | Parameter invalid
meiErrorNoMemory | Out of memory
meiErrorObjectNotEnabled | Object not enabled
meiErrorTimeout | MPX Timeout
meiErrorUnsupported | Feature not supported
meiErrorFatal | Fatal error
meiErrorFileClose | Error closing a file
meiErrorFileOpen | Error opening a file
meiErrorFileRead | Error reading from a file
meiErrorFileWrite | Error writing to a file
meiErrorAxisCommandNotSet | Command position not set
meiErrorAxisHomeSource | Cannot set HomeInvert = false when HomeSource = meiHomeSourceCapture
meiErrorControllerAddress | Controller.Address invalid
meiErrorControllerNumber | Controller.Number invalid
meiErrorControllerType | Controller.Type invalid
meiErrorControllerInterruptsDisabled | Controlller interrupts disabled
meiErrorControllerMemoryOverflow | Controller memory overflow
meiErrorControllerCount | Object count invalid
meiErrorAxisFilterAlgorithm | Axis.FilterAlgorithm invalid
meiErrorMotionAxisNotFound | Axis not found
meiErrorMotionAxisCount | Axis count error
meiErrorMotionAttribute | Motion attribute invalid
meiErrorMotionNotReady | Motion object not ready
meiErrorMotionIdle | Motion.State is meiStateIdle
meiErrorMotionMoving | Motion.State is meiStateMoving
meiErrorMotionStopping | Motion.State is meiStateStopping
meiErrorMotionStoppingError | Motion.State is meiStateStoppingError
meiErrorMotionError | Motion.State is meiStateError
meiErrorRecorderStarted | Recorder has started executing
meiErrorRecorderStopped | Recorder is not executing
meiErrorRecorderNotConfigured | Recorder has not been configured
meiErrorCanFirmwareInvalid | Can firmware invalid
meiErrorCanFirmwareVersion | Can firmware version invalid
meiErrorFlashRead | Flash memory could not be read
meiErrorFlashWrite | Flash memory could not be written to
meiErrorMapName | Invalid characters in name
meiErrorMapNameNotFound | Could not find name
meiErrorMapIndex | Index invalid
meiErrorMapFile | Map file invalid or not found
meiErrorPacketError | Packet error while communicating with server
meiErrorDevice | Device driver invalid
meiErrorDeviceError | Device driver error


meiEventType

MEI Home
.

meiEventType

The meiEventType enumeration values represent controller event types.

meiEventTypeValue | Source | Event Handler | Meaning
meiEventTypeLimitPositionError | Axis | OnErrorEvent | Position Error Limit Event
meiEventTypeLimitHwPos | Axis | OnErrorEvent | Positive Hardware Limit Event
meiEventTypeLimitHwNeg | Axis | OnErrorEvent | Negative Hardware Limit Event
meiEventTypeLimitSwPos | Axis | OnErrorEvent | Positive Software Limit Event
meiEventTypeLimitSwNeg | Axis | OnErrorEvent | Negative Software Limit Event
meiEventTypeAmpFault | Axis | OnErrorEvent | Amplifier Fault Event
meiEventTypeEncoderFault | Axis | OnErrorEvent | Encoder Fault Event
meiEventTypeLimitTorque | Axis | OnErrorEvent | Torque Limit Event
meiEventTypeUserLimit0 | Axis | OnAnyEvents | User Limit 0 Event
meiEventTypeUserLimit1 | Axis | OnAnyEvents | User Limit 1 Event
meiEventTypeUserLimit2 | Axis | OnAnyEvents | User Limit 2 Event
meiEventTypeUserLimit3 | Axis | OnAnyEvents | User Limit 3 Event
meiEventTypeUserLimit4 | Axis | OnAnyEvents | User Limit 4 Event
meiEventTypeUserLimit5 | Axis | OnAnyEvents | User Limit 5 Event
meiEventTypeUserLimit6 | Axis | OnAnyEvents | User Limit 6 Event
meiEventTypeUserLimit7 | Axis | OnAnyEvents | User Limit 7 Event
meiEventTypeHome | Axis | OnMotionEvent | Home Event
meiEventTypeInPositionCoarse | Axis | OnMotionEvent | In Coarse Position Tolerance Event
meiEventTypeSettled | Axis | OnMotionEvent | In Fine Position Tolerance Event
meiEventTypeAtTarget | Axis | OnMotionEvent | At Target Event
meiEventTypeFrame | Axis | OnMotionEvent | ???
meiEventTypeDone | Motion | OnMotionEvent | Motion is Complete
meiEventTypeAtVelocity | Motion | OnMotionEvent | At Slew Velocity
meiEventTypeOutOfFrames | Motion | OnMotionEvent | Motion is Out of Frames
meiEventTypePowerFault | Controller | OnAnyEvents | Supply Voltage is Low
meiEventTypeRecorderFull | Object not accessible by ActiveX control | OnAnyEvents | Recoder is Full
meiEventTypeRecorderDone | Object not accessible by ActiveX control | OnAnyEvents | Recoder has Completed
meiEventTypeExternal | Object not accessible by ActiveX control | OnAnyEvents | External Event
meiEventTypeNone | No event is to be generated

See Also

Motion Object:
EventEnable

Axis Object:
EventEnable


meiFilterAlgorithm

MEI Home
.

meiFilterAlgorithm

The meiFilterAlgorithm enumeration values represent different control alogorithms to be used by the Axis object.

meiFilterAlgorithm | Meaning
meiFilterAlgorithmNone | No control algorithm. Can use with stepper motors.
meiFilterAlgorithmPID | PID algorithm
meiFilterAlgorithmPIV | PIV algorithm
meiFilterAlgorithmUser | User algorithm implemented with the Firmware Development Kit

See Also

Axis Object:
FilterAlgorithm


meiFilterCoeff

MEI Home
.

meiFilterCoeff

The meiFilterCoeff enumeration values represent filter algorithm coefficients.

meiFilterCoeffValue | Algorithm | Description
meiFilterCoeffPidKp | PID | Proportional Term
meiFilterCoeffPidKi | PID | Integral Term
meiFilterCoeffPidKd | PID | Derivative Term
meiFilterCoeffPidKpff | PID | Position Feed Forward
meiFilterCoeffPidKvff | PID | Velocity Feed Forward
meiFilterCoeffPidKaff | PID | Acceleration Feed Forward
meiFilterCoeffPidKfff | PID | Friction Feed Forward
meiFilterCoeffPidIMaxMoving | PID | Maximum Moving Integral
meiFilterCoeffPidIMaxRest | PID | Maximum Rest Intgral
meiFilterCoeffPidDRate | PID | Derivative Rate measured in samples
meiFilterCoeffPidDRate | PID | Absolute Output Limit measured in Volts
meiFilterCoeffPidOutputLimitAbs | PID | High Output Limit measured in Volts
meiFilterCoeffPidOutputLimitHigh | PID | Low Output Limit measured in Volts
meiFilterCoeffPidOutputLimitLow | PID | Output Offset measured in Volts
meiFilterCoeffPidOutputOffset | PIV | Position Loop Proportional Term
meiFilterCoeffPivKpp | PIV | Position Loop Integral Term
meiFilterCoeffPivKpv | PIV | Velocity Loop Proportional Term
meiFilterCoeffPivKpff | PIV | Position Feed Forward
meiFilterCoeffPivKvff | PIV | Velocity Feed Forward
meiFilterCoeffPivKaff | PIV | Acceleration Feed Forward
meiFilterCoeffPivKfff | PIV | Friction Feed Forward
meiFilterCoeffPivIMaxMoving | PIV | Position Loop Maximum Moving Integral
meiFilterCoeffPivIMaxRest | PIV | Position Loop Maximum Rest Intgral
meiFilterCoeffPivKdv | PIV | Velocity Derivative Term
meiFilterCoeffPivOutputLimitAbs | PIV | Absolute Output Limit measured in Volts
meiFilterCoeffPivOutputLimitHigh | PIV | High Output Limit measured in Volts
meiFilterCoeffPivOutputLimitLow | PIV | Low Output Limit measured in Volts
meiFilterCoeffPivOutputOffset | PIV | Output Offset measured in Volts
meiFilterCoeffPivKiv | PIV | Velocity Integral Term
meiFilterCoeffPivVIntMax | PIV | Velocity Loop Maximum Integral
meiFilterCoeffPivKa0 | PIV | Velocity Smoothing Parameter

See Also

Axis Object:
FilterCoeff


meiHomeSource

MEI Home
.

meiHomeSource

The meiHomeSource enumeration values represent possible sources for the home status bit and home events.

meiHomeSource | Description
meiHomeSourceCapture | The home status bit would be determined from CaptureState
meiHomeSourceIo | The home status bit would be determined from the digital home input

See Also

Axis Object:
HomeSource
CaptureState


meiIoConfig

MEI Home
.

meiIoConfig

The meiIoConfig enumeration values represent digital I/O configurations.

meiIoConfig | Description
meiIoConfigInput | Io bit is to be used as a digital input
meiIoConfigOutput | Io bit is to be used as a digital output
meiIoConfigStep | Io bit is to be used to output the step pulse for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigDir | Io bit is to be used to output the direction state for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigCw | Io bit is to be used to output the clockwise pulse for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigCcw | Io bit is to be used to output the counter-clockwise pulse for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigQuadA | Io bit is to be used to output the quadrature A state for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigQuadB | Io bit is to be used to output the quadrature B state for stepper motors. Currently not supported in SynqNet Phase II.
meiIoConfigSource1 ... meiIoConfigSource4 | SynqNet Phase II: Node-specific configurations for digital outputs.

See Also

Axis Object:
IoConfig


meiInput

MEI Home
.

meiInput

The meiInput enumeration values represent digital inputs for the axis object.

meiInput | Description
meiInputHwPos | Positive hardware limit input
meiInputHwNeg | Negative hardware limit input
meiInputHome | Home input
meiInputAmpFault | Amplifier fault input
meiInputIndex | Index input
meiInputSimIndex | SIM Index input
meiInputSimEncA | SIM Encoder A input
meiInputSimEncB | SIM Encoder B input
meiInputIo0 | Node-specific output 0
meiInputIo1 | Node-specific output 1
meiInputIo2 | Node-specific output 2
meiInputIo3 | Node-specific output 3
meiInputIo4 | Node-specific output 4
meiInputIo5 | Node-specific output 5
meiInputIo6 | Node-specific output 6
meiInputIo7 | Node-specific output 7
meiInputDriveStatus0 | Node-specific Drive status 0
meiInputDriveStatus1 | Node-specific Drive status 1
meiInputDriveStatus2 | Node-specific Drive status 2

For a breakdown of how the hardware I/O matches up to the MPX software for Analog XMP controllers and SynqNet Phase I RMBs, please see the Hardware to Software Map of I/O.

For information about the map of I/O for other drives/nodes, please contact the manufacturer's drive/node documentation.

See Also

Axis Object:
DigitalIn


meiMap

MEI Home
.

meiMap

The meiMap enumeration represents variables on the controller commonly accessed by MPX properties and methods. Most meiMap enumeration values need to be associated with an index value when used by MPX properties and methods.

meiMap | Description | Meaning of Associated Index
meiMapActPos | Actual Position | Axis number
meiMapActVel | Actual Velocity | Axis number
meiMapADC* | ADC Level | ADC number
meiMapAxisDigitalIn | Axis Object's Digital Inputs | Axis number
meiMapAxisDigitalOut | Axis Object's Digital Outputs | Axis number
meiMapAxisStatus | Axis Status | Axis number
meiMapBkgndCycle | Controller's Background Cycle | (none)
meiMapCmdAcc | Command Acceleration | Axis number
meiMapCmdJerk | Command Jerk | Axis number
meiMapCmdPos | Command Position | Axis number
meiMapCmdVel | Command Velocity | Axis number
meiMapDemand | Axis Demand | Axis number
meiMapDemandAuxiliary | Sinusoidal Commutation Auxiliary Demand | Axis number
meiMapDemandPrimary | Sinusoidal Commutation Primary Demand | Axis number
meiMapMotionStatus | Motion Status | Motion number
meiMapSampleCounter | Controller's Sample Counter | (none)
meiMapPosErr | Position Error | Axis number
* Not yet supported by SynqNet Phase II

See Also

Map Object:
DataType
String


meiMoveAttr

MEI Home
.

meiMoveAttr

Motion attributes change the behavior of the standard motion commands. If no motion attributes are specified then the standard behavior of the motion command is generated.

Attribute
Description
meiMoveAttrRelative

If this attribute is set all position values will be used as relative motion distances instead of final absolute positions.

For example. Without this attribute, a move beginning at position 1000 with a position parameter value of 2000 will move to position 2000. With this attribute, the final move position would have been 3000, a relative distance of 2000 counts from the starting value of 1000.

meiMoveAttrAppend

This attribute makes it possible to buffer several point-to-point motion profiles in the controller.

Repeatedly calling motion commands with this attribute will append the new motions to the previously commanded motions creating a sequence of different motions. When each of these motions complete a new Done event will be generated.

meiMoveAttrModify

This attribute modifies the current motion.

Executing a motion command with this attribute immediately (within two servo cycles) end the current motion and replace it with the new motion, smoothly transitioning between the moves. All the remaining original move will be lost.

If the original move completes before the new modified move has time to start (reaches the Idle state) the new move will not start and return an error. The AutoStart attribute below can be used in conjunction with the Modify attribute in this condition.

meiMoveAttrAutoStart This attribute modifies the Modify action so that the new motion will automatically start, event if the State is Idle.
meiMoveAttrSyncStart

This attribute modifies a point-to-point move that uses more than one axis. If this attribute is set then all the axis moves are separate moves that will begin simultaneously.

See the description of Synchronized Attributes.

meiMoveAttrSyncEnd

This attribute modifies a point-to-point move that uses more than one axis. This is a synchronised motion similar to SyncStart except that each of the axes will end simultaneously.

If SyncStart and SyncEnd are both specified then all the axes will start and stop at the same time with the motion of all the faster axes slowed down to match the time of the slowest axis.

See the description of Synchronized Attributes.

Not all of the different attributes are used by each of the motion commands. The following table shows which attributes are valid for which motion commands. If an attribute is specified for a move type for which it is not valid it will be ignored.

 | Relative | Append | Modify | AutoStart | SyncStart | SyncEnd
Trapizoidal | x | x | x | x | x | x
SCurve | x | x | x | x | x | x
SCurveJerk | x | x | x | x | x | x
Velocity |  | x | x | x | x |
VelocityJerk |  | x | x | x | x |


meiMotorIo

MEI Home
.

meiMotorIo

The meiMotorIo enumeration values represent drive-specific configurable I/O.

meiMotorIo | Description | Related I/O
meiMotorIo0 | Drive-specific I/O 0 | meiInput0, meiOutputIo0
meiMotorIo1 | Drive-specific I/O 1 | meiInput1, meiOutputIo2
meiMotorIo2 | Drive-specific I/O 2 | meiInput2, meiOutputIo2
meiMotorIo3 | Drive-specific I/O 3 | meiInput3, meiOutputIo3
meiMotorIo4 | Drive-specific I/O 4 | meiInput4, meiOutputIo4
meiMotorIo5 | Drive-specific I/O 5 | meiInput5, meiOutputIo5
meiMotorIo6 | Drive-specific I/O 6 | meiInput6, meiOutputIo6
meiMotorIo7 | Drive-specific I/O 7 | meiInput7, meiOutputIo7

See Also

meiInput
meiOutput

Axis Object:
IoConfig


meiMotorType

MEI Home
.

meiMotorType

The meiMotorType enumeration values represent different motor types that the Axis object can control.

meiMotorType | Description
meiMotorTypeServo | Servo Motor
meiMotorTypeStepper | Stepper Motor
meiMotorTypeSercos | Sercos drive controlling the motor

See Also

Axis Object:
MotorType


Hardware to Software Map of I/O

MEI Home
.

Hardware to Software Map of I/O

The following MPX values are only valid for an Analog XMP and a SynqNet Phase 1 RMB.

For more information, please see meiOutput and meiInput.

For information about the map of I/O for other drives/nodes, please contact the manufacturer's drive/node documentation.

Analog XMP
Analog XMP I/O | meiOutput Value | meiInput Value
Transceiver A | meiOutputIo0 | meiInputIo0
Transceiver B | meiOutputIo1 | meiInputIo1
Transceiver C | meiOutputIo2 | meiInputIo2
Transceiver D* | meiOutputIo3 | meiInputIo3
Transceiver E* | meiOutputIo4 | meiInputIo4
Transceiver F* | meiOutputIo5 | meiInputIo5
User I/O | meiOutputIo6 | meiInputIo6
* for XMP-Pulse and eXMP only

SynqNet Phase I RMB
SynqNet Phase I RMB | meiOutput Value | meiInput Value
Transceiver A | meiOutputIo0 | meiInputIo0
Transceiver B | meiOutputIo1 | meiInputIo1
Transceiver C | meiOutputIo2 | meiInputIo2
User I/O 1 | meiOutputIo6 | meiInputIo6
User I/O 2 | meiOutputIo7 | meiInputIo7


meiOutput

MEI Home
.

meiOutput

The meiOutput enumeration values represent digital outputs for the axis object.

meiOutput | Description
meiOutputAmpEnable | Amplifier Enable output
meiOutputBrakeRelease | Brake Enable output
meiOutputIo0 | Drive-specific output 0
meiOutputIo1 | Drive-specific output 1
meiOutputIo2 | Drive-specific output 2
meiOutputIo3 | Drive-specific output 3
meiOutputIo4 | Drive-specific output 4
meiOutputIo5 | Drive-specific output 5
meiOutputIo6 | Drive-specific output 6
meiOutputIo7 | Drive-specific output 7
meiOutputIo8 | Drive-specific output 8
meiOutputIo9 | Drive-specific output 9
meiOutputIo10 | Drive-specific output 10
meiOutputIo11 | Drive-specific output 11
meiOutputIo12 | Drive-specific output 12
meiOutputIo13 | Drive-specific output 13
meiOutputIo14 | Drive-specific output 14
meiOutputIo15 | Drive-specific output 15

For a breakdown of how the hardware I/O matches up to the MPX software for Analog XMP controllers and SynqNet Phase I RMBs, please see the Hardware to Software Map of I/O.

For information about the map of I/O for other drives/nodes, please contact the manufacturer's drive/node documentation.

See Also

Axis Object:
DigitalOut
DigitalOutInvert


meiRecorderMessage

MEI Home
.

meiRecorderMessage

Description

The meiRecorderMessage enumeration values represent possible messages to be associated with recorder buffers when returned via the Controller.OnRecorderBufferDone event callback method.

This method needs to be defined by the user.

Arguments

meiRecorderMessage | Description
meiRecorderMessageNone | No message
meiRecorderMessageStopped | The recorder has be stopped. This can happen if there are no more buffers to be filled or if the recorder was stopped by a call to the Recorder.Stop method by another application.
meiRecorderMessageOverflow | The controller's internal recorder buffer has overflowed because the host application could not keep up. The recorder is stopped when an overflow occurs.
meiRecorderMessageUnknown | An unknown problem has occurred.

See Also

Controller Object:
OnRecorderBufferDone


meiState

MEI Home
.

meiState

Description

This enumeration defines the different motion states of a motion object.

Enumeration | Description
meiStateIdle | The motion is idle and waiting to start or resume motion.
meiStateMoving | The axes are moving.
meiStateStopping | The axes are stopping. This occurs from a Stop command.
meiStateStoppingError | The axes are performing an emergency stop and/or abort on all axes.
meiStateError | The axes are in error.

See Also

Motion Object:
State


meiStatus

MEI Home
.

meiStatus

The meiStatus enumeration values represent object status information.

NOTE: The meiStatusEncoderFault status will be set if any of the following statii are set:

  • meiStatusBrokenWire
  • meiStatusIllegalState
  • meiStatusAbsEncoderFault
  • meiStatusAbsEncoderTimeout

meiStatusValue | Meaning
meiStatusLimitPositionError | Position Error Limit
meiStatusLimitHwPos | Positive Hardware Limit
meiStatusLimitHwNeg | Negative Hardware Limit
meiStatusLimitSwPos | Positive Software Limit
meiStatusLimitSwNeg | Negative Software Limit
meiStatusAmpFault | Amplifier Fault
meiStatusEncoderFault | Encoder Fault
meiStatusBrokenWire | Encoder Broken Wire
meiStatusIllegalState | Encoder Illegal State Transition
meiStatusAbsEncoderFault | Absolute Encoder Fault
meiStatusAbsEncoderTimeout | Absolute Encoder Timeout
meiStatusLimitTorque | Torque Limit
meiStatusUserLimit0 | User Limit 0
meiStatusUserLimit1 | User Limit 1
meiStatusUserLimit2 | User Limit 2
meiStatusUserLimit3 | User Limit 3
meiStatusUserLimit4 | User Limit 4
meiStatusUserLimit5 | User Limit 5
meiStatusUserLimit6 | User Limit 6
meiStatusUserLimit7 | User Limit 7
meiStatusHome | Home
meiStatusInPositionCoarse | Axis In Coarse Position Tolerance
meiStatusSettled | Axis Settled
meiStatusAtTarget | Axis At Target
meiStatusFrame | Frame Event Requested
meiStatusDone | Motion is Complete
meiStatusAtVelocity | Axes at Final Velocity
meiStatusOutOfFrames | Motion is Out of Frames
meiStatusPowerFault | Supply Voltage is Low
meiStatusRecorderFull | Recoder is Full
meiStatusRecorderDone | Recoder has Completed
meiStatusExternal | External Event Requested

See Also

Motion Object:
Status

Axis Object:
Status


Map Object

.

Map Object

The Map object allows a user to obtain the default data type and controller memory location of commonly used controller variables.

Data Location
String
Data Type
DataType


Map.String

MEI Home
.

Map.String

Description

Returns a string representing the location of some controller variable when passed an enumeration of type meiMap.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description | Default Value
Var | meiMap | The variable whose string location is to be returned. |
Index | Long (optional) | If a variable index is required, then index represents the index of the variable whose string location is to be returned. | -1

Type

String (read only)

Visual Basic Example

SampleCounterAddr = Controller.Map.String(meiMapSampleCounter)
'returns "MEIXmpData.SystemData.SampleCounter"

Syntax

Visual Basic

Sub String(Var As meiMap,
Index As Long = -1)
IDL Interface

HRESULT String([in] meiMap Var,
[in, defaultvalue(-1)] long Index,
[out, retval] BSTR* pVal)

See Also

DataType

meiMap


Map.DataType

MEI Home
.

Map.DataType

Description

Returns the data type of a controller variable.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description | Default Value
Var | meiMap | The variable whose data type is to be returned. |
Index | Long (optional) | If a variable index is required, then index represents the index of the variable whose data type is to be returned. | -1

Type

meiDataType (read only)

Visual Basic Example

SampleCounterType = Controller.Map.DataType(meiMapSampleCounter)
'returns meiDataTypeLong

Syntax

Visual Basic

Sub DataType(Var As meiMap,
Index As Long = -1)
IDL Interface

HRESULT DataType([in] meiMap Var,
[in, defaultvalue(-1)] long Index,
[out, retval] meiDataType* pVal)

See Also

String

meiMap


Motion Object

.

Motion Object

A motion object is responsible for initiating all motion on any single axis or group of axes. Before any motion can be initiated the motion object has to know which axes it is going to use; the Axes property is used to perform this mapping. This mapping action allows separate motion objects to be created for each of the primary components on a machine, e.g. an X-Y table or an in-feed belt. The motion object is then be used as the primary way of commanding motion to this component within the machine. The second responsibility of the motion object is to allow errors within a group of axes to be propagated between the axes. Motion objects also allow operations to affect all the axes within an axis group. for example is several axes are mapped to a single motion object, if a fault is detected on one axis that aborts the motion on that axis the other axes would also have their motions aborted.

Mapping
 | Axes Refresh
Move
 | Trapezoidal SCurve SCurveJerk Velocity VelocityJerk
Trajectory Information
 | ActualPosition ActualVelocity CommandPosition CommandVelocity PositionError

Amplifier Enable
 | AmpEnable
State
 | State
Actions
 | Reset Abort EStop EStopAbort StopTime EStopTime Stop Resume

Defaults
 | DefaultSpeed DefaultAccel DefaultDecel DefaultJerkPercent DefaultAccelJerk DefaultDecelJerk
Flash
 | FlashSave
Status
 | Status
Events
 | EventEnable EventEnableAll EventEnableNone


Motion.Abort

MEI Home
.

Motion.Abort

Description

Disables the filter algorithm, sets the demand level to zero, and disables the amplifiers for all axes associated with the motion object.

The motion State will immediately move to its Error condition. Before starting another move the Reset method needs to be executed to clear the error and all axes' amplifiers need to be enabled.

Visual Basic Example

Controller.Motion(3).Abort

Syntax

Visual Basic

Sub Abort()
IDL Interface

HRESULT Abort()

See Also

State
Reset
AmpEnable


Motion.EStop

MEI Home
.

Motion.EStop

Description

Decelerates the axes to a stop in the time specified by the EStopTime.

While the axes are decelerating, the Motion.State will be meiStateStoppingError, and once the axis has stopped, the state will stay as meiStateError. The axes will remain in the Error state controlling the axis (servoing), with the amplifier enabled. Before starting another move, the Reset method needs to be called in order to change the state to meiStateIdle.

Visual Basic Example

Controller.Motion(3).EStop

Syntax

Visual Basic

Sub EStop()
IDL Interface

HRESULT EStop()

See Also

State
EStopTime
Reset


Motion.EStopAbort

MEI Home
.

Motion.EStopAbort

Description

This method of a motion object will will decelerate the axis (or axes) to a stop in the time specified by the EStopTime and then disable the drive.

While the axis is decelerating the motion State will be StoppingError, and once the axis has stopped the state will stay as Error. The axis will remain in the Error state with the amplifiers disabled and the DAC forced to zero (plus the DACOffset). Before starting another move the Reset method needs to be executed to clear the error and move the State to Idle and the axes need to be enabled.

Visual Basic Example

Controller.Motion(3).EStopAbort

Syntax

Visual Basic

Sub EStopAbort()
IDL Interface

HRESULT EStopAbort()

See Also

State
EStopTime
Reset


Motion.EStopTime

MEI Home
.

Motion.EStopTime

Description

The deceleration time for an EStop action.

Units

seconds

Type

Double

Visual Basic Example

Controller.Motion(3).EStopTime = .010 '10 milliseconds

x = Controller.Motion(3).EStopTime

Syntax

Visual Basic

Property EStopTime As Double
IDL Interface

[propget] HRESULT EStopTime([out, retval] double *pVal)

[propput] HRESULT EStopTime([in] double newVal)

See Also

State
EStop


Motion.Resume

MEI Home
.

Motion.Resume

Description

Resumes any uncompleted motion that was prematurely stopped with the Stop method. Any time after a stop command, the Resume command can be used to complete the remainder of the original move.

Visual Basic Example

Controller.Motion(3).Resume

Syntax

Visual Basic

Sub Resume()
IDL Interface

HRESULT Resume()

See Also

State
Stop


Motion.Reset

MEI Home
.

Motion.Reset

Description

Attempts to return all axes associated with the motion object to their Idle state.

Visual Basic Example

Controller.Motion(3).Reset

Syntax

Visual Basic

Sub Reset()
IDL Interface

HRESULT Reset()

See Also

State


Motion.Stop

MEI Home
.

Motion.Stop

Description

Decelerates the axes to a stop in the time specified by the StopTime.

While the axes are decelerating, the Motion.State will be meiStateStoppingStopping, and once the axes have stopped, the state will stay as meiStateIdle. If you want to complete the remainder of the move that has stopped, the Resume method can be used or a new new motion command can be executed, at the cost of loosing the uncompleted part of the original move.

Visual Basic Example

Controller.Motion(3).Stop

Syntax

Visual Basic

Sub Stop()
IDL Interface

HRESULT Stop()

See Also

StopTime
Resume


Motion.StopTime

MEI Home
.

Motion.StopTime

Description

The deceleration time for a Stop action.

Units

seconds

Type

Double

Visual Basic Example

Controller.Motion(3).StopTime = .500 '500 milliseconds

x = Controller.Motion(3).StopTime

Syntax

Visual Basic

Property StopTime As Double
IDL Interface

[propget] HRESULT StopTime([out, retval] double *pVal)

[propput] HRESULT StopTime([in] double newValue)

See Also

State
Stop


Motion.AmpEnable

MEI Home
.

Motion.AmpEnable

Description

Attempts to enable or disable the amplifers of all axes associated with the motion object by setting the AmpEnable property on all axes mapped to this motion object.

This property cannot be saved to flash memory.

Type

Boolean (write only)

AmpEnable | Description
True | Attempt to enable all axes' amplifiers
False | Disable all axes' amplifiers

Visual Basic Example

Controller.Motion(3).AmpEnable = True

Syntax

Visual Basic

Property AmpEnable As Boolean
IDL Interface

[propput] HRESULT AmpEnable([in] VARIANT_BOOL newVal)

See Also

State
Abort

Axis Object:
AmpEnable


Motion.DefaultAccel

MEI Home
.

Motion.DefaultAccel

Description

The default acceleration parameter to be used in a move. This property is used for all motions where synchronized attributes are specified, use Axis.DefaultAccel.

This property cannot be saved to flash memory.

Units

counts/sec2

Type

Double

Default

0

Visual Basic Example

Controller.Motion(3).DefaultAccel = 50000

x = Controller.Motion(3).DefaultAccel

Syntax

Visual Basic

Property DefaultAccel As Long

IDL Interface

[propget] HRESULT DefaultAccel([out, retval] double *pVal)

[propput] HRESULT DefaultAccel([in] double newVal)

See Also

Trapezoidal
SCurve
SCurveJerk
Velocity
VelocityJerk

Axis Object
DefaultAccel


Motion.DefaultAccelJerk

MEI Home
.

Motion.DefaultAccelJerk

Description

The default jerk to be used in the acceleration phase of a move. This property is used for all motions that do not used the synchronized attributes.

This property cannot be saved to flash memory.

Units

counts/sec3

Type

Double

Default

0

Visual Basic Example

Controller.Motion(3).DefaultAccelJerk = 5000

x = Controller.Motion(3).DefaultAccelJerk

Syntax

Visual Basic

Property DefaultAccelJerk As Long
IDL Interface

[propget] HRESULT DefaultAccelJerk([out, retval] double *pVal)

[propput] HRESULT DefaultAccelJerk([in] double newVal)

See Also

SCurveJerk
VelocityJerk
DefaultDecelJerk

Axis Object
DefaultAccelJerk


Motion.DefaultDecel

MEI Home
.

Motion.DefaultDecel

Description

The default deceleration parameter to be used in a move. This property is used for all motions that do not used the synchronized attributes.

This property cannot be saved to flash memory.

Units

counts/sec2

Type

Double

Default

0

Visual Basic Example

Controller.Motion(3).DefaultDecel = 50000

x = Controller.Motion(3).DefaultDecel

Syntax

Visual Basic

Property DefaultDecel As Long
IDL Interface

[propget] HRESULT DefaultDecel([out, retval] double *pVal)

[propput] HRESULT DefaultDecel([in] double newVal)

See Also

Trapezoidal
SCurve
SCurveJerk

Axis Object
DefaultDecel


Motion.DefaultDecelJerk

MEI Home
.

Motion.DefaultDecelJerk

Description

The default jerk to be used in the deceleration phase of a move. This property is used for all motions that do not used the synchronized attributes.

This property cannot be saved to flash memory.

Units

counts/sec3

Type

Double

Default

0

Visual Basic Example

Controller.Motion(3).DefaultDecelJerk = 5000

x = Controller.Motion(3).DefaultDecelJerk

Syntax

Visual Basic

Property DefaultDecelJerk As Long
IDL Interface

[propget] HRESULT DefaultDecelJerk([out, retval] double *pVal)

[propput] HRESULT DefaultDecelJerk([in] double newVal)

See Also

SCurveJerk
VelocityJerk
DefaultAccelJerk

Axis Object
DefaultDecelJerk


Motion.DefaultJerkPercent

MEI Home
.

Motion.DefaultJerkPercent

Description

The percentage of the acceleration and deceleration phases that has an S curved velocity profile. This property is used for all motions that do not used the synchronized attributes.

This property cannot be saved to flash memory.

Type

Double

Default

100%

Visual Basic Example

Controller.Motion(3).DefaultJerkPercent = 50

x = Controller.Motion(3).DefaultJerkPercent

Syntax

Visual Basic

Property DefaultJerkPercent As Long
IDL Interface

[propget] HRESULT DefaultJerkPercent([out, retval] double *pVal)

[propput] HRESULT DefaultJerkPercent([in] double newVal)

See Also

SCurve
Velocity

Axis Object
DefaultJerkPercent


Motion.DefaultSpeed

MEI Home
.

Motion.DefaultSpeed

Description

The default maximum speed used for a move.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Double

Default

0

Visual Basic Example

Controller.Motion(3).DefaultSpeed = 5000

x = Controller.Motion(3).DefaultSpeed

Syntax

Visual Basic

Property DefaultSpeed As Long
IDL Interface

[propget] HRESULT DefaultSpeed([out, retval] double *pVal)

[propput] HRESULT DefaultSpeed([in] double newVal)

See Also

Trapezoidal
SCurve
SCurveJerk

Axis Object
DefaultSpeed


Motion.EventEnable

MEI Home
.

Motion.EventEnable

Description

Enables or disables any of the events that are generated by the motion object from being reported to the host. The events that can be generated by this object is are:

  • Motion Done
  • Motion At Velocity
  • Motion Out of Frames

Arguments

Argument | Type | Description
Type | meiEventType | The type of event that is being enabled or disabled.

Type

Boolean

  • True - The event is generated on the host
  • False - The event is not generated on the host

Visual Basic Example

Controller.Motion(3).EventEnable(meiEventTypeAtVelocity) = True

x = Controller.Motion(3).EventEnable(meiEventTypeAtVelocity)

Syntax

Visual Basic

Property EventEnable(Type As meiEventType) As Boolean
IDL Interface

[propget] HRESULT EventEnable([in] meiEventType eventType,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT EventEnable([in] meiEventType eventType,
[in] VARIANT_BOOL newVal)

See Also

EventEnableAll
EventEnableNone

Status

meiEventType


Motion.EventEnableAll

MEI Home
.

Motion.EventEnableAll

Description

Enables reporting of all events generated by the motion object to the host. Please refer to the events overview section for a list of events generated by the motion object.

Visual Basic Example

Controller.Motion(0).EventEnableAll

Syntax

Visual Basic

Sub EventEnableAll
IDL Interface

HRESULT EventEnableAll()

See Also

EventEnable
EventEnableNone

meiEventType

Events Overview


Motion.EventEnableNone

MEI Home
.

Motion.EventEnableNone

Description

Disables reporting of all events generated by the motion object to the host. Please refer to the events overview section for a list of events generated by the motion object.

Visual Basic Example

Controller.Motion(0).EventEnableNone

Syntax

Visual Basic

Sub EventEnableNone
IDL Interface

HRESULT EventEnableNone()

See Also

EventEnable
EventEnableAll

meiEventType

Events Overview


Motion.FlashSave

MEI Home
.

Motion.FlashSave

Description

Saves the current motion object settings to flash memory. This configuration will be loaded onto the controller during the next power up or controller reset.

Visual Basic Example

Controller.Motion(3).FlashSave

Syntax

Visual Basic

Sub FlashSave()
IDL Interface

HRESULT FlashSave()

See Also

Controller Object:
FlashSave
FlashSaveAll

Axis Object:
FlashSave


Motion.Axes

MEI Home
.

Motion.Axes

Description

Specifies which axes this motion object coordinates.

Type

Array of Long

Visual Basic Example

The following code connects motion(0) with axis 0.

Controller.Motion(0).Axes = Array(0)

The following code connects motion(1) with axis 1 and 2.

Controller.Motion(1).Axes = Array(1,2)

The following code disconnects motion(2) from all axes.

Controller.Motion(2).Axes = Array()

The following diagram shows the resulting object relationships from the above code.

Syntax

Visual Basic

Property Axes() As Long
IDL Interface

[propget] HRESULT Axes([out, retval] SAFEARRAY(long)* pVal)

[propput] HRESULT Axes([in] SAFEARRAY(long) newVal)

See Also

Refresh


Motion.Refresh

MEI Home
.

Motion.Refresh

Description

The axis map a motion object is using can be changed without the MEI ActiveX control knowing. For example if an MPI application or Motion Console uses a different mapping it will overwrite the axis mapping that the ActiveX control was initialized with. This method interrogates the motion controller to find out what the current axis map is and updates the motion object's axes property.

Visual Basic Example

Controller.Motion(3).Refresh

Syntax

Visual Basic

Sub Refresh()
IDL Interface

HRESULT Refresh()

See Also

Axes


Motion.SCurve

MEI Home
.

Motion.SCurve

Description

Initiates a point-to-point motion using an "S" shaped velocity profile similar to that shown below. This move type generates a motion that takes the same time as the trapezoidal move but allows the acceleration to have smoother transitions. This comes at the expense of requiring a larger peak accelerations and decelerations. The total move time is always the same as the equivalent trapezoidal move.

See the section on synchronized motion for when either the meiSyncStart or meiSyncEnd attributes are specified.

Arguments

Argument Type Description
Position Variant

The absolute target position in counts.

This argument will generally be an array of doubles where the number of elements in this array must match the number of mapped axes. If only one axis is mapped then a double can be used instead of an array.

Speed Variant
(optional)

The maximum speed, in counts/sec, that will be achieved during the move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Accel Variant
(optional)

The acceleration, in counts/sec2, during the acceleration phase of the similar trapeziodal move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Decel Variant
(optional)

The deceleration, in counts/sec2, during the deceleration phase of the similar trapeziodal move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

JerkPercent Variant
(optional)

The percentage of the acceleration and deceleration phases that has an S curve.

This argument varies between 0%, and 100%. If the JerkPercent is zero then the move is the same as the basic trapezoidal motion.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Attributes meiMoveAttr
(optional)

Flags that modify the motion.

If this argument is omitted then no attributes are assumed and the standard action is generated.

Errors

Argument Type mismatch

Visual Basic Example

The following code will move axis 3 to position 1000.

Controller.Motion(3).Axes = 3
Controller.Motion(3).SCurve 1000

The following code will move axes 3 and 4 in a straight line to position 1000,2000.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).SCurve Array(1000,2000)

The following code will move axes 3 and 4 in a straight line to position (1000,2000) overriding the default speed with 200 counts/sec.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).SCurve Array(1000,2000),
        Speed:=200

Syntax

Visual Basic

Sub SCurve(Position As Variant,
Speed As Variant,
Accel As Variant,
Decel As Variant,
JerkPercent As Variant,
Attributes As meiMoveAttr)
IDL Interface

HRESULT SCurve([in] VARIANT Position,
[in] VARIANT speed,
[in] VARIANT accel,
[in] VARIANT decel,
[in] VARIANT jerkPercent,
[in] meiMoveAttr attributes)

See Also

Traezoidal
SCurveJerk

meiMoveAttr

Synchronized Attributes


Motion.SCurveJerk

MEI Home
.

Motion.SCurveJerk

Description

This method of a motion object initiates a point-to-point motion using an "S" shaped velocity profile similar to that shown below. This move type allows the magnitude of the jerk (the first derivative of acceleration) used during the acceleration or deceleration to be specified.

See the section on synchronized motion for when either the meiSyncStart or meiSyncEnd attributes are specified.

Arguments

Argument Type Description
Position Variant

The absolute target position in counts.

This argument will generally be an array of doubles where the number of elements in this array must match the number of mapped axes. If only one axis is mapped then a double can be used instead of an array.

Speed Variant
(optional)

The maximum speed, in counts/sec, that will be achieved during the move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Accel Variant
(optional)

The maximum acceleration, in counts/sec2, that will be achieved during the move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Decel Variant
(optional)

The maximum deceleration, in counts/sec2, that will be achieved during the move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

AccelJerk Variant
(optional)

The jerk, in counts/sec3, that will be used in the acceleration phase for this move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

DecelJerk Variant
(optional)

The jerk, in counts/sec3, that will be used in the deceleration phase for this move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Attributes meiMoveAttr
(optional)

Flags that modify the motion.

If this argument is omitted then no attributes are assumed and the standard action is generated.

Visual Basic Example

The following code will move axis 3 to position 1000.

Controller.Motion(3).Axes = 3
Controller.Motion(3).SCurveJerk 1000

The following code will move axes 3 and 4 in a straight line to position 1000,2000.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).SCurveJerk Array(1000,2000)

The following code will move axes 3 and 4 in a straight line to position (1000,2000) overriding the default speed with 200 counts/sec.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).SCurveJerk Array(1000,2000),
        Speed:=200

Syntax

Visual Basic

Sub SCurve(Position As Variant,
Speed As Variant,
Accel As Variant,
Decel As Variant,
AccelJerk As Variant,
DecelJerk As Variant,
Attributes As meiMoveAttr)
IDL Interface

HRESULT SCurveJerk([in] VARIANT Position,
[in] VARIANT speed,
[in] VARIANT accel,
[in] VARIANT decel,
[in] VARIANT accelJerk,
[in] VARIANT decelJerk,
[in] meiMoveAttr attributes)

See Also

Traezoidal
SCurve

meiMoveAttr

Synchronized Attributes


Motion.Trapezoidal

MEI Home
.

Motion.Trapezoidal

Description

Initiates a point-to-point motion using a trapezoidal velocity profile similar to that shown below.

Arguments

Argument | Type | Description
Position | Variant | The absolute target position in counts. This argument will generally be an array of doubles where the number of elements in this array must match the number of mapped axes. If only one axis is mapped then a double can be used instead of an array.
Speed | Variant (optional) | The maximum speed, in counts/sec, that will be achieved during the move. The section on synchronized motion summarizes the different data types and default values this argument uses.
Accel | Variant (optional) | The acceleration, in counts/sec2, that will be used for this move. The section on synchronized motion summarizes the different data types and default values this argument uses.
Decel | Variant (optional) | The deceleration, in counts/sec2, that will be used for this move . The section on synchronized motion summarizes the different data types and default values this argument uses.
Attributes | meiMoveAttr (optional) | Flags that modify the motion. If this argument is omitted then no attributes are assumed and the standard action is generated.

Visual Basic Example

The following code will move axis 3 to position 1000.

Controller.Motion(3).Axes = 3
Controller.Motion(3).Trapezoidal 1000

The following code will move axes 3 and 4 in a straight line to position 1000,2000.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).Trapezoidal Array(1000,2000)

The following code will move axes 3 and 4 in a straight line to position (1000,2000) overriding the default speed with 200 counts/sec.

     Controller.Motion(3).Axes
        = Array(3,4)
Controller.Motion(3).Trapezoidal Array(1000,2000),
        Speed:=200

Syntax

Visual Basic

Sub Trapezoidal(Position As Variant,
Speed As Variant,
Accel As Variant,
Decel As Variant,
Attributes As meiMoveAttr)
IDL Interface

HRESULT Trapezoidal([in] VARIANT position,
[in] VARIANT speed,
[in] VARIANT accel,
[in] VARIANT decel,
[in] meiMoveAttr attributes)

See Also

SCurve
SCurveJerk

meiMoveAttr

Synchronized Attributes


Motion.Velocity

MEI Home
.

Motion.Velocity

Description

This method of a motion object starts the axes moving at a continuous velocity as using an "S" shaped velocity profile similar to that shown below. This move type is the same as the acceleration phase of the SCurve move, allowing the acceleration to have smoother transitions. This comes at the expense of requiring a larger peak accelerations and decelerations.

The axes will continue to move at the specified velocity until a new velocity is commanded (by calling this method again with the meiMoveAttrModify attribute). The move is finished by using the Stop command.

See the section on synchronized motion for when either the meiSyncStart or meiSyncEnd attributes are specified.

Arguments

Argument Type Description
Velocity Variant

The target velocity in counts/sec2.

This argument will generally be an array of doubles where the number of elements in this array must match the number of mapped axes. If only one axis is mapped then a double can be used instead of an array.

Accel Variant
(optional)

The average acceleration, in counts/sec2, during the acceleration phase of the similar constant acceleration move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

JerkPercent Variant
(optional)

The percentage of the acceleration phase that has an S curve. This argument varies between 0%, and 100%.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Attributes meiMoveAttr
(optional)

Flags that modify the motion.

If this argument is omitted then no attributes are assumed and the standard action is generated.

Visual Basic Example

The following code will start a continuous move of 1000 counts/sec on axis 3.

Controller.Motion(3).Axes = 3
Controller.Motion(3).Velocity 1000

The following code will change the target velocity to 500 counts per second.

Controller.Motion(3).Velocity 500, attributes:=meiMoveAttrModify

The following code will bring the axis to a stop before terminating the velocity motion. The stop command could be used by itself but the StopTime property would determine the deceleration.

    Controller.Motion(3).Velocity 0,
        attributes:=meiMoveAttrModify
Controller.Motion(3).Stop

The following code will move axes 3 and 4 in a straight line with velocity components of 1000 and 2000 counts/sec respectively.

Controller.Motion(3).Axes = Array(3,4)
Controller.Motion(3).Velocity Array(1000,2000) Syntax

Syntax

Visual Basic

Sub Velocity(Velocity As Variant,
Accel As Variant,
JerkPercent As Variant,
Attributes As meiMoveAttr)
IDL Interface

HRESULT Velocity([in] VARIANT Velocity,
[in] VARIANT accel,
[in] VARIANT jerkPercent,
[in] meiMoveAttr attributes)

See Also

VelocityJerk

meiMoveAttr

Synchronized Attributes


Motion.VelocityJerk

MEI Home
.

Motion.VelocityJerk

Description

This method of a motion object starts the axes moving at a continuous velocity as using an "S" shaped velocity profile similar to that shown below. This move type allows the magnitude of the jerk (the first derivative of acceleration) used during the acceleration to be defined.

The axes will continue to move at the specified velocity until a new velocity is commanded (by calling this method again with the meiMoveAttrModify attribute). The move is finished by using the Stop command.

See the section on synchronized motion for when either the meiSyncStart or meiSyncEnd attributes are specified.

Arguments

Argument Type Description
Velocity Variant

The target velocity in counts/sec2.

This argument will generally be an array of doubles where the number of elements in this array must match the number of mapped axes. If only one axis is mapped then a double can be used instead of an array.

Accel Variant
(optional)

The maximum acceleration, in counts/sec2, that will be achieved during the move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

AccelJerk Variant
(optional)

The jerk, in counts/sec3, that will be used in the acceleration phase for this move.

The section on synchronized motion summarizes the different data types and default values this argument uses.

Attributes meiMoveAttr
(optional)

Flags that modify the motion.

If this argument is omitted then no attributes are assumed and the standard action is generated.

Visual Basic Example

The following code will start a continuous move of 1000 counts/sec on axis 3.

Controller.Motion(3).Axes = 3
Controller.Motion(3).VelocityJerk 1000

The following code will change the target velocity to 500 counts per second.

Controller.Motion(3).VelocityJerk 500, attributes:=meiMoveAttrModify

The following code will bring the axis to a stop before terminating the velocity jerk motion. The stop command can be used by itself but the StopTime property would determine the deceleration.

Controller.Motion(3).VelocityJerk 0, attributes:=meiMoveAttrModify
Controller.Motion(3).Stop

The following code will move axes 3 and 4 in a straight line with velocity components of 1000 and 2000 counts/sec respectively.

Controller.Motion(3).Axes = Array(3,4)
Controller.Motion(3).VelocityJerk Array(1000,2000)

Syntax

Visual Basic

Sub VelocityJerk(Velocity As Variant,
Accel As Variant,
AccelJerk As Variant,
Attributes As meiMoveAttr)
IDL Interface

HRESULT VelocityJerk([in] VARIANT Velocity,
[in] VARIANT accel,
[in] VARIANT accelJerk,
[in] meiMoveAttr attributes)

See Also

Velocity

meiMoveAttr

Synchronized Attributes


Motion.State

MEI Home
.

Motion.State

Description

The current state of the motion object.

When in the idle state, the motion object waits for motion start commands (Trapezoidal, SCurve, SCurveJerk, Velocity, VelocityJerk etc.) to be executed. If the motion command is successful the state will become Moving while the axes are moving. Once the move has completed the state will automatically return to Idle.

The Stopping state allows the current motion to be paused (by decelerating to zero speed within the StopTime) using the Stop command. The Resume command will allow the remainder of the move to be completed.

There are two error states: Error and Stopping Error. The Stopping Error state can be entered by executing the EStop command. This will decelerate the axis to zero speed within the EStopTime, before entering the Error state. The error state can also be entered directly by executing the Abort command; this will immediately stop the current motion. The motion state will stay in the Error state until a Reset command is executed.

Either the Abort or EStopAbort actions will disable the amplifies and force the DAC to output zero (plus the DACOffset) when they enter the Error state; the EStop action will leave the DAC outputs servoing and the amplifiers enabled.

Many events can be programmed to automatically generate state transitions. Each such event has an action property that defines the automatic action taken when the event is generated. For example the default action for the AmpFault event is to Abort.

This property cannot be saved to flash memory.

Type

meiState (read only)

Visual Basic Example

x = Controller.Motion(3).State

Syntax

Visual Basic

Property State As meiState
IDL Interface

[propget] HRESULT State([out, retval] meiState *pVal)

See Also

Abort
Stop
EStop
EStopAbort
Reset
Resume
AmpEnable

meiState


Motion.Status

MEI Home
.

Motion.Status

Description

This property of the motion object returns the current state of each events generated by the motion object. After an event has occurred the Status will report True until it is cleared. The Type argument defines all the possible event types, many of which are not generated by this object. Trying to read the state for these events will generate an error.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description
Type | meiStatus | The type of status being read.

Type

Boolean (read only)

Visual Basic Example

The following code will get the state of the "At Velocity" event.

x = Controller.Motion(3).Status(meiStatusAtVelocity)

Syntax

Visual Basic

Property Status(Type As meiStatus) As Boolean
IDL Interface

[propget] HRESULT Status([in] meiStatus Type,
[out, retval] VARIANT_BOOL *pVal)

See Also

EventEnable


Motion.ActualPosition

MEI Home
.

Motion.ActualPosition

Description

The current actual position of all the axes associated with the motion object. The number of elements in the array is the same as the number of axes mapped to this Motion object.

This property cannot be saved to flash memory.

Units

counts

Type

Array of Double (read only)

Visual Basic Example

x = Controller.Motion(3).ActualPosition

Syntax

Visual Basic

Property ActualPosition As Double()
IDL Interface

[propget] HRESULT ActualPosition([out, retval] SAFEARRAY(double) *pVal)

See Also

Motion Object:
CommandPosition
PositionError
ActualVelocity

Axis Object:
CommandPosition
PositionError
ActualVelocity


Motion.ActualVelocity

MEI Home
.

Motion.ActualVelocity

Description

The current actual velocity of all the axes associated with the motion object. The number of elements in the array is the same as the number of axes mapped to this Motion object.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Array of double (read only)

Visual Basic Example

x = Controller.Motion(3).ActualVelocity

Syntax

Visual Basic

Property ActualVelocity As Double()
IDL Interface

[propget] HRESULT ActualVelocity([out, retval] SAFEARRAY(double) *pVal)

See Also

Motion Object:
ActualPosition
CommandPosition
PositionError

Axis Object:
ActualPosition
CommandPosition
PositionError


Motion.CommandPosition

MEI Home
.

Motion.CommandPosition

Description

The current commanded position of all the axes associated with the motion object. The number of elements in the array is the same as the number of axes mapped to this Motion object.

This property cannot be saved to flash memory.

Units

counts

Type

Array of Double (read only)

Visual Basic Example

x = Controller.Motion(3).CommandPosition

Syntax

Visual Basic

Property CommandPosition As Double()
IDL Interface

[propget] HRESULT CommandPosition([out, retval] SAFEARRAY(double) *pVal)

See Also

Motion Object:
ActualPosition
PositionError
ActualVelocity

Axis Object:
ActualPosition
PositionError
ActualVelocity


Motion.CommandVelocity

MEI Home
.

Motion.CommandVelocity

Description

The current commanded velocity of all the axes associated with the motion object. The number of elements in the array is the same as the number of axes mapped to this Motion object.

This property cannot be saved to flash memory.

Units

counts/sec

Type

Array of Double (read only)

Visual Basic Example

x = Controller.Motion(3).CommandPosition

Syntax

Visual Basic

Property CommandPosition As Double()
IDL Interface

[propget] HRESULT CommandVelocity([out, retval] SAFEARRAY(double) *pVal)

See Also

Motion Object:
ActualPosition
PositionError
ActualVelocity

Axis Object:
ActualPosition
PositionError
ActualVelocity


Motion.PositionError

MEI Home
.

Motion.PositionError

Description

The current position error (the difference between the commanded and actual positions) of all the axes associated with the motion object. The number of elements in the array is the same as the number of axes mapped to this Motion object.

This property cannot be saved to flash memory.

Units

counts

Type

Array of Double (read only)

Visual Basic Example

x = Controller.Motion(3).PositionError

Syntax

Visual Basic

Property PositionError As Double()
IDL Interface

[propget] HRESULT PositionError([out, retval] SAFEARRAY(double) *pVal)

See Also

Motion Object:
ActualPosition
CommandPosition
ActualVelocity

Axis Object:
ActualPosition
CommandPosition
ActualVelocity


Recorder Object

.

Recorder Object

The Recorder object allows applications to capture a set of data points every sample or every n milliseconds. This allows data to be to be analyzed and/or plotted real-time.

Configuration

PointCount
PointCountMax
PointSource
PointDataType
PointMask

Period
Actions

Start
Stop

AddBuffer
RemoveBuffers

Status
 | Status
Events
 | EventEnable EventEnableAll EventEnableNone


Recorder.AddBuffer

MEI Home
.

Recorder.AddBuffer

Description

Creates a buffer of Recorder.PointCount points and samples number of samples that the recorder object will fill and return to the OnRecorderBufferDone event once full.

NOTE: The property Recorder.PointCount cannot be changed while a recorder object has buffers left to be filled. To remove buffers from a recorder, use the Recorder.RemoveBuffers method.

Arguments

Argument | Type | Description
Name | Type | The number of samples of data the new buffer is to hold

Visual Basic Example

controller.Recorder(0).AddBuffer 1000

Syntax

Visual Basic

Sub AddBuffer(samples As Long)
IDL Interface

HRESULT AddBuffer([in] long samples)

See Also

Start
RemoveBuffers

Controller Object:
 OnRecorderBufferDone


Recorder.RemoveBuffers

MEI Home
.

Recorder.RemoveBuffers

Description

Removes all data buffers from a recorder object.

Visual Basic Example

controller.Recorder(0).RemoveBuffers

Syntax

Visual Basic

Sub RemoveBuffers()
IDL Interface

HRESULT RemoveBuffers()

See Also

AddBuffer


Recorder.Start

MEI Home
.

Recorder.Start

Description

Starts the recorder. Upon filling a buffer, the recorder will fire an OnRecorderBuferDone event. Once the recorder has processed all buffers, it will automatically stop.

Visual Basic Example

Controller.Recorder(0).Start

Syntax

Visual Basic

Sub Start()
IDL Interface

HRESULT Start()

See Also

Stop

Controller Object:
OnRecorderBufferDone


Recorder.Stop

MEI Home
.

Recorder.Stop

Description

Stops the recorder if it is currently running.

Visual Basic Example

Controller.Recorder(0).Stop

Syntax

Visual Basic

Sub Stop()
IDL Interface

HRESULT Stop()

See Also

Start


Recorder.Period

MEI Home
.

Recorder.Period

Description

The time in seconds between successive samples. A value of zero means the recorder will record data every sample.

NOTE: All values will be truncated to the next smallest millisecond value.

Units

Seconds

Type

Double

Visual Basic Example

Controller.Recorder(0).Period = .01 '10 ms.

x = Controller.Recorder(0).Period

Syntax

Visual Basic

Property Period As Double
IDL Interface

[propget] HRESULT Period([out, retval] double *pVal)

[propput] HRESULT Period([in] double newVal)

See Also


Recorder.PointCount

MEI Home
.

Recorder.PointCount

Description

The number of records the recorder object uses while recording.

Type

Long

Visual Basic Example

Controller.Recorder(0).PointCount = 3

x = Controller.Recorder(0).PointCount

Syntax

Visual Basic

Property PointCount As Long
IDL Interface

[propget] HRESULT PointCount([out, retval] long *pVal)

[propput] HRESULT PointCount([in] long newVal)

See Also

PointSource
PointDataType
PointMask


Recorder.PointCountMax

MEI Home
.

Recorder.PointCountMax

Description

Specifies the maximum value of the Recorder.PointCount property.

This property cannot be saved to flash memory.

Type

Long (read only)

Visual Basic Example

x = Controller.Recorder(0).PointCountMax

Syntax

Visual Basic

Property PointCountMax() As Long
IDL Interface

[propget] HRESULT PointCountMax([out, retval] long *pVal);

See Also

PointCount


Recorder.PointDataType

MEI Home
.

Recorder.PointDataType

Description

The data type of the indexth point.

NOTE: PointDataType will be modified when PointSource is set.

Arguments

Argument | Type | Description
Index | Long | The index of the record whose data type is to be accessed. Valid values are 0 to (PointCount-1) inclusive.

Type

meiDataType

Visual Basic Example

Controller.Recorder(0).PointDataType(1) = meiDataTypeFloat

x = Controller.Recorder(0).PointDataType(3)

Syntax

Visual Basic

Property PointDataType(Index As Long) As meiDataType

IDL Interface

[propget] HRESULT PointDataType([in] long Index
[out, retval] meiDataType *pVal)

[propput] HRESULT PointDataType([in] long Index
[in] meiDataType newVal)

See Also

PointCount
PointSource
PointMask


Recorder.PointMask

MEI Home
.

Recorder.PointMask

Description

The bit mask the indexth record. Only the bits specified by PointMask will be returned by GetData. For example, if PointMask is set to 12 (1100 in binary), then only the 3rd and 4th bits of the associated PointSource will be recorded.

PointMask is used only when PointDataType is an integer data type.

NOTE: PointMask will be modified when PointSource is set.

Arguments

Argument | Type | Description
Index | Long | The index of the record whose mask is to be accessed. Valid values are 0 to (PointCount-1) inclusive.

Type

Long

Visual Basic Example

Controller.Recorder(0).PointMask(1) = 7 'record only lowest 3 bits

x = Controller.Recorder(0).PointMask(3)

Syntax

Visual Basic

Property PointMask(Index As Long) As Long

IDL Interface

[propget] HRESULT PointMask([in] long Index
[out, retval] long *pVal)

[propput] HRESULT PointMask([in] long Index
[in] long newVal)

See Also

PointCount
PointSource
PointMask


Recorder.PointSource

MEI Home
.

Recorder.PointSource

Description

The string representing the data source for the indexth record.

NOTE: Setting PointSource will set PointDataType and PointMask to the default data type of specified data.

Arguments

Argument | Type | Description
Index | Long | The index of the record whose source string is to be accessed. Valid values are 0 to (PointCount-1) inclusive.

Type

String

Visual Basic Example

Controller.Recorder(0).PointSource(1) = "Axis[2].CommandVelocity"

x = Controller.Recorder(0).PointSource(3)

Syntax

Visual Basic

Property PointSource(Index As Long) As String

IDL Interface

[propget] HRESULT PointSource([in] long Index
[out, retval] BSTR *pVal)

[propput] HRESULT PointSource([in] long Index
[in] BSTR newVal)

See Also

PointCount
PointDataType
PointMask


Recorder.EventEnable

MEI Home
.

Recorder.EventEnable

Description

Enables or disables any of the events that are generated by the recorder object from being reported to the host. Please refer to the events overview section for a list of events generated by the recorder object.

Arguments

Argument | Type | Description
eventType | meiEventType | The type of event to be accessed

Type

Boolean

Visual Basic Example

Controller.Recorder(0).EventEnable(meiEventTypeRecorderDone) = True

Syntax

Visual Basic

Property EventEnable(eventType As meiEventType) As Boolean
IDL Interface

[propget] HRESULT EventEnable([in] meiEventType eventType,
[out, retval] VARIANT_BOOL *pVal)

[propput] HRESULT EventEnable([in] meiEventType eventType,
[in] VARIANT_BOOL newVal)

See Also

EventEnableAll
EventEnableNone

meiEventType

Events Overview


Recorder.EventEnableAll

MEI Home
.

Recorder.EventEnableAll

Description

Enables reporting of all events generated by the recorder object to the host. Please refer to the events overview section for a list of events generated by the recorder object.

Visual Basic Example

Controller.Recorder(0).EventEnableAll

Syntax

Visual Basic

Sub EventEnableAll
IDL Interface

HRESULT EventEnableAll()

See Also

EventEnable
EventEnableNone

meiEventType

Events Overview


Recorder.EventEnableNone

MEI Home
.

Recorder.EventEnableNone

Description

Disables reporting of all events generated by the recorder object to the host. Please refer to the events overview section for a list of events generated by the recorder object.

Visual Basic Example

Controller.Recorder(0).EventEnableNone

Syntax

Visual Basic

Sub EventEnableNone
IDL Interface

HRESULT EventEnableNone()

See Also

EventEnable
EventEnableAll

meiEventType

Events Overview


Recorder.Status

MEI Home
.

Recorder.Status

Description

Reports whether the conditions necessary for generating the specified event are met.

This property cannot be saved to flash memory.

Arguments

Argument | Type | Description
Type | meiStatus | The type of event whose related status bit is being read.

Type

Boolean (read only)

Visual Basic Example

x = Controller.Recorder(0).Status(meiStatusRecorderFull)

Syntax

Visual Basic

Property Status(Type As meiStatus) As Boolean
IDL Interface

[propget] HRESULT Status([in] meiStatus Type,
[out, retval] VARIANT_BOOL *pVal)

See Also

EventEnable

meiStatus


MPX Quickstart Guide Home

.

For Visual Basic
 | Legal Information
 | Overview
 | Visual Basic Example Application
 | Error and Event Handling
 | Where to Get Help
For LabVIEW
 | Legal Information
 | Overview
 | LabVIEW Example Instrument
 | Error and Event Handling
 | Where to Get Help


MPX Documentation - Legal Information

.

9D00-0166 Rev. 1
Copyright Notice

Copyright © 2002 Motion Engineering, Inc.

This document contains proprietary and confidential information of Motion Engineering, Inc., and is protected by federal copyright law. The contents of the document may not be disclosed to third parties, translated, copied, or duplicated in any form, in whole or in part, without the express written permission of Motion Engineering, Inc.

Motion Engineering Inc.
33 South La Patera Lane
Goleta, CA 93117

http://www.motioneng.com/

Contents

Concepts
Documentation


MPX Quickstart Guide for LabVIEW - Legal Information

.

MPX Quickstart Guide

for

LabVIEW

9D00-0233 Rev. 2
Copyright Notice

Copyright © 2002 Motion Engineering, Inc.

This document contains proprietary and confidential information of Motion Engineering, Inc., and is protected by federal copyright law. The contents of the document may not be disclosed to third parties, translated, copied, or duplicated in any form, in whole or in part, without the express written permission of Motion Engineering, Inc.

Motion Engineering Inc.
33 South La Patera Lane
Goleta, CA 93117

http://www.motioneng.com/

Contents

Overview
LabVIEW Example Instrument
Error and Event Handling
Where to Get Help


Overview

.

Overview

This guide will take you through the process of adding the MPX control to the LabVIEW development environment and creating a simple instrument to perform trapezoidal type moves.

This guide assumes the following:

  • You have LabVIEW 5.0 or later installed.
  • You have an MPI compatible controller installed.
  • You have installed the version of the MPX library compatible with the installed MPI version of software and the installed controller firmware.
  • You have either:
    • Hooked up axis 0 to a physical system and tuned axis 0 with Motion Console
    • Or have an analog XMP and have set up axis 0 to use stepper motor mode with step-loopback enabled. This will allow motion to be simulated without a physical system being connected to the controller.

To enable step-loopback mode with and analog XMP, please run the Visual Basic script Simulate.vbs, available from the Start Menu: Start > Programs > Motion Engineering > Simulate.vbs


LabVIEW Example Instrument

.

LabView Example Instrument

This example assumes that you have set up axis 0 in Motion Console so that it is correctly tuned with the amplifier enabled an in an idle state, and is the only axis associated with motion 0.

Start LabVIEW. When the startup widow appears, press the New VI button.

A blank instrument panel, blank diagram, a Controls panel, and a Tools panel will appear.

Tools Panel

Controls Panel

Instrument Panel

Diagram

From the Controls Panel, click on the ActiveX button. A new ActiveX controls panel will appear. From this dialog, click on the Container control.

Now move the mouse to the instrument panel. You will be able to create an ActiveX container by clicking somewhere in the panel.

Once you create the control, the word "Container" will be highlighted. You can rename the container by typing in a new name. Rename the container "Controller" now.

Right click in the center of the container. A popup menu will appear.

Select Insert ActiveX Object.

A dialog box will appear. Unlike Visual Basic or some other applications, LabVIEW displays a list of objects, not type libraries. You will not see the MPX Library, only the Controller Class.

The listing of controls is sorted by ASCII character values. In other words, capital letters will appear before lower case letters.For example, "apple" will appear after "Zebra" and "Controller" will appear after "CWSlide."

From the list of objects, select Controller Class.

An MEI logo will appear on the instrument panel. This icon represents the MEI ActiveX Controller object.

Now switch to the Diagram window. You will see node representing named "Controller." This is the Controller object node.

Right click on the Controller node. A popup menu will appear. Select the following options:

Create --> Method --> Motion

A node representing the Motion method of the Controller object will appear. Place this node to the right of the controller node.

Go to the Tools panel and select the wiring tool. You can now connect the Controller node to the Motion method node.

Connect the two nodes as is shown to the right.

Go to the Functions panel and click on the Numeric functions button. A new Numeric panel will appear. Select the Numeric Constant icon.

We are now ready to run our application. Press the F5 key to start the application.

Place the constant in the diagram to the left of the Index input of the Motion node. Leave its value zero and wire the constant to the Index input.

Now, right click on the Motion output. A popup menu will appear. Select the following options:

Create --> Method -> Trapezoidal

Place the new node to the right of the Motion output. Wire the Motion output of the Motion node to the reference input of the Trapezoidal node.

Select another numeric constant from the Numeric palette and place it to the left of the speed input. Change the value of the constant to 1000. Right click on the constant. From the popup menu, select:

Representation --> DBL

This will change the representation of the constant to a double precision floating point number.

Now, wire the constant to the speed input.

Create another double precision numeric constant with the value 10000 and wire the constant to both the accel and decel inputs of the Trapezoidal node.

Click anywhere in the Instrument Panel. This will bring back the ActiveX controls panel. Click on the button with the arrow pointing up. This will bring back the Controls panel.

Click on the Numeric controls button. From the new Numeric panel, select the Digital Control icon.

Place the digital control on the Instrument Panel, next to the MEI controller icon and name the control "Target."

Return to the Diagram window. Move the Target node below the Motion node. Wire the Target node to the position input of the Trapezoidal node.

Go back to the Instrument Panel, and enter 5000 into the Target control.

Now, execute the VI by clicking on the Run button

The motor connected to Axis 0 will now move to a position of 5000. You may watch the actual and command positions of the axis change in Motion Console.

Congratulations! You have completed and run your first virtual instrument with the MPX control. Experiment with this VI by changing the target position into the text box and pressing the Run button.

If you want to learn a little bit about error handling and events, please continue on to the next section.


Where to Get Help

.

Where to Get Help

A help file is provided with the MPX control. It can be accessed via the Start Menu:

Start > Program Files > Motion Engineering > MPX > MPX Documentation

Our on-line help system is also accessible. Our technical support website can be accessed at http://support.motioneng.com.


MPX Quickstart Guide for Visual Basic - Legal Information

.

MPX Quickstart Guide

for

Visual Basic

9D00-0232 Rev. 3
Copyright Notice

Copyright © 2002 Motion Engineering, Inc.

This document contains proprietary and confidential information of Motion Engineering, Inc., and is protected by federal copyright law. The contents of the document may not be disclosed to third parties, translated, copied, or duplicated in any form, in whole or in part, without the express written permission of Motion Engineering, Inc.

Motion Engineering Inc.
33 South La Patera Lane
Goleta, CA 93117

http://www.motioneng.com/

Contents

Overview
Visual Basic Example Application
Error and Event Handling
Where to Get Help


Overview

.

Overview

This guide will take you through the process of adding the MPX control to the Visual Basic development environment and creating a simple application to perform trapezoidal type moves.

This guide assumes the following:

  • You have Visual Basic 5.0 or later installed
  • You have an MPI compatible controller installed
  • You have installed the version of the MPX library compatible with the installed MPI version of software and controller firmware.
  • You have either:
    • Hooked up axis 0 to a physical system and tuned axis 0 with Motion Console
    • Or have an analog XMP and have set up axis 0 to use stepper motor mode with step-loopback enabled. This will allow motion to be simulated without a physical system being connected to the controller.

To enable step-loopback mode with an analog XMP, please run the Visual Basic script Simulate.vbs, available from the Start Menu: Start > Programs > Motion Engineering > Simulate.vbs


Visual Basic Example Application

.

Visual Basic Example Application

This example assumes that you have set up axis 0 in Motion Console so that it is already correctly tuned with the amplifier enabled an in an idle state.

Start Visual Basic. When the New Project widow appears, select Standard EXE and press the Open button.

An application with a blank form should appear. Using the mouse, right click within a blank area of the tools window. Select Components from the popup menu that appears.

Scroll down until you find MPX from Motion Engineering. Select it by clicking the checkbox next to its name and press the OK button.

You should now see an MEI icon in the tools window. This is the MPX control. You can add a MPX control to the form by double clicking on the MEI icon.

Set the name to “Controller” by changing the “(Name)” property in the Properties window. Add a button control to the form by double clicking the button icon in the tools window. Name it “MoveButton” and set its caption to “Move” by changing the “Caption” property in the Properties window.

Now add a TextBox control. Name it “Target” and set its “Text” attribute to “0”

Add a Timer control. Name it “Update” and change its “Interval” property to 50.

We are now finished adding the controls we need. Before we go any further, let us arrange the controls and change the size of the form to be more visually appealing.

We are now ready to add the code for the application. Double click on a blank area of the form. A code page for Form1 should appear with the outline of the subroutine Form_Load() written. Add in the code shown to the right.

This code tells Motion object 0 to control Axis 0 and sets the default motion parameters for Motion object 0.

Go back to the form layout window and double click on the Move button. Again, add in the code shown to the right.

Double click on the Timer control so we can add code to update the display of the axis position.

We are now ready to run our application. Press the F5 key to start the application.

Enter 5000 in the text box and press the Move button. The axis will move to position 5000 and the current axis position will be displayed.

Congratulations! You have completed your first application with the MPX control. Experiment with this application by entering different positions into the text box and pressing the Move button.

If you want to learn a little bit about error handling and events, please continue on to the next section.


Error and Event Handling

.

Error and Event Handling

Move the axis back to a position of 5000. Now enter 0 in the text box and click on the Move button twice. The second click will command another motion while the first motion is still being executed. This will cause the ActiveX control to raise a run-time error.

You will notice that a dialog appears announcing the error and from which the application cannot recover. Click on the End button to return to the Visual Basic development environment.

In a real application, we would not like an error to terminate our application. One way of solving this problem is to use Visual Basic’s error handling mechanism. We are going to modify MoveButton_Click() to employ this mechanism.

Go back to the code window for Form1. Add the code shown to the right to MoveButton_Click().

Now execute the application again by pressing F5. Move the axis to position 5000 and enter 0 in the text box. Now click on the Move button twice.

You will notice that message box appears instead. And best of all, when you press the OK button, the application will still be running.

Being able to trap run-time errors is good, but it would be better if we could prevent errors. We could prevent this error if we disabled the Move button while a motion was in progress. This would involve:

  • Disabling the Move button after the user clicked it.
  • Enabling the Move button once the motion was complete.

The first requirement seems easy to implement, but we can only implement the second if we can have the controller notify us that the motion is complete. Well, the MPX control allows this to happen through ActiveX events.

To define an ActiveX event callback function, we select the object creating the event from the left drop down box at the top of the code window—In this case we will select the Controller object.

Once we select the object, we need to select the event handler from the right drop down box at the top of the code window. We are interested in the Motion event Done, so we will select the handler OnMotionEvent.

The mouse will now be placed in a subroutine called Controller_OnMotionEvent.

We need to add code to this subroutine and to the Form_Load and MoveButton_Click subroutines as well.

Modify the code so that it is in agreement with the code shown to the right.

The new code in the subroutine MoveButton_Click will disable the Move button when a motion is commanded.

The code in the subroutine Controller_OnMotionEvent will enable the Move button when a Done event is received from Motion object 0.

The EventEnable call that was added to the subroutine Form_Load enables the reporting of the Done event. Without this call, the Controller_OnMotionEvent subroutine would never be called and the Move button never reenabled.

Now when you run the application and click on the Move button, the Move button will be disabled until the move is complete.

Congratulations! You have now learned a little bit about handling errors and events. For more sample applications, please see the ActiveX Visual Basic Sample Applications Guide.


DSP Software Home

.

DSP Manuals
 C Programming Manual
Sample Applications Manual

Application Notes
 20 MHz / 10MHz Clock Application Note
Sinusoidal Commutation Release Note


Utilities

.

Select a section below.


Bode Tool Home

.

Introduction
Connecting to a Drive
Running a Sine Sweep
Running an FFT Measurement
Plotting
View
Charts
Filter Simulation
Stability


Introduction

.

Introduction

The Bode Tool tests a system of one or two axes with a sine sweep and measures the closed loop frequency response.

From the closed loop response, the open loop response is simulated. A filter can be simulated and the filtered open and closed loop response can be simulated.

The results are plotted graphically, in addition to being made available as tab delimited text files for use in external analysis programs.

Testing can be performed with correlated excitation across two axes and the response of both axes can be tested simultaneously. This is useful for systems with cross-coupled axes (gantries, scara robots, etc.)


Connecting to a Drive

.

Connecting to a Drive

Local System

To test a system locally, leave the check box next to the Server Name edit box unchecked. This is the default configuration. This feature is useful for testing a networked system. Anything entered in the Server Name edit box will be ignored.

Network System

To test a system over a network, you will need to identify which computer you are accessing. Check the box next to the Server Name edit box. The Server Name edit box will become enabled. The name that you enter will be used to identify the computer (host machine). Enter either the computer name (ex: scara, see below) or use the IP address (ex: 205.254.239.104, see below).

The default Server Port number of 3300 is correct for most systems, although you can change this setting, if necessary.

The Controller Number parameter indicates the number of the controller in the system that is being tested (ex: Controller Number 0). For all single controller configurations, the Controller Number = 0.


Running a Sine Sweep

.

Running a Sine Sweep

To make a sine sweep measurement of the system, select "Sine Sweep" as the type of measurement from the Measurement menu bar (Measurement->Fourier->Sine Sweep).

Before performing a sine sweep test, several parameters must be set:

First Motor Number

This is the motor number of the primary motor to test. If two motors are being tested, the choice of which motor is the First Motor Number is arbitrary. However, this number must correspond to an enabled motor object (object enabled in firmware, not enabled at the amplifier).

First Motor Coefficient

This number scales the sine sweep signal for testing. When testing a single motor, this number should be left at 1.0. When testing two cross-coupled motors with different effective torque constants, this number can be useful. The allowed range on this number is +/- 2.0.

Second Motor Number

This number is similar to the first motor number. This number is only used if the check box next to the Second Motor Number edit box is checked. If that box is unchecked, no excitation will be sent to a second motor, nor will any data be calculated for a second motor. Two motors are often excited simultaneously if two motors are cross-coupled.

Second Motor Coefficient

The second motor coefficient is similar to the first motor coefficient. If the First and Second Motor Coefficients are both 1.0, the same excitation signal will be sent to both axes. If the signals are opposite in sign, the excitation will be effectively out-of-phase. If the cross-coupled axes do not have equivalent, effective motor torque constants, scaling the Second Motor Coefficient value to a value other than 1.0, while keeping the First Motor Coefficient = 1.0 will provide the intended flexibility when testing. This adjustment can be helpful when testing scara and other complex, cross-coupled axes. It will help differentiate between the cross coupled behavior associated with a derived/complex coupled axis showing motional interation and axes from a single non cross-coupled axis that showing no such interaction.

Phantom Motor Number

The phantom motor is no longer required in any MPI version using phase 2 SynqNet. If the phantom motor box is grayed out, you do not need to be concerned with the phantom motor, as it is not used.

This is the number of the motor object that generates the sine sweep signal. For safety reasons, this motor should not be connected to a physical motor. The only requirement for this motor is that the firmware has enough motors enabled to calculate this motor object. The number of enabled motor objects can be changed in Motion Console.

Start Frequency

This is the beginning of the sine sweep range. Frequencies that are below 1 Hz suffer from sine signal generation artifacts, which typically result in rough motion during testing. However, the data collected should only be slightly affected. Most systems controlled by an XMP will have an ideal response below 1 Hz.

End Frequency

This is the ending frequency of the sine sweep signal. The practical upper limit is the Nyquist frequency (1 / 2 * servo sample rate, default sample rate = 2000 Hz). While any data collected above the Nyquist frequency is not recommended, you can still test above this frequency. However, an upper limit of 20,000 Hz is enforced.

Step Percentage

The sine sweep is not a smooth ramping of a sine test signal. Rather, it is a series of sine signals that are momentarily constant in frequency and are stepped in frequency between adjacent frequencies. The entire sine sweep signal is continuous in time (i.e. no discontinuities in time). The size of the adjacent frequency steps are set by Step Percentage. Using a small Step Percentage (< 3%) will result in more frequency response collected, finer resolution of that data, and a longer test. A high Step Percentage (> 3%) will result in less frequency response data collected, coarser resolution of that data, and a shorter test. If the step percentage is too high, resonance data can be distorted, or miss a resonance altogether. A step percentage a 4% seems to be a good starting point for most systems. For example, if you had a Start Frequency of 1 Hz and a Step Percentage of 4%, you would get the following sine frequencies: 1.0 1.04 1.0816 1.124864 etc…

Amplitude

The sine test signal is scaled in DAC counts. The Amplitude is the peak amplitude of a sine sweep. Valid values are between 0 - 32767 (10 Volts output). Care should be taken to make sure that no clipping occurs. Values of 15000 or less are typically clipping free, but systems with a large resonances can clip even with lower values.

Implementation Details

In order for a sine sweep to be completed on the XMP, an axis that is not being tested must be used to help generate the sinusoidal disturbance. The program will generate a virtual (phantom) motion supervisor, axis, and motor of the "Phantom Motor Number" during testing and will remove the same objects once the testing is finished. This "phantom" axis can be one that is used by your system, but during the sine sweep its amplifier should be disabled. The program attempts to eliminate any disturbance signals that may affect the phantom axis (if one is hooked up). However, you should disable any system hooked up to the "phantom" axis.

Abort Button

WARNING: A sine sweep can take a long time and can easily introduce too much energy into a system if configured incorrectly. This can result in resonances being excited for a long period of time and possible overheating of motors. The Bode Tool does not have any way to recognize that a system has gone into an uncontrollable oscillation. The user is responsible for choosing parameters that will not result in dangerous or damaging motion if a physical motor is connected. If dangerous motion does occur, click on the large abort button that pops up upon the start of the test. The user can also press the space bar or the enter button to do the same when the abort button has focus (active window).

An abort causes the axis being tested to perform an abort action, perform a stop action on the phantom axis, and return the settings to their original state (remove sine sweep specific settings).

If the large abort button does not have focus (grey title bar), the space bar and enter button will not stop the test. The abort will lose focus when the mouse is clicked outside the large abort button window. Loss of focus can be seen by a change in the appearance of the abort button and a change in the abort button window title bar (turns to grey).

The Current Frequency is also shown in real time, along with a vertical bar that shows the current progress of the sine sweep (in time).

Motion States

The Bode Tool will attempt to clear errors on the phantom axis. If for some reason, the error will not clear, the program will pop up an error window asking you to fix the problem. An error state on the axis being tested will generate this pop up window:

If the axis being tested has an error, the program will not start testing until the error is cleared. Use Motion Console or a similar application to clear the error and start another test.

Command Line Switches

Command line switches allow automated Bode Tool operation from the command line. Refer to the usage and examples below.

Usage

bode_NT [-control <0-9>]
[-firstMotor <0-9>] [-secondMotor <0-9>] [-phantomMotor <0-9>]
[-startrFreq <0-20000>] [-endFreq <0-20000>]
[stepPercent <0-400>]
[-exciteAmp <0-32767>]
[-autoStart] [-autoStop]
[-noise]
[-numSamples <0- >]
[-fftPoints <0- >]
[-percentOverlap <0-50>]

Most command line switches shown above are direct analogies to the data that would be entered into the fields in the Bode Tool GUI.

Examples

bode_NT -control 1
Starts the Bode Tool on controller 1

bode_NT -exciteAmp 5000 -autoStart
Starts a sine sweep test with an amplitude of 8000 and a default frequency range.

bode_NT -firstMotor 3 -phantomMotor 5 -exciteAmp 5000 -autoStart
Starts a sine sweep test on motor 3 using motor 5 as the phasntom and amplitude of 5000.

Bode NT -noise -exciteAmp 5000
Starts a random noise test on motor 1 with an amplitude of 5000.

Notes

The -autoStart switch starts a sine sweep test with the specified command line settings as soon as the program starts. The results will be displayed when the test in completed. For safety reasons, the large abort button will be displayed during the test.

The -autoStop switch causes the Bode Tool to exit after the measurement is taken. Using this switch along with the -autoStart facilitates automated data collection with the Bode Tool using a batch file or something similar. In this situation, renaming and saving fr.txt will make it easier to collect frequency response measurements at many locations or perform other repetitive tests.

The -exciteAmp switch sets both the sine sweep amplitude and noise amplitude to the value specified by -exciteAmp.


Running an FFT Measurement

.

Running an FFT Measurement

To make an FFT measurement of the system, select "Noise" as the type of measurement from the Measurement menu bar (Measurement->FFT->Noise).

Before performing an FFT measurement, several parameters must be set:

First Motor Number

This is the motor number of the primary motor to test. If two motors are being tested, the choice of which motor is the First Motor Number is arbitrary. However, this number must correspond to an enabled motor object (object enabled in firmware, not enabled at the amplifier).

First Motor Coefficient

This number scales the sine sweep signal for testing. When testing a single motor, this number should be left at 1.0. When testing two cross-coupled motors with different effective torque constants, this number can be useful. The allowable range of this number is +/- 2.0.

Second Motor Number

Not used in FFT measurements at this time.

Second Motor Coefficient

Not used in FFT measurements at this time.

Closed Loop Drop Down Box

This drop down box lets you select between velocity and position loop measurements.
When testing a control loop using the PID algorithm, use Position Closed Loop.
When testing a control loop using the PIV algorithm, use Velocity Closed Loop.

Number Samples

Number Samples sets the number of samples of data that will be collected. Keep in mind that the amount of time needed for the test is set by the sample rate. For example, 20,000 samples at a 2,000 Hz sample rate will result in 10 seconds of excitation. Increasing the number of samples will result in a longer test and less noise in the final measurement. The number of samples must be greater or equal to the number of FFT points.

Number FFT Points

Number FFT Points sets the resolution of the FFT measurement. The resolution of the FFT measurement is the Sample Rate / Number FFT Points. Low resolutions of FFT produce the least amount of noise, whereas high resolutions of FFT yield more noise.

For example, at a 2,000 Hz sample rate and 4096 FFT points, the FFT resolution is 0.49 Hz.

Increasing the Number FFT Points will increase FFT resolution and make the measurement noisier. By lowering the FFT resolution, you are essentially averaging more than one frequency together, thereby lowering the noise. (The FFT algorithm is designed to be efficient for most numbers of FFT Points.) The FFT algorithm is most efficient when using powers of 2 for the Number FFT Points.

NOTE: The FFT algorithm does not work well when prime numbers are used for the Number FFT Points.

Overlap %

Use the Overlap % parameter to adjust the overlap between FFT segments. This number can be adjusted from 0 - 100. A value of 50% is a good default setting.

Amplitude (DAC counts)

The sine test signal is scaled in DAC counts. The Amplitude is the peak amplitude of a sine sweep. Valid values are between 0 - 32767 (10 Volts output). It is important to ensure that no clipping occurs. Values of 15000 or less are typically clipping free, but systems with large resonances can clip, even when lower values are used.

Motion States

The Bode Tool will attempt to clear errors on the phantom axis. If for some reason, the error will not clear, the program will pop up an error window asking you to fix the problem. An error state on the axis being tested will generate this pop up window:

If the axis being tested has an error, the program will not start testing until the error is cleared. Use Motion Console or a similar application to clear the error and start another test.

Command Line Switches

Command line switches allow automated Bode Tool operation from the command line. Refer to the usage and examples below.

Usage

bode_NT [-control <0-9>]
[-firstMotor <0-9>] [-secondMotor <0-9>] [-phantomMotor <0-9>]
[-startrFreq <0-20000>] [-endFreq <0-20000>]
[stepPercent <0-400>]
[-exciteAmp <0-32767>]
[-autoStart] [-autoStop]
[-noise]
[-numSamples <0- >]
[-fftPoints <0- >]
[-percentOverlap <0-50>]

Most command line switches shown above are direct analogies to the data that would be entered into the fields in the Bode Tool GUI.

Examples

bode_NT -control 1
Starts the Bode Tool on controller 1

bode_NT -exciteAmp 5000 -autoStart
Starts a sine sweep test with an amplitude of 8000 and a default frequency range.

bode_NT -firstMotor 3 -phantomMotor 5 -exciteAmp 5000 -autoStart
Starts a sine sweep test on motor 3 using motor 5 as the phasntom and amplitude of 5000.

Bode NT -noise -exciteAmp 5000
Starts a random noise test on motor 1 with an amplitude of 5000.

Notes

The -autoStart switch starts a sine sweep test with the specified command line settings as soon as the program starts. The results will be displayed when the test in completed. For safety reasons, the large abort button will be displayed during the test.

The -autoStop switch causes the Bode Tool to exit after the measurement is taken. Using this switch along with the -autoStart facilitates automated data collection with the Bode Tool using a batch file or something similar. In this situation, renaming and saving fr.txt will make it easier to collect frequency response measurements at many locations or perform other repetitive tests.

The -exciteAmp switch sets both the sine sweep amplitude and noise amplitude to the value specified by -exciteAmp.


Plotting

.

Plotting

Showing the Plot

Click on the Display button to show a plot of the data that was collected from the test that was just run. Previously saved data can also be collected and graphed.

The default view is shown above. The red line is the closed loop response. The blue line is the open loop response (simulated from the closed loop response). The top half of the window is the Amplitude Response and the bottom half is the Phase Response.

Traces

Under Traces on the Bode Plot window menu, six traces can be selected. Each trace represents a different colored line displayed on the graph. This will allow you to choose which traces you wish to display in the graph. Simply click on a trace to either have the data graphed or not. The traces that will be graphed are denoted by a check mark. (The data collected from a sine sweep test is Closed Loop -> No Filter.)

The following traces are available:

Open Loop -> No Filter - This is the simulated open loop response calcluated from the closed loop data collected.

Open Loop -> Filtered - This is the simulated open loop response above with a simulated fitler simulated in addition.

Closed Loop -> No Filter - This is the data collected directly by the sine sweep test.

Closed Loop -> Fitlered - This is the data collected with the filter on the axis being tested applied via simulation.

Filter -> Current - This is a simulation of the filter on the controller.

Filter -> As measured - This is a simulation of the filter that was on the controller at the time the Bode data was taken.

Any combination of the above traces can be shown at the same time. Shown below is a plot of the open loop response, filter, and filtered open loop response of a particular system.

For more information on how the filters are simulated, see the Filter Simulation section.

Smoothing Data

You can smooth out noisy data with the Smooth Data menu item. The data smoothing is not saved to the file, so you don't have to worry about corrupting your data.

To smooth the data, click Traces -> Smooth Data. You will get a pop up window to select the amount of smoothing you want to perform.

You can choose the amount of smoothing you would like to perform by adjusting the slider or typing in a value into the edit box. The smoothing is performed by averaging all data points within x percent of the data point in question, where x is the smoothing value you choose in the smoothing pop up window.

An example of before and after smoothing:

Before:

After: The same data after 3 percent smoothing.


View

.

View

Grid Lines

The grid lines and labels can be removed by clicking View -> Grid. A check next to the menu item indicates whether the grids are enabled or not.

Cursors

The cursors can be removed by clicking View -> Cursors. A check next to the menu item indicates whether the cursors are enabled or not.

Sticky Windows

"Sticky Windows" can be turned on and off by clicking View -> Sticky Windows. "Sticky Windows" makes the Bode Tool and Bode View windows move together when the edges of the window are in close proximity and one of the windows is moved.

Refresh

When iterating through filters, it is convenient to quickly see the changes of the applied filter. Clicking View -> Refresh gets the filter parameters off of the controller and replots the response simulation.


Charts

.

Charts

A brief summary of each chart type is shown below. Only the Closed Loop Unfiltered Response is shown for visual clarity. The four plots below show the same set of data in the four different forms.

Bode

This is the Classic Frequency Response chart that shows Log Amplitude and phase vs. log scale frequency. The Phase Response is in the top half of the window, while the Amplitude Response is in the bottom half of the window.

Nyquist

The Nyquist (or polar) chart is often used to (though not limited to) determine the stability of a system. The Imaginary Linear Amplitude Response is plotted against the Real Linear Amplitude Response. The grid lines are unit circles.

Real / Imaginary vs. Phase

The Real / Imaginary vs. Frequency chart shows the Log Real Amplitude Reponse vs. Frequency in the top half of the window and the Log Imaginary Response vs. Frequency in the bottom half of the screen.

The Real / Imaginary vs. Frequency Response is often used to verify a resonance when the real response is at a local min or max, while the imaginary response is at a point of inflection at the same frequency.

Amplitude vs. Phase

The Amplitude vs. Phase chart simply plots the Log Amplitude Response vs. the Phase Response. This plot is often used in conjunction with a Nichols chart.


Filter Simulation

.

Filter Simulation

The Bode Tool can simulate the response of a system when a post filter is applied without having to retest the system with the newly applied filter. To perform this type of simulation, follow the procedure below.

Step 1 - Get the frequency response of the system

Here is a system with a load that resonates at 6.7 Hz with no post filter. The closed loop response is in red, with the open loop response in blue. The same system will be used for each step in this procedure.

We will use the open loop data to apply the filters and verify at the end that the closed loop response is what we desire. Notice that the resonance appears to be at ~12 Hz in the closed loop response, while it is at 6.7 Hz in the open loop response.

The post filters are applied to the open loop system, so we will use the open loop resonance frequency. This is normal.

Step 2 - Simulate the open loop response

Turn off the axis to be tested and apply the desired filter to the axis being tested. We will use a resonantor at 6.7 Hz in this example.

Once the filter is applied, click on View -> Refresh to get the current filter data from the controller and display the filtered and unfiltered open loop, and filter traces from the Traces menu item.

You can see that the resonance is largely eliminated. You can update the post filter as many times as you want, clicking on View -> Refresh to simulate the updated post filter. When the results are satisfactory, enable the drive and make some moves to make sure that the stage is still stable. If it is stable, proceed to the next step.

Step 3 - Simulate the closed loop response

Change the traces to the filtered and unfiltered closed loop, as well as the filter traces in the traces menu to verify the closed loop response. Repeat the filter and go back to step 2 if needed.

Step 4 - Verify the open loop response

After simulating the filter, retest the system to verify that the simulated system accurately represents the actual system. When simulating a filter, only use the unfiltered output, as the simulated filter trace takes the tested data and simulates the filter, effectively applying the filter twice (once while testing, once while simulating). The plot shown is the open loop response after the resonator has been applied. Comparing the response to the original data shows a good correlation between simulated filter response and actual filter response.

Step 5 - Verify the closed loop response

After getting the closed loop response where you want it, check the closed loop response and compare it to the simulated closed loop system. If the result is too different from the simulated result, make a change to the filter and interate until the results are acceptably close to the intended results.


Stability

.

Stability

A quantitative stability measurement is made when a bode test is run. The measurement is displayed quantitatively in the bottom right hand corner of the plotting window.

A visual representation of the measurement is shown in the Nyquist plot when the "Stability" trace is shown. To show the Nyquist plot, make sure Traces->Nyquist is checked. To see the stability measurement, make sure the Traces->Stability is checked. The stability measurement is shown as a black arrow. The length of the arrow is equal to the stability measurement value in the lower right of the plotting window.

The stability measurement is the distance between 0 dB, -180 degrees and the closest open loop response point. The 0 dB, -180 degree point represents an oscillator. In the example above, the stability measurement is 0.63.

The stability value ranges from 0 on up (x > 0). However, a realistic upper limit value of 1 would be normal. A stability measurement of 0 would represent an extrememly unstable system. A stability measurement of 1 would represent an extrememly stable system.

NOTE: The stability measurement is calculated off of the nearest open loop response point. No interpolation between points is performed for this measurement.

Back to Table of Contents


CANFlash Utility

.

The CANFlash Utility downloads, uploads, and erases the CANFlash memory on a CAN controller.

How to Use the CANFlash Utility

At the command line, type one of the following options:
ex: C:\mei\20021021\XMP\bin>canflash -d can002a3.out

Arguments

-? | Help
-d | This will download the specified outfile (*.out) to the specified CAN controller. NOTE: Download is the default option if no usage flag is specified. ex: C:Mei\20021021\Xmp\Bin>canflash can002a3.out
-u | This will upload the specified file (*.out) to the CAN controller.
-e | This will erase the contents of the CAN controller firmware from memory.

Examples

C:Mei\20021021\Xmp\Bin>canflash can002a3.out
C:Mei\20021021\Xmp\Bin>canflash -d can002a3.out
C:Mei\20021021\Xmp\Bin>canflash -u myfile.out
C:Mei\20021021\Xmp\Bin>canflash -e can002a3.out


Configuration Utility Home

.

Introduction
Command-Line Syntax
Examples
Firmware/Library Upgrades
Modifying Configuration
Open Issues


Introduction

.

Introduction

The XMP Configuration Utility provides a means of configuring the XMP using text files. The text files contain symbolic configuration data for MPI objects in a format that is independent of firmware version. You can get configuration data for MPI objects from XMP RAM or flash memory and save it to a text file. Similarly, you can load configuration data for MPI objects from a text file and set either XMP RAM or flash memory. Command line arguments to the config utility make it possible to selectively configure MPI objects.

The config utility makes it easy to upgrade to a new release of XMP firmware while retaining custom firmware configuration. It is also easy to configure the XMP without writing any code.


Command Line Syntax

.

Command Line Syntax

The config utility is located in the XMP\bin\WinNT directory of your MPI/XMP installation path. The command-line syntax is as follows:

config [-ram|-flash] [-map map-file] get output-file [object[#] ...]
config [-ram|-flash] [-map map-file] set input-file [object[#] ...]

Options:

-ram | use XMP's volatile memory (default)
-flash | use XMP's non-volatile (flash) memory
-map | use map-file in place of the default input map file
map-file | filename of input map file

NOTICE: The default input map file is named xmp###.map where ### is the firmware version number for which the config utility was built. It is installed into the XMP\bin\WinNT directory of your MPI/XMP installation path.

The input map file will be searched for in the directory from which the config utility was executed, the current directory, the Windows system directory (system32), the Windows directory and the directories in the PATH environment variable.

get | get configuration from XMP RAM or flash and save to output-file
set | load configuration from input-file and set XMP RAM or flash
output-file | path/filename for output configuration file
input-file | path/filename for input configuration file
object | MPI object(s) to get/set.

Case-sensitive values for the object are:

adc[#] | motion[#]
axis[#] | motor[#]
capture[#] | node[#]
control | recorder
dac[#] | sequence[#]
eventmgr | sercos[#]
filter[#] |

The absence of a number (i.e. #) immediately following an object on the command line indicates that all objects of that type are selected. Otherwise, only the object specified by the number is selected. Objects must be separated by a space. If no objects are specified, all objects are selected.


Examples

.

Examples

The examples below use a configuration file with a suffix of ".cfg". The use of this suffix is recommended, but it is not required.

To get RAM configuration of all MPI objects and save to a file: config get all.cfg

To get flash configuration of all MPI objects and save to a file: config -flash get all.cfg

To load configuration of all MPI objects from a file and set flash (non-volatile) memory: config -flash set all.cfg

To get RAM configuration for all axes and save to a file: config get axes.cfg axis

To get RAM configuration for axis 3 and filter 5 and save to a file: config get a3f5.cfg axis3 filter5

To load configuration of axis objects from a file and set flash (non-volatile) memory: config -flash set all.cfg axis

To load configuration of axis objects from a file and set RAM: config get control.cfg control

To set RAM configuration to an axis count of 8, create file axis.cfg with the following line: MPIControl Config.axisCount 8 config set axis.cfg control -OR- config set axis.cfg


Firmware/Library Upgrades

.

Firmware/Library Upgrades

Configuration files are usable with different firmware and library revisions, i.e. older configuration files will generally work with newer versions of the firmware and library. The exception is when a field from an older configuration file is no longer supported. In such a case, one of the following messages will be displayed: `field`: name not found

This message indicates that the `field` member of an MPI Config{} structure is either no longer supported or in error. `field`: `value`: name not found

This message indicates that the `field` member of an MPI Config{} structure is a pointer and the symbolic XMP address `value` is either no longer supported or in error.

In either case the field will be ignored.

If a new field has been added, there is no way for an older configuration file to handle it. Newly added fields will remain at their current value.

To upgrade to a new version of the MPI library and/or XMP firmware while retaining custom configuration, do the following:

config -flash get all.cfg
install new library and firmware
config -flash set all.cfg


Modifying Configuration

.

Modifying Configuration

It is possible to create a configuration file or to modify an existing one. For example, to modify gain configuration for filters 0 through 2, create a file called filter.cfg with the following lines:

MEIFilterConfig[0].GainSwitchType 0
MEIFilterConfig[0].GainDelay 0.000000
MEIFilterConfig[0].GainWindow 500
MEIFilterConfig[1].GainSwitchType 0
MEIFilterConfig[2].GainDelay 0.000000
MEIFilterConfig[1].GainWindow 500
MEIFilterConfig[2].GainSwitchType 0
MEIFilterConfig[2].GainDelay 0.000000
MEIFilterConfig[3].GainWindow 500

Changing the numeric value on the right hand side will change the configuration value on the XMP, only after you execute a config set command, such as any of the following:

config set filter.cfg
config set filter.cfg
filter config set filter.cfg filter0 filter1 filter2

You must not change the data type when you change a value. Values for type long may be specified in decimal, octal (leading 0) or hexadecimal (leading 0x). Values for type float or double must contain a decimal point. Values for type pointer must be a symbolic XMP address.


Open Issues

.

Open Issues

There is no backward compatibility with earlier configuration files. This is the only open issue at this time.

Back to Table of Contents


Flash Utility

.

The Flash Utility loads, saves, or erases flash memory on a motion controller card. It is also used to download FPGA binary images to the controller's flash memory.

Arguments

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-download | Download firmware file to flash memory (default).
-upload | Upload firmware file from flash memory.
-erase | Erase the controller's flash memory.
-fpga0 | Download FPGA #0 file to flash memory.
-fpga1 | Download FPGA #1 file to flash memory.

Examples

C:Mei\20030513\Xmp\Bin\>flash -download
C:Mei\20030513\Xmp\Bin\>flash -erase
C:Mei\20030513\Xmp\Bin\>flash -fpga0


memoryDump Utility

.

The memoryDump Utility either saves controller memory to a specified file or loads a specified file to controller memory.

Arguments

At the command line, type one of the following options:
ex: C:\mei\20030513\XMP\bin\WinNT>memoryDump -control 1

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.

Examples

C:Mei\20030513\Xmp\Bin\WinNT>memoryDump -control 1


Message Utility

.

The Message Utility will translate MPI message codes into text. This is useful in case an application only reports an error code and not the associated message.

NOTE: Error code values and their corresponding description may change from one software release version to the next.

Usage

At the command line, type one of the following options:
ex: C:\mei\XMP\bin\>message.exe

message [ msg# ]

Where

message.exe | Creates a complete list of return values (messages).
message # | Gives the return value of the specified message number. (ex: C:\mei\xmp\bin\winnt\message 1559)

Examples

C:\Mei\20030325\xmp\bin\winnt\message

C:\Mei\20030325\xmp\bin\winnt\message 10112
C:\Mei\20030325\xmp\bin\winnt\message 0x2780


Motion Console Home

.

Requirements and Safety
Introduction
Required Materials
Safety Precautions
Hardware Requirements and Installation
Motion Console
Object-oriented Motion Control
Motion Console Objects
Motion Console User Interface
 | Main Motion Console Frame
 | Adding a New Controller
 | Object Summary Windows
 | Object Explorer
 | Object List Configuration Dialog Boxes
Configuring New Systems with Motion Console
 | Getting Started with Motion Console
 | Saving Parameter Settings
 | Associating Objects with Motion Console
 | Configuring a Motion Supervisor
 | Mapping One Object to Another
 | Removing (Deleting) a Mapped Object
 | Safety Reminders
Motion Console Objects
 | Controller Object
 | Motion Supervisor Object
 | Axis Object
 | Filter Object
 | Motor Object
 | SynqNet Object
 | SqNode Object
 | CAN Network Object
 | CAN Node Object
 | I/O Object


Object Oriented Motion Control

.

Object-oriented Motion Control

The XMP motion control system is distinguished by its unparalleled flexibility in design. This is largely the result of two features: 1) a firmware-configured DSP processor which can be customized for efficient tasking; and, 2) a dual-library software architecture containing both general (MPI) and specialized (MEI) software objects. These objects encompass complex motion control functions, enabling the programmer to quickly build programs without writing hundreds or thousands of lines of code. Objects lend extraordinary portability to the software environment, allowing complex functions to be executed by calling them as single objects.

Motion Console embodies this object-oriented approach to motion control through its unique graphical user interface. It has been designed as a utility to assist programmers. It does not write custom applications. Rather, it provides an environment for the testing and monitoring of motion control components. This will prove extremely helpful to you when writing new applications, because it allows you to check your code against a proven interface. (For example, if your application fails to move a component, you can try Motion Console to see whether the problem lies within the hardware or software.)

This chapter will guide you through the basic use of Motion Console, and includes a description of objects and attributes. If you would like to try configuring a simple motion control system with Motion Console, please see the Quick-Start Guide, which accompanies MEI's Firmware Developer's Kit. Another helpful section is the Configuring New Systems with Motion Console section.


Motion Console Objects

.

Motion Console Objects

Motion Console divides motion control into several distinct software objects. Some of these objects have direct hardware equivalents, such as Motor objects. Other objects are more abstract and complicated, such as Filter objects. Motion Console provides direct configuration and monitoring of XMP motion control objects, including:

Motion Controller -- A single XMP controller, capable of controlling motion supervisors, and served by a host computer. A Controller folder lists the controllers served by the host computer, of which there may be more than one. However, each Controller demands its own separate motion controller hardware (i.e., one main controller board, with or without an attached expansion board).

Motion Supervisor -- Topmost level of motion control associated with a Controller. Each Motion Supervisor, in turn, has 0 (zero) or more Axes mapped to it.

Axis -- A motion vector associated with either linear (e.g., linear slide), or rotary (e.g., turntable) motion, and associated with a Motion Supervisor. Each Axis has 0 (zero) or more Filters mapped to it.

Filter -- Attributes applied to closed-loop motor control, such as gains and motion algorithms. Each Filter has 0 (zero) or more Motors mapped to it.

Motor -- A motor, which may be either rotary (such as a rotary motor shaft), or linear (such as a linear motor, pneumatic cylinder, hydraulic actuator, etc.).

SynqNet -- A SynqNet object manages a single SynqNet network that is connected to a motion controller. It represents the physical network. It contains information about the network state, number of nodes, and status.

SqNode -- A SqNode object manages a single SynqNet network node that is connected to a SynqNet network. It represents the physical network node. It contains information about the node, as well as its status and configuration. It provides read/write access to the node via network cyclic data and service commands. It also provides an interface to any drives connected to the node.

CAN Network -- A CAN Network object manages a single CANOpen network connected to a motion controller. It represents the physical network. It contains information about the network state and configuration.

CAN Node -- A CAN Node object manages a single CANOpen network node connected to a CANOpen network. It represents the physical network node. It contains information about the node, as well as its status and configuration.

I/O -- I/O objects in Motion Console represent the individual I/O associated with other objects. Currently, CAN Node and Motor objects support I/O, so the I/O Summary contains separate tabs for the I/O associated with those objects.

Mapping

"Mapping" means associating one object with another. For example, one axis may have one motor mapped to it (such as a motor-driven leadscrew on a slide), or one axis may have two motors mapped to it (such as a gantry crane).

Frequently, motion designers think of each axis in terms of a single motor; however, the XMP environment allows you to expand this model. For example, the X-Y table on a three-axis machine is simply controlled by two motors, each of which represents a single, independent axis. However, it may be advantageous to add a second motor to each axis, in order to obtain independent, rapid-coarse motion and slow-fine motion. In this model, each axis has two motors associated with it: one coarse, one fine. The choice of when to use what motor is performed by a Filter object, written into the custom application code. If the fine motor is commanded to move to a point outside its range, the filter object can be configured to use the coarse motor to reposition the axis. Once the coarse motor has positioned the axis at its starting point, the filter will switch to the fine motor. This level of flexibility is made possible by object mapping.

Motors 1 and 2 (M1 and M2) are mapped to Axis 1 (A1) on the X-axis. Motors 3 and 4 (M3 and M4) are mapped to Axis 2 (A2) on the Y-axis.

This allows one component to be associated with another by simply dragging one object to another on the computer screen with a mouse.

IMPORTANT! Object mappings, along with all other Motion Console settings, are NOT saved until the Save to Flash Memory [image] function is used on the Object Explorer or object summary window. If you do not save your settings to flash memory, your settings will be lost when the system is powered down, or when the controller is reset.

Before using Motion Console to map objects, it will help to review how the user interface is designed.


Main Motion Console Frame

.

Motion Console User Interface

Main Motion Console Frame

The outermost Motion Console window frame presents a toolbar at the top with several buttons. Each button function is summarized below.

Toolbar Functions

View Error List -- MPI library function errors are displayed in the Library Function Errors window. When there are no errors to display, the View Error List button is disabled. Otherwise, it is enabled and clicking on it opens the Library Function Errors window.

To empty the list, click on the Reset button. To close the list, click on either the Close button, or the close ("X") icon in the upper-right corner of the window. Some MPI error messages are described in the Software Reference.

New -- Clicking on the New Profile button will create a new initialization file (.INI), or profile. The default setting will initially display only the Object Explorer box with no controllers.

Open -- Clicking the Open Existing Profile button will open a specified .INI file.

Save As -- Clicking the Save Profile As button will save the current profile into the specified .INI file.

View Object Explorer -- Clicking on the View Object Explorer button displays the Object Explorer window. See the Object Explorer section for more information.

Open and Configure Controller Summary -- Clicking on this button opens and configures the Controller Summary window. See the Controller Objects section for more information.

Open and Configure Motion Supervisor Summary -- Clicking on this button opens and configures the Motion Supervisor Summary window. See the Motion Supervisor Objects section for more information.

Open and Configure Axis Summary -- Clicking on this button opens and configures the Axis Summary window. See the Axis Objects section for more information.

Open and Configure Filter Summary -- Clicking on this button opens and configures the Filter Summary window. See the Filter Objects section for more information.

Open and Configure Motor Summary -- Clicking on this button opens and configures the Motor Summary window. See the Motor Objects section for more information.

Open and Configure SynqNet Summary -- Clicking on this button opens and configures the SynqNet Summary window. See the SynqNet Objects section for more information.

Open and Configure SqNode Summary -- Clicking on this button opens and configures the SqNode Summary window. See the SqNode Objects section for more information.

Open and Configure CAN Network Summary -- Clicking on this button opens and configures the CAN Network Summary window. See the CAN Network Objects section for more information.

Open and Configure CAN Node Summary -- Clicking on this button opens and configures the CAN Node Summary window. See the CAN Node Objects section for more information.

I/O Summary -- Clicking on this button opens the I/O Summary window. See the I/O Objects section for more information.

Configure Grid Rows -- Clicking on this button displays a window to configure the Row Configuration of the highlighted Object Summary window. This allows the configfuration of each window to display only the required parameters. This will simplify the Motion Console interface and hide parameters that should not be modified. The Row Configuration settings can be saved to an initialization file.

Add Controller -- Clicking on this button adds a new Controller object. See "Controller Objects" section for more information.

Refresh -- Clicking on this button will refresh the Motion Console display. While the Status tabs at the bottom of the Object Summary windows are constantly updated, the Configuration tabs at the top are only updated when manually changed by the user, when Motion Console is restored after being minimized, or when the Refresh button is clicked. This is particularly helpful if another application is also accessing the XMP controller and changing the controller configuration.

Panic Button -- Clicking on this button activates a Panic action for each Motion Supervisor.

WARNING! The Panic Stop behaves according to the user-specified Panic Action parameter located in the Motion Supervisor Summary / Config tab. Depending upon how Panic Action is configured, a panic stop may initiate a slow or rapid motion stop, an error state, or no error at all. For details on configuring your Panic Stop, see the "Motion Supervisor Object" section below in this chapter. You must custom-configure your Panic Stop according to the level of control and safety required by your motion system!

NOTE-- The Shift and Ctrl keys can be used to modify the action performed when clicking on a toolbar button that opens a window. The modified actions are listed below:

  • Shift + button — Changes the state of the window. If the window is closed, it will be opened. If the window is open, it will be closed.

  • Ctrl + button — If the window is already open, it activates the window and brings it to the foreground. This is useful for locating a window that is buried under other windows.

Furthermore, for those buttons that open object summary windows, the Ctrl and Shift keys will cause the Summary Object List Configuration dialog box to be by-passed. The Summary window will be opened to the current configuration.


Adding a New Controller

.

Adding a New Controller

Recall that each Controller is represented by an actual, physical controller. Therefore, a new Controller cannot be added until a new motion controller has first been installed in the computer. After installation is complete, click on the Add Controller button on the toolbar of the Object Explorer to add a new controller.

Clicking on the Add Controller button displays the Add Controller dialog box. Enter the name of the new Controller in the Name field. This may be any alphanumeric label up to 27 characters long ("Controller 1," "XY Table," "Julie Ann," etc.). The Name need not be the same as the Controller Number, but many users find this less confusing.

There are three ways to address a new controller:

  • If only one controller is being installed on the host computer, simply assign a Name, then click on the OK button. The Controller number will be 0. This is the Default option.

  • Click on the Device tab if there is more than one controller card in the computer.

  • Click on the Client tab if the controller card resides inside a separate client computer (i.e., not in the same computer running Motion Console), linked across a TCP/IP network with it.

Device Settings

Device settings should be used whenever more than one XMP controller card is in the host system. If ALL controllers reside inside the host, you may ignore settings on the Client tab.

Controller Number -- the MEI-specific index, inside the device list, that is used by the computer to identify each controller. Although you may customize the name of the controller, you cannot customize the “Controller Number,” because it is already preconfigured to coordinate with the appropriate XMP controller board. For example, you can call a controller “Martha,” but if the Controller Number is 3, Motion Console will be referencing the 3rd board installed on your system.

Client Settings

NOTE: Before a client-based controller can be added to the object tree, the client computer must be running the server.exe utility. If you have not already done so, start the utility now before proceeding. Once server.exe is running, it can be "minimized" on the client computer's monitor and kept running in the background.

Client settings apply to XMP controllers which reside on separate client computers (i.e., computers other than the one running the Motion Console utility). To access a client controller, its client computer must be networked with the host computer and be running the server.exe application.

Controller Number -- the MEI-specific index, inside the device list, that is used by the computer to identify each controller. Although you may customize the name of the controller, you cannot customize the “Controller Number,” because it is already preconfigured to coordinate with the appropriate XMP controller board. For example, you can call a controller “Martha,” but if the Controller Number is 3, Motion Console will be referencing the 3rd board installed on your system.

Port -- Socket connection to use for the client. NOTE: In most cases this will be the same for host and client(s), and the default value (3300) can be used.

Server -- IP address of the client computer serving the XMP controller.

Error Messages

If error messages are encountered while adding a new controller, refer to the table below.

Add Controller Error Messages
 | Error Message | Controller Type | Action |
A | mpiControlInit failed while creating (controller name) | Device | Recheck hardware installation, especially PCI bus socket. | A
B |  |  | Open the "Control Panel" and double-click "Devices." Find the "MeiXMP" device and make sure its status is "started." | B
C |  |  | Swap XMP board with a reliable card in a reliable host computer. If card fails to respond, contact MEI. | C
D |  | Client | Recheck client address. | D
E |  |  | Verify that client is running server.exe application. | E
F |  |  | Refer to Actions A and C above. | F
G |  | Device | Verify Controller Number field under the Device tab is different from existing controller(s). | G
H |  | Client | Verify that Controller Number, Port and Server fields under the Client tab are different from existing controller(s). | H
I | MPIControlInit() returns 0x8603:Packet:communication error | All | Verify that client is running server.exe application. | I

Removing Controllers

Controllers may be removed quickly with the Object Explorer by highlighting the controller to be removed and clicking on the Remove Controller icon. A controller can also be removed by clicking on the Remove button for the controller on the Operations tab of the Controller Summary window.

A Note Regarding Synchronized Motion

Designers should bear in mind that Motion Console does NOT support synchronized motion between separate controllers. (For example, you cannot perform a precision, interpolated move between Controller 0 and Controller 1 using only Motion Console.) However, coordinated motion between controllers on the order of milliseconds is supportable from user-written applications. Please contact an MEI applications engineer.


Object Summary Windows

.

Object Summary Windows

Object Summary windows display the attributes of individual objects using a grid control, much like a spreadsheet. Each object is represented by a column and the attributes are represented by rows. For some objects, there are so many attributes that they are divided and categorized into several tab windows. The user can configure which objects are to be displayed by an Object Summary.

Configuring Object Summaries

Summary windows are configured to display objects directly or by association. For example, the Axis Summary can be configured to display a set of axes, such as Axis 0, Axis 1, and Axis 2, or it can be configured to display all the axes associated with a set of super-objects, such as MS 0, MS 1, and MS 2.

Object Summaries can be configured by using 1) the Object Explorer, or 2) the Object List Configuration dialog box, or 3) the View Sub-objects buttons on another Summary window. See the sections related to these windows for more information. The View Sub-objects buttons are described below.

View Sub-Objects

The View Sub-objects button is displayed as a general configuration item on most object windows. It is not displayed for DAC and IDN objects because they do not have any sub-objects. A "sub-object" is meant to signify any object that is mapped to another object, either directly or indirectly. The summaries shown are identical to those presented by clicking on summary icons in the Object Explorer. For example, clicking on the View Sub-objects button within the Controller Summary window displays eight types of subordinate objects:

A lower-level object such as the Filter object will display fewer sub-object types:

Sub-object summaries are displayed by selecting them with the mouse. More than one summary can be selected from a list by simultaneously holding down the key while clicking on both.

Anatomy of an Object Summary

Below is a diagram that illustrates the various parts of an Object Summary window.

"Configurable Attributes" versus "Status Parameters"

Some summary windows are divided into two sections. The top section of the window lists attributes which may be altered through direct data entry; these are configurable. The bottom section of the window contains read-only information regarding the status of objects; these are not configurable. An example of one such panel (an Axis summary) is shown below.

In this example, the bottom, read-only parameters provide status information about the axis; they cannot be manually changed. Attributes in the upper portion of summary windows may be altered by manually entering values.

Cell Controls

Each grid cell contains a user interface control that displays data and, for configurable attributes, allows the user to enter data. Below are shown some controls found within an object grid.

Edit Box -- Data is entered manually into the cell using the keyboard.

Combo Box -- Clicking on a cell yields a pull-down menu of options, which can be selected, or data can be manually entered via the keyboard. Combo boxes consist of two parts: 1) the edit box; 2) a drop-down button. If you choose to type in your selection manually, you must enter it exactly as shown in the list of options. Clicking on drop-down button will cause a window to appear that displays the option list. You may then click on a selection. If you do not want to use a mouse for entry, type to display the choice list and then use the navigation keys to make a selection. Every control type has a method for entering data without using the mouse.

Checklist Combo Box -- Similar to the regular combo box, except it has selectable check boxes.

Push Buttons -- Clicking on the button will cause an action to be performed on the selected object. If multiple buttons are selected in a row, then the action will be executed on all selected objects. Selecting buttons on multiple rows is not allowed. Buttons can also be activated by selecting the cell containing the button and pressing the Space bar.

Button Grid -- This is a set of Push Buttons displayed in a grid, with each button appearing in a separate row. Each individual button behaves exactly as a regular push button. Multiple buttons may be selected.

CAUTION! Parameter values take effect immediately. If you are entering a value which influences machine movement, be certain to keep clear of moving components!

Navigating Within a Summary

Mouse-less Navigation within a Summary Window

Tab -- Move the focus to the next control in the window.

Shift + Tab -- Move the focus to the previous control in the window.

<Arrow Key> -- Within a grid control, set the current cell to the adjacent cell in the direction of the arrow key. The arrows keys are also used to change the tab page on a tab control.

Ctrl + <Arrow Key> -- Set the current cell to the extreme cell in the direction of the arrow key. For example, Ctrl + sets the current cell to the right-most cell in the current row.

Ctrl + Home -- Set the current cell to the top, left-most cell.

Ctrl + End -- Set the current cell to the bottom, right-most cell.

Selecting Cells

To select a single cell within the the table, click on the cell. To toggle the selection state of a single cell, hold down the key while clicking on the cell. To select a range of cells, click on the first cell in the range, then hold down the shift key while clicking on the last cell in the range.

An entire row of cells can be selected by clicking on the row header button. An entire column can be selected by clicking on the column header button.

Cells can also be selected with the keyboard:

Shift + <Arrow Key> -- Set the current cell to the next cell in the direction of the arrow key and select both the new and previous current cell.

Shift + Ctrl <Arrow Key> -- Set the current cell to the extreme cell in the direction of the arrow key and select all cells between the former current cell and the new current cell.

Shift + Ctrl + Home -- Set the current cell to the top, left-most cell and select all cells in the range between the former current cell and the new current cell.

Shift + Ctrl + End -- Set the current cell to the bottom, right-most cell and select all cells in the range between the former current cell and the new current cell.

Copying Cell Data

It is possible to select cells within the grid, then copy them to another group of cells. (For example, when configuring two side-by-side columns.) Text values of selected cells can also be copied into the window's clip board by typing C, or using Edit / Copy.

Configure Grid Rows
The Configure Grid Rows button (Ctrl-R) will open a window that customizes the Object Summary display. This allows the user to select which parameters to display. This provides a simplified display for Motion Console that omits many unneeded or pre-configured parameters. It also hides parameters that should not be changed by users less familiar with the system.

In order to click the Configure Grid Rows button, one of the Object Summary windows must first be selected. Clicking the button will display a new window with all the parameters for the Object. Each parameter has a Check Box in the Hidden column. To hide a Row, simply select the appropriate Check Box. In the example below, the Axis Summary Row Configuration window is open. Note that the Relative Distance, AccelJerk and DecelJerk rows have been checked as Hidden. This causes the Axis Summary window to no longer displays these rows. To display these rows, simply un-check the appropriate box in the Row Configuration window.


Object Explorer

.

Object Explorer

The Object Explorer provides the topmost, "bird's eye" view of the XMP motion control system. Objects such as Motion Supervisors and Motors are grouped together in their own separate folders. When opened, folders reveal objects available for mapping.

In this example, the Filter icon is double-clicked to reveal currently available Filter objects (or you can click once on the file tree's "+" junction).

Tool Buttons -- Clicking on a tool button causes an action to be performed in relationship to the object or folder currently selected in the object explorer. Another way to act on a selection is to right-click on the selected icon. Actions that can be performed on a specific type of object are unique to that object. Therefore, the user will notice that the tool buttons in the toolbar will change when a different object is selected.

The Tool Buttons can be roughly divided up into two groups:

  • buttons that open and configure object Summaries

  • buttons that perform an action on the selected object

Summary of Configuration Buttons

When you click on a summary button, it opens and configures the selected object’s summary window (see below).

For example, suppose Axis 1 is selected on the Object Explorer. Clicking on the Filter Summary button will configure the Filter Summary window to display the Filter objects that are mapped to Axis 1. Clicking on the Axis Summary button will program the Axis Summary window to display Axis 1.

Summary buttons are lettered with the first letter of the object they represent. In the case of Motion Supervisor and Motor objects, the Motor is represented by an M, while the Motion Supervisor is represented with an S.

Within the View menu, summaries can also be displayed by typing their hot keys ("c" for Controller, "a" for Axis, etc.).

The Other Tool Buttons include:

- Reset the selected controller(s)

- Refresh display of the selected controller(s) and sub-objects

- Upload the firmware of the selected controller(s) to a file

- Download firmware from a file to the selected controller(s)

- Remove the selected controller(s)

- Add a controller

- Disassociate (un-map) the selected sub-object from the object containing it.

Object Explorer: Mouse Controls

Shift-click -- When holding down the Shift key and clicking on a Summary window icon, the selected object is either: 1) added to the Summary window (if it is not already there); or 2) removed from the Summary window (if it is already being displayed).

Right mouse button -- The functions performed by the toolbar buttons can also be accessed by clicking on the selected object or folder with the right mouse button. This provides a drop-down menu listing of all actions that can be applied to the selected item.

Each item on the pull-down menu corresponds to an icon on the tool bar.


Object List Configuration Dialog Boxes

.

Object List Configuration Dialog Boxes

When using Motion Console, it is sometimes necessary to define a list of objects. The Object List Configuration Dialog Box is used for this purpose. To select more than one, hold Ctrl + Left Click. Object lists are used for three different purposes:

To display all objects mapped to a list of objects

An Object Summary can be programmed to display all the objects mapped directly or indirectly to a list of objects. For this purpose, the Object List Configuration Dialog Box is opened by clicking on one of the Open and Configure Object Summary buttons on the main frame toolbar, or by selecting one of the View/Object Summary menu items.

To map sub-objects to a super-object

A super-object(Motion Supervisor 1, for example) can be mapped to a list of sub-objects (Axis 0-3, for example) . The Object Explorer can be used to map sub-objects one at a time to a super-object, but the Object List Configuration Dialog Box is used to define the entire list of sub-objects all at once. For this purpose, the Object List Configuration Dialog Box is opened by clicking on the sub-object map button on the Config tab page of the Object Summary. These buttons are listed below for each object that has sub-objects:

Motion Supervisor: Axis Map

Axis: Filter Map

Filter: Motor Map

Save objects to flash memory

A list of objects can be defined to save to flash memory. There is a Save To Flash button on the Config tab page of each Object Summary. Clicking on this button will open the Object List Configuration Dialog Box, allowing multiple objects to be selected and saved to flash memory.

The title bar of the Object List Configuration Dialog Box tells the user what function is currently being performed. It may be one of the following:

  • [Object] Summary Object List Configuration: For example: MS Summary Object List Configuration. In this case, the Object List Configuration Dialog Box is being used to configure the MS Summary to display a set of Motion Supervisors.

  • [Object] [Sub-Object] List Configuration: [Object Name]: For Example: "MS Axis List Configuration: MS 0, Controller 0". In this case, the Object List Configuration Dialog Box is being used to map a set of axes to MS 0, Controller 0.

  • Save To Flash Memory Object List Configuration: The Object List Configuration Dialog Box is being used to define a list of objects to save to flash memory.

Object List

The Object List displays the list of objects that will be the result of clicking the OK button. In most cases, the order of objects in the Object List is insignificant. The only exception to this is when configuring the Motion Supervisor Axis List. When the order of objects in the Object List is significant, then the order of the list can be modified using the Up and Down buttons, or by using the mouse to drag selected objects to a new position. (The Up and Down buttons are hidden if the order of objects in the Object List is insignificant.)

Object Pool

The Object Pool displays all objects that are valid candidates for the Object List. It consists of a set of tab pages, one for each type of object that can be in the Object List. The set of tab pages will vary, depending on the function of the object list that is being defined.

Summary Object List Configuration

For this purpose, the Object Pool will include all objects hierarchically greater than or equal to the object type that is being displayed. For example, when configuring the Motor Summary Object List, the Object Pool will contain all Motors, Filters, Axes, Motion Supervisors, and Controllers. This is because the Motor Summary window can be configured to display motor objects directly, or it can be configured to display all motors that are associated with a set of super-objects.

Sub-object List Configuration

For this purpose, the only objects displayed in the Object Pool will be those of the same type as the sub-object list that is being configured. For example, when the Axis List of a Motion Supervisor is being configured, then only axes will appear in the Object Pool.

Save to flash memory object list configuration

Every object will appear in Object Pool.

Buttons

Add -- Adds the highlighted object(s) in the Object Pool to the Object List. NOTE: You may select more than one object in the Object Pool by holding down the Ctrl button while clicking on individual objects with the mouse. To select ALL objects between two items, hold down the <Shift> button while using the mouse to click on both items. Objects can also be selected without the mouse by using the navigation keys in conjunction with <Ctrl> and <Shift>. <Ctrl><Enter> will toggle selection of the current object.

The entire list can be selected by double-clicking on any member in the list. Selected items in either list can be dragged and dropped onto the other list. NOTE: Clicking the Add button is equivalent to dragging the selection in the Object Pool and dropping it into the Object List.

Set -- Sets the Object List to those objects selected in the Object Pool. NOTE: Clicking on the Set button is equivalent to dragging the selection in the Object Pool and dropping it into the Object List while simultaneously holding town the Alt key.

Configure Sub-object Summaries Identically -- This check box is only visible when configuring an Object Summary and the object type for the Summary that is being configured has sub-objects associated with it. Checking the box will cause all the Object Summaries that display objects that are hierarchically lower than the object type of the Summary that is currently being configured, to be configured identically. For example, if the Motion Supervisor Summary is being configured to display MS 0, then the Axis, Filter, and Motor Summary windows will be configured to display all of their associated object types that are directly and indirectly mapped to MS 0. NOTE: The sub-object Summary windows must be open for them to be configured.

Up and Down -- Clicking on the Up or Down button will move objects that are selected in the Object List up or down one position. The same result can be achieved by dragging the selected objects and dropping them into the desired position. These buttons are hidden when the order of objects in the Object List is insignificant.

Remove-- Removes highlighted object(s) from the Object List. NOTE: Clicking on the Remove button is equivalent to dragging the selection in the Object List and dropping it into the Object Pool.

OK -- Closes the dialog box and retains the Object List settings.

Cancel -- Closes the dialog box without retaining the Object List settings.


Getting Started with Motion Console

.

Configuring New Systems with Motion Console

Introduction

This section describes how to configure a new motion control system using Motion Console. If you are new to Motion Console, you should read this section first, then proceed to the other sections in this manual.

Getting Started with Motion Console

Motion Console is a utility designed to assist software and hardware designers with MEI motion controllers. There are two major releases of Motion Console: one for the XMP Series motion controllers, and another, older release for DSP Series motion controllers. This section discusses only the XMP version of Motion Console; the DSP release is outlined in separate documents available from MEI.

What is Motion Console?

Briefly stated, Motion Console is a software interface linking the programmer to your MEI motion controller. It gives you the ability to perform simple motions with hardware and verify that controller-hardware wiring is working properly. Motion Console is NOT a software authoring tool. It does not compile programs or check code. However, using Motion Console alongside a line editor and compiler will allow you to quickly troubleshoot programs and determine whether problems lie in hardware or software. Motion Console also provides a quick way to demonstrate the full range of mechanical movement in your system, so that you may perfect hardware designs while software is still being developed.

What is Motion Scope?

Another MEI utility, separate from Motion Console, is Motion Scope. Motion Scope provides a virtual "oscilloscope" to plot the movements of your motion system. Using Motion Scope in conjunction with Motion Console allows you to command and plot the movement of any axis. See the Motion Scope section.

First Things First: Safety

Before configuring your system, you must consider the safety aspects of your motion control system. Such configurations as "amplifier enabling" impact every movement that your system makes, and dramatically redefine the degree of safety. Specifically, the following safety issues must be addressed when configuring new systems:

  • What hazards are posed by your motion control system to personnel and material? Has a safety zone been established to exclude personnel, their hands and fingers, etc. from dangerous spaces? Are warnings posted to alert personnel when and where hardware is in motion?

  • Are safety interlocks in place to automatically protect personnel from exposed high voltage and mechanical movements? Are emergency switches in place to perform instant, electro-mechanical shut-downs when needed?

  • How will your drive amplifiers be wired? Are they wired in a fail-safe mode which leaves your system safe when power is suddenly or unexpectedly lost? For more informtion, see the Amplifier Enabling section.

Designers of new systems are sometimes tempted to rush and ignore basic safety issues; however, safety is integral to your system's usability. If you design your system with safety in mind from the beginning, you will alleviate major hardware and software design problems later, saving valuable lives and time.


Saving Parameter Settings

.

Saving Parameter Settings

Before proceeding, you must learn to save your object settings and mappings. If you do not save your configurations, they will be lost the next time your controller is reset and/or powered down. Saving in Motion Console is NOT like saving files in other applications. (Remember, you are dealing with a lower-level hardware controller which interacts directly with hardware.) Motion Console saves parameter settings directly to its own flash memory, which ensures the same settings are reused when you repower your controller. You may also upload settings from flash memory to a firmware file, located on a hard disk or separate storage media. This permits the saving of more than one set of parameter settings, and allows multiple controllers to be loaded with the same parameter values. To ensure that your settings are protected, it is recommended that you both Save to Flash and save to an archived firmware file (Firmware Upload). Both functions are explained below.

Saving to Flash Memory
Each object has its own Save to Flash [Memory] button, which opens the Save Objects to Flash Memory dialog box. This dialog box configures a list of objects to be saved to flash memory. When the controller is powered down and restarted, the last-flashed settings are loaded automatically. For example, clicking on the Save to Flash button under Motor 2 will open the dialog box, with Motor 2 shown in the object list.

Each object has its own Save to Flash [Memory] button, which opens the Save Objects to Flash Memory dialog box. This dialog box configures a list of objects to be saved to flash memory. When the controller is powered down and restarted, the last-flashed settings are loaded automatically. For example, clicking on the Save to Flash button under Motor 2 will open the dialog box, with Motor 2 shown in the object list.

Uploading Firmware
Firmware settings which are flashed to the controller's memory can also be saved as a file on separate media using the FW [Firmware] Upload function. It is highly recommended that settings be uploaded to an archive for secure storage. This ensures protection of your settings in case the controller is damaged or lost, and allows storage of multiple configurations.

IMPORTANT! The FW Upload function saves only what is stored in flash memory, not settings on the Motion Console screen. Therefore, you must first use the Save to Flash function (see above) before using the FW Upload function.

The FW Upload function can be accessed either from the Object Explorer window, or the Controller Summary window.

Clicking on the FW Upload button displays a file manager window:

Enter the path and filename of the firmware file to be saved, then click on the Save button. The controller's firmware in flash memory will be saved to the file indicated.

Downloading Firmware
The opposite of uploading is downloading. Once a firmware file has been saved, the FW Download function copies the saved firmware file into the controller's flash memory, and volatile memory as well. To download a firmware file into the controller's flash memory, click on the FW Download function in the Object Explorer or Controller Summary windows.

Clicking on the FW Download button displays a file manager window:

Enter the path and filename of the firmware file to be loaded, then click on the Open button. The selected file will be loaded into the controller's flash memory.

Clicking the Advanced button allows the user to choose the FPGA files that will be loaded with the Firmware code. Please contact MEI for more information about using custom FPGA files. Choosing the Basic button will automatically find and download the default FPGA files.


Associating Objects with Motion Console

.

Associating Objects with Motion Console

Motion Console's Object Explorer can be used to associate objects comprising your motion control system. Objects are associated (mapped) in specific ways, for example:

  • Motors are mapped to Filters

  • Filters are mapped to Axes

  • Axes are mapped to Motion Supervisor

How Many Controllers?

In Motion Console, each "Controller" designates a physical piece of hardware: one XMP controller, with or without an expansion card. Depending upon how your XMP controller is configured, you will be able to command 8-24 axes per controller. If you require more axes, you will need to install additional XMP controllers.

Creating a New Controller

Object Before any mapping can de done, you must first add a Controller. To determine whether a Controller object already exists, look at the Object Explorer. The Object Explorer may appear as shown below if a Controller has not yet been added. (No objects will be listed below the Controllers icon in Object Explorer, or listed within the Controller Summary.)

An unconfigured Motion Console.

To add a Controller to Motion Console, click on the Add Controller icon on the Object Explorer toolbar or the main toolbar.

Clicking on the Add Controller icon displays the Add Controller dialog box. In most cases, the default settings may be left as-is. If you desire to make changes to settings, refer to the "Controller Object" section of this chapter for a description of attributes.

Click on the OK button to add a new Controller. The new Controller will be added to the object tree of the Object Explorer, which now appears as shown here:

Whenever a Controller is added to the Object Explorer, it will have a number of sub-objects. These objects are explained below.

Mapping a Motion Supervisor

The Motion Supervisor is a high-level, motion "task master," which may be configured to manage any number of axes. In the majority of cases, however, it is advantageous to assign to each Motion Supervisor one Axis. This keeps the architecture simple, and offers maximum flexibility. In limited cases (e.g., gantry cranes), it may prove helpful to map additional axes to a single Motion Supervisor.

The mapping displayed below shows one configuration. In this case, Axis 0 has been mapped to MS 0. Motion Supervisors 1-7 (not shown below) are also mapped to the same Controller object, giving a total of eight (8) Motion Supervisors.

As shown here, Motion Supervisor 0 has the following sub-objects mapped to it: Axis 0; Filter 0; and Motor 0. Other mappings and combinations are possible too, subject to the user's control.


Configuring a Motion Supervisor

.

Configuring a Motion Supervisor

Because Motion Supervisors comprise the highest level of object organization (after the controller itself), they provide a convenient starting point from which to map. Mapping will require some forethought. Some of these objects are linked tightly together (e.g., Axes, Motors and Filters); therefore, it is useful to think of them as a single unit, operating under the direction of a given Motion Supervisor. Other objects may operate independently of others.

The Object Explorer gives the best single overview of your motion control system. To look at what you have configured, open the object tree below Motion Supervisors by clicking on the file "branch" at this point. It will look something like the object tree shown here:

Mapping Axes

Classically, a single motion axis is powered by a single motor. The XMP's architecture accommodates this traditional arrangement, but also allows more than one motor to be mapped to a single axis. (Through the use of Filters, multiple motors can be configured to operate differently upon the same axis.) For now, do not worry about the type of motor(s) to be used. Think only of the axes of motion. Before further mapping, you should know the following about your motion control system:

  • How many axes of motion are required?

  • Do some axes have special requirements or limitations?

  • Will some motors always operate with other motors? How?

After these questions have been answered, you may begin mapping Axis objects to Motion Supervisors. In the examples which follow, it is assumed that objects will be mapped in numerical order (e.g., we will map Motor 1 before we map Motor 2). This is the usual order of progress, although you may do things differently if you prefer.


Mapping One Object to Another

.

Mapping One Object to Another

To map Axis 1 to MS 0, use the cursor to select the Axis 1 object, then drag it into MS 0.

A dialog box will be displayed to confirm the object mapping:

To confirm the object mapping, click on the Yes button. The Object Explorer will now show Axis 1 mapped to Motion Supervisor 0:

To map several objects to their "default" sub-object, i.e., the one with the same number, use the "Sub-Object Map" button on the Summary window. (For Motion Supervisors, this button is labeled "Axis Map.") If the entire row is selected and the button is clicked, then an Object List Configuration Dialog Box will be opened to map sub-objects to each object. If the key is held down when the button is clicked, then each object will be mapped to its default sub-object.

Mapping Filters, and Motors

Each Axis has at least one Motor and Filter object associated with it. Mapping of these objects is performed exactly as demonstrated above with Axis objects.

Before mapping these objects, it will help to answer the following questions:

  • What types of motors are required by your system? Servo or stepper? If servo-type, what phase? What are the speed and travel constraints of each axis? How does this affect the torque capabilities of your selected motors? What duty cycle is expected of your motors?

  • Is your system closed-loop or open-loop? If closed-loop, how many encoders? What levels of resolution and repeatability are required?

  • Which motion path algorithm will best answer your needs (PID, PVT, PD, etc.)? How will you tune and adjust your system?

Based upon the mechanical requirements and overall architecture of your system, you should proceed to mapping objects with the simplest configuration possible. Motor objects correlate to specific pieces of hardware having connection and power constraints. These can be determined by referring to the XMP Hardware section and the manufacturer's specifications.


Removing (Deleting) a Mapped Object

.

Removing (Deleting) a Mapped Object

Recall that in the example above, Axis 0 was mapped to Motion Supervisor 0. But what if you prefered to map Axis 1 to Motion Supervisor 0 (MS 0) instead? To do this, you must first remove Axis 0 from MS 0. Object removal is done by first selecting the object to be removed, then clicking on the Remove Axis From List icon (or use the <Delete> key).

A dialog box will be displayed to confirm the object removal:

To confirm the object removal, click on the Yes button. The Object Explorer will now appear as shown here:

Notice that Axis 0 is no longer mapped to MS 0. Moreover, all of the sub-objects associated with Axis 0 (e.g., Filter 0 and Motor 0) have also been removed from MS 0. This is because Filter 0, and Motor 0, were mapped to Axis 0. When we removed Axis 0, all its sub-objects were removed with it.

Note that Axis 0 has not been entirely removed from use. If you click on the Axes portion of the object tree, you will still find it there. But, it is no longer mapped to another object.


Safety Reminders

.

Safety Reminders

As you map out your motion control system using the Object Explorer, you must address specific safety factors. These should be addressed BEFORE you mechanically engage motors to axes, and connect motion hardware to the controller.

Establish a Safety Zone

If you have not already done so, define a safety zone around the motion system to be configured. Areas traversed by hardware should be clearly marked and/or partitioned to keep out personnel, hands, fingers, etc. Warning signs and labels should be clearly posted.

Mount an Emergency Off Switch

At least one emergency off (EMO) switch should be prominently mounted where operators and technicians can easily locate and reach it at all times. Depending upon your system, the EMO should effect a rapid and safe stop of all components, preferably wired through the power lines of the system components themselves. Consider using automatic mechanical braking where heavy and/or fast components might coast dangerously after the loss of a controller.

Wire all Drive Amplifiers for Fail Safe Operation

The wiring of your system's drive amplifiers is a critical design detail and is discussed in the XMP Hardware Installation Manual. As part of your design, you must decide whether to wire the drive's amplifier enable (Amp En) line as "active high" or "active low." Regardless of the method used, ensure that your motion system cannot run away when power to the controller is lost. Design for the worst possible power loss scenario, then ask yourself: "Is this machine safe with power to the controller turned off?" Amplifier enabling should be tested in crude hardware fashion before the system is either mechanically coupled or connected to an XMP controller. Once hardware wiring has been tested for fail-safe design, proceed to the configuration of Motor Summary / General Configuration attributes (see below).

Configure Motor Summary / General Configuration Attributes

Attributes in the Motor Summary / Config tab page configure both motors and encoders. Of particular importance to safety are the following:

  • Amp Enable
  • Type
  • Encoder Phase
  • Encoder Term
  • Encoder Type
  • Encoder Cnts/Rev.
  • Amp Disable Delay
  • Brake Mode
  • Brake Enable Delay
  • Brake Disable Delay
  • Fault Config
  • DAC Offset
  • Aux DAC Offset
  • SIM4

Each of these attributes are described in a separate section of this chapter. The Amp Enable and Polarity attributes are treated in the XMP Hardware Installation Manual. Note especially that once a motor's Amp Enable line has been wired, the Amp Enable and Polarity attributes must accord with system wiring to avoid problems.

Encoder Phase and Encoder Cnts/Rev affect the safety of your system by telling the controller which way an axis is moving, how far and how fast. If encoder attributes are set wrong, you may experience runaway problems.

Configure Motion Supervisor Summary / General Configuration Attributes

Attributes in the Motion Supervisor Summary / Config tab page include those used to configure a motion system's panic actions. These tell the controller what to do when an error or panic stop command is encountered. If they are not correctly configured, your controller may ignore an operator's command to stop! Attributes include the following:

  • Stop Time
  • E-Stop Time
  • Normal Feedrate
  • Delay
  • Panic Action

The Panic Action parameter is of particular importance. When switched to None, the controller will take no action after panic events! Please note that the <F12> panic stop key generates a panic action for all Motion Supervisors, according to how Panic Action is configured.


Controller Objects

.

Controller Objects

Within the Motion Console program, Controller objects occupy the highest level on the motion control tree. This prominent software position reflects the hardware reality: each controller represents a separate, physical piece of hardware (i.e., an XMP card) having local control. Moreover, each controller is capable of operating multiple motion supervisors, each with its own subordinate array of axes, motors, etc.

If you have not already added a Controller, please see the Add Controller section.

Controller-Client Configuration

A Controller is physically connected with a host computer via PCI bus. Hosts may be linked to clients, which allows virtually unlimited configuration combinations.

Each controller in a machine is assigned a unique device identification number by the operating system. Motion Console uses this number to communicate with the controller. When all controllers reside within a single host computer, Motion Console requires only Controller numbers (0, 1, 2, etc.) to differentiate between them. When controllers reside in separate client computers linked through a network to the Motion Console host, each controller must also be assigned a unique IP address and Port Number.

XMP Controller Placement on PCI Buses

PCI bus architecture imposes constraints which must be observed during card installation. When adding controllers to Motion Console, each XMP board is assigned a physical location on the PCI bus in the form of a Controller Number. This is a device index number beginning at "0," which indexes with each new addition of a controller board, and which ignores non-MEI devices. Motion Console uses the device index number to associate configuration/status information with a particular controller.

Adding, removing or rearranging PCI devices can cause a motion controller device number to change. For systems with only a single controller, this is not a problem. For systems with multiple controllers, Motion Console will not know whether the device index to the physical controller map has changed. This is because some data is stored in the Motion Console initialization file and is associated with the device number. The following data will be associated with the wrong controller in Motion Console if the device number changes:

  • Controller name
  • Summary object list configuration
  • Axis attributes:
    • Position 1
    • Position 2
    • Velocity
    • Acceleration
    • Deceleration
    • Jerk Percent

WARNING! When using Motion Console with multiple controller systems, make sure you know exactly which physical controller is associated with which device index. Be sure to always verify controller-to-device index relationships before commanding any motion.

The Controller Summary window lists Controller attributes in four tab pages: Actions, Config, Version, and Stats.

Configuration Attributes: "Action" Tab Page

"Action" Filter attributes include configurations for standard and custom filter features.

Reset -- Resets the controller to the power-up configuration saved in flash memory.

Refresh -- Refreshes display to reflect any external modifications.

FW Upload -- Uploads Flash memory to the firmware file. See the Uploading Firmware section earlier in this chapter for more information.

FW Download -- Downloads the firmware file to Flash memory. See the Downloading Firmware section earlier in this chapter for more information.

Save Topology -- Saves the current network topology to Flash memory.

Remove -- Removes controller from Motion Console controller list.

Controller Configuration Attributes: "Config" Tab Page

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for the Controller. For more information, see the View Sub-object section.

User Version -- User defined version. See MPIControlConfig.

Sample Rate -- Sample Rate (samples/sec). See MPIControlConfig.

MS Count -- Number of enabled Motion Supervisor objects. See MPIControlConfig.

Axis Count -- Number of enabled Axis objects. See MPIControlConfig.

Filter Count -- Number of enabled Filter objects. See MPIControlConfig.

Motor Count -- Number of enabled Motor objects. See MPIControlConfig.

ADC Count -- Number of enabled Adc objects. See MPIControlConfig.

DAC Count -- Number of enabled DAC objects. See MPIControlConfig.

Aux DAC Count -- Number of enabled Auxiliary DAC objects. See MPIControlConfig.

Record Count -- Number of enabled Record objects. See MPIControlConfig.

Sequence Count -- Number of enabled Program Sequence objects. See MPIControlConfig.

SynqNet Tx Time -- The percentage of the sample rate to devote to transmitting SynqNet telegrams. This should be set in such a way that the transmissions occur after the firmware has completed its foreground cycle. (0-100%).

Available Memory -- The amount of external memory available on the controller. The maximum value for Record Count and Axis Count is limited by the available memory.

Configuration Attributes: "Version" Tab Page

Model -- Currently only “XMP.” See MEIControlVersion.

Type -- Currently either “Device” or “Client.”

Number -- The device number of the controller on the IDE bus.

Address -- The device driver for “Device” type controllers, the IP address for “Client” type controllers.

Port -- Port for “Client” type controllers only.

Firmware Dev. ID -- Firmware Development ID.

Firmware Version -- Firmware Version. See MEIControlVersion.

Firmware Revision -- Firmware Revision.

Firmware Option -- Firmware Option. Configuration Attributes: "Stats" Tab Page

Configuration Attributes: "Stats" Tab Page

Zero Max. Times -- Zeros the maximum foreground and background timers.

Recalculate -- Triggers a recalculation of the timing statistics.

Max Fg. Time -- Maximum foreground time in microseconds. Max Bg. Time-- Maximum background time in microseconds.

Max Delta -- Maximum Delta (samples/ background cycle).

Avg. Bg. Cycle Rate -- Average interrupted background cycle rate (cycles/sec).

Avg. Bg. Cycle Time -- Average interrupted background cycle time in microseconds.

Bg. Cycle Time -- Uninterrupted background cycle time in microseconds.


Motion Supervisor Object

.

Motion Supervisor Object

Motion Supervisors can be thought of as specialized task-masters for motion control. Many system designers find it convenient to divide their system into specialized sub-tasks, each handled by a separate motion supervisor. As you organize your motion control system, the advantages of this approach will become obvious.

The Motion Supervisor summary window is divided into two configuration tab pages, plus a General Status page as shown below, and includes such attributes as Motion Type and Stop Time:

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for the Motion Supervisor. For more information, see Object Summary Windows.

Axis Map -- Displays the MS Axis List Configuration window. For more information, see the Object List Configuration Dialog Boxes section.

Motion Type -- There are ten Motion Type settings; however, only three are supported in Motion Console. All are supported by the MPI library.

  • Jog -- (Unsupported)
  • PT -- (Unsupported)
  • PVT -- (Unsupported)
  • Spline -- (Unsupported)
  • B-Spline 2-- (Unsupported)
  • Bessel-- (Unsupported)
  • B-Spline-- (Unsupported)

S-Curve -- Implements an S-curve velocity trajectory, using the Jerk Percent parameter to reach the target position.

Trapezoidal -- (Default) Implements a trapezoidal velocity trajectory to reach the target position. Does not use the Jerk Percent parameter.

Velocity -- Implements an S-curve velocity trajectory using the Jerk Percent parameter to reach the target velocity.

Attributes -- Applies special attributes to motion objects via mpiMotionModify.

Relative -- Axes are commanded to move to a point relative to their present location (i.e., without regard to their starting points).

Sync End -- Axes are commanded to end motion simultaneously at the same point.

Sync Start -- Axes are commanded to start motion simultaneously from the same point.

Stop Time --Time (in seconds) to decelerate axis to a stop.

CAUTION! Actual stopping time is limited by mass and speed! If you are moving a heavy object at high speed and command a very rapid Stop Time, your motion control or mechanical system may be unable to comply. Verify that drive and motor manufacturer's specifications meet the demands placed upon your system BEFORE assuming a stop time.

E-Stop Time -- Time to decelerate to an emergency stop. When E-Stop is activated, the State will be flagged with a Stopping Error while the axis is decellerated. An Error state is flagged when the axis comes to a complete stop. However, amp enable outputs are NOT disabled. NOTE: If the axis is close to completing a move when E-Stop is activated, the axis may halt before the E-Stop Time has expired.

Normal Feedrate -- Speed scaling factor applied to movement. 0 = stopped; 1 = normal speed (unscaled); 1.5 = 150%; 2 = 200%, -1 = reversed norma speed; etc.

Delay -- Time delay (in seconds) before execution of next move command. If operating in Repeat Mode, the delay will be applied to the beginning of each move segment.

Panic Action -- Action to execute when the panic key is activated. NOTE: Some panic action states (E-Stop and Abort) flag a fault condition. To reset the system after a fault, click on the Clear Fault button (MS Summary / Actions tab page).

None -- Motion is halted at the end of the currently commanded move. (No-fault condition.)

Stop -- Motion is halted using a Stop. (No-fault condition.)

E-Stop -- Motion is halted using an E-Stop, and a fault condition is flagged.

E-Stop, Abort -- Motion is halted using both an E-Stop and an Abort, and a fault condition is flagged. A fault condition is flagged.

Abort -- Motion is halted using an Abort.

Configuration Attributes: "Actions" Tab Page

Repeat Mode -- [Enabled; (not enabled)] Repeats programmed motion. NOTE: Each repeated motion will be delayed by the Delay amount (see description above on Delay).

Move Pos. 1 -- Command each axis associated with the Motion Supervisor to Position 1.

Move to Further -- Command each axis associated with the Motion Supervisor to either Position 1 or Position 2, whichever is further away.

Move Pos. 2 -- Command each axis associated with the Motion Supervisor to Position 2.

Stop -- Stops movement of objects under control of current Motion Supervisor within Stop time (seconds).

E-Stop -- Emergency stop. Halts movement of objects under control of current Motion Supervisor within E-Stop time (seconds) and leaves the axes in an Error state. NOTE: E-Stop does NOT disable closed-loop control and does not disable the amp enable output(s).

Abort -- Immediately stops movement of objects under control of current Motion Supervisor, disables closed-loop control, and disables the amp enable output(s), leaving the axes in an Error state.

CAUTION! Do not use Abort when testing equipment which depends upon servos or stepper motors to secure personnel or equipment (e.g., lifting cranes, elevators, etc.). The Abort command disables servos and steppers and, in some circumstances, may present a hazard to personnel or equipment due to sudden loss of power.

Zero Position -- Sets the origin of the axis to the current actual position and the command position to 0. The algorithm for setting the origin is: new origin = current origin + actual position

Clear Fault -- Clears the Motion Supervisor's error state and all sub-object statuses.

Status Attributes

Status fields are read-only:

Motion States

State -- Current motion state. (See Motion States table below.)

Motion States
State | Description
 | Idle (State parameter). Awaiting a move command.
 | In motion (State parameter). Performing a move command.
 | Stopping. (State parameter). Motion has been commanded to stop.
 | Moving when not commanded to move. NOTE: This occurs when another application commands a move.
 | Initializing.
 | Unknown state.
 | Fault or limit detected. (See Event Status Flags below.)

Error States

Event Status Flags
Error | Flag | Description
Amp[lifier] Fault |  | Amplifier fault.
Home Limit |  | Encoder home pulse exceeded or not found.
Position Error Limit |  | Error between command and actual position exceeds user-defined limit.
HW Neg. limit |  | Hardware negative limit activated.
HW Pos. limit |  | Hardware positive limit activated.
SW Neg. limit |  | Software negative limit exceeded.
SW Pos. limit |  | Software positive limit exceeded.
Encoder Fault |  | Encoder fault detected.
Motion Done |  | Move command completed.
At Velocity |  | Commanded velocity attained.
Out of Frames |  |


Axis Objects

.

Axis Objects

Axis objects are classically associated with a single vector of motion, particularly as it relates to a specific motor. In Motion Console, Axis objects bridge the control link between Filters and Motion Supervisors.

Object Explorer panel

Axis Summary Window

Configuration Attributes: "Motion" Tab Page

The following attributes appear on the Motion configuration tab page:

Position 1 -- The home position.

Position 2 -- The target position.
NOTE: Either Position 1 or 2 can be the target position at the end of the move.

Velocity -- Command velocity during move (in encoder counts / second).

Acceleration -- Command acceleration during move (in encoder counts / sec2).

Deceleration -- Command deceleration during move (in encoder counts / sec2).

Jerk Percent -- Percentage of acceleration / deceleration curve utilized for transitioning between Acceleration, Velocity, and Deceleration components. In the figure below, the effects of various Jerk Percent values are illustrated for a simple triangular profile move.

Changes in Jerk Percent parameter change the acceleration-deceleration curve characteristics. The graphs below display commanded and actual velocities.

Configuration Attributes: "Config" Tab Page

The following attributes appear on the General Config tab page:

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for Axis object. For more information, see Object Summary Windows.

Filter Map -- Displays the Axis Filter Map Configuration window. For more information, see Object List Configuration Dialog Boxes. See MPIAxisConfig.

Pos. Tol., Fine -- Fine Positional Tolerance. Maximum allowable positional deviation (error) from target position to be considered done. See MPIAxisInPosition.

Pos. Tol., Coarse -- Coarse Positional Tolerance. Arbitrarily set deviation (error) from target position. NOTE: The Pos. Tol., Coarse parameter is useful for triggering auxiliary events just prior to attaining target position. (e.g. On an automated milling machine, Pos. Tol., Coarse can be used to trigger the flow of cutting fluid when the tool is close to the object being milled.) See MPIAxisInPosition.

Velocity Tol.-- Velocity Tolerance. Maximum allowable velocity deviation (error) from target velocity to be considered "at velocity." See MPIAxisInPosition.

Settling Time -- Minimum time interval for both the Fine Pos[itional] Tol[erance] and Velocity Tol[erance] attributes to qualify as "done."
NOTE: As they approach their target positions / velocities, all axes will spend some interval of time settling. Only when an axis attains both its Fine Positional Tolerance and Velocity Tolerance within the Settling Time is that axis regarded as truly "done"; this triggers a Motion Done event (See Motion Supervisor objects). See MPIAxisInPosition.

Settle on Stop -- When checked, the settling criteria is applied to moves halted by a stop. See MPIAxisInPosition.

Settle on EStop -- When checked, the settling criteria is applied to moves halted by an E-Stop. See MPIAxisInPosition.

Settle on EStop C=A -- When checked, the settling criteria is applied to moves halted by an E-Stop. During an Estop, the command position is set equal to the actual position from the previous servo sample. This mode is not recommended. See MPIAxisInPosition.

Status Parameters

Actual Position -- Real, current position of axis. Where the axis actually is.

Command Position -- Commanded axis position. Where the axis should be.

Position Error -- Difference between Command and Actual positions.

Velocity -- Command velocity.

Acceleration -- Command acceleration.

State -- Current state of the axis.

Motion States and Descriptions
Motion State | Description
 | Moving toward target position 1.
 | Moving toward target position 2.
 | Moving when not commanded to move. NOTE: this occurs when another application commands a move while Motion Console is displaying the MS.
 | Error state
 | Idle


Filter Objects

.

Filter Objects

Filters provide linkage between motors and axes: motors are mapped to filters, and filters are mapped to axes. (It is not possible to map a motor directly to an axis without a filter.) Depending upon the algorithm employed, filters use such coefficients as gains, feed forward and torque limits.

Filter Configuration Attributes

The Filter Summary window lists Filter attributes in two tab pages: "Config" and "Coeffs."

Configuration Attributes: "Config" Tab Page

"Config" Filter attributes include configurations for standard and custom filter features.

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for Filter object. For more information, see Object Summary Windows.

Motor Map -- Displays the Filter Motor Map Configuration window. For more information, see Object List Configuration Dialog Boxes.

Algorithm -- Software filter algorithm. There are five types:

  • None -- Filter is OFF. No algorithm is applied.
  • PID -- Proportional Integral Differential algorithm.
  • PIV -- Proportional Integral Velocity.
  • PIV1 -- Proportional Integral Velocity.
  • User -- User-defined algorithm defined in firmware. (For more information, please contact MEI.)

Configuration Attributes: "Coeffs" Tab Page

The display of filter coefficients changes according to the Algorithm chosen (selectable from the Filter / General panel). The algorithm combo box on the Coeffs tab merely changes how the coefficients are displayed. It changes the row headers and displays N/A for coefficients that are not used for the selected algorithm. If the algorithm of a filter object does not match the algorithm being displayed, then N/A is displayed for all coefficients.

Each set of coefficients is described in separate tables below.

PID Coefficients

PID coefficients are defined in the table below. See MEIFilterGainPID. See the PID Tuning Parameters for Different Controller Sample Rates application note.

Filter Coefficients (PID Algorithm)
Coefficient | Description
Kp | Proportional gain
Ki | Integral gain
Kd | Derivative gain
Kpff | Position feed forward gain
Kvff | Velocity feed forward gain
Kaff | Acceleration feed forward gain
Kfff | Friction feed forward gain
ImaxMoving | Position loop integration maximum (while moving)
IMaxRest | Position loop integration maximum (while resting)
DRate | Derivative sub-sampling rate
Output Limit | Voltage command output limit
Output Limit High | Maximum command output voltage limit.
Output Limit Low | Minimum command output voltage limit.
Output Offset | Offset added to output.
Ka0 | Fast Fourier transform (FFT) testing gain (0)
Ka1 | Fast Fourier transform (FFT) testing gain (1)
Ka2 | Fast Fourier transform (FFT) testing gain (2)

PIV Coefficients

PIV coefficients are described in the table below. See MEIFilterGainPIV.

Filter Coefficients (PIV Algorithm)
Coefficient | Description
Kpp | Position loop proportional gain
Kip | Position loop integral gain
Kpv | Velocity loop proportional gain
Kvff | Velocity feed forward gain
Kaff | Acceleration feed forward gain
Kfff | Friction feed forward gain
ImaxMoving | Position loop integration maximum (while moving)
IMaxRest | Position loop integration maximum (while resting)
Kdv | Velocity estimate feedback gain
Output Limit | Voltage command output limit
Output Limit High | Upper voltage command output limit.
Output Limit Low | Lower voltage command output limit.
Output Offset | Offset added to output
Kiv | Velocity loop integral gain
VintMax | Velocity loop integration maximum
Ka0 | Fast Fourier transform (FFT) testing gain (0)
Ka1 | Fast Fourier transform (FFT) testing gain (1)


Motor Objects

.

Motor Objects

Motor objects are mapped to Filter objects. Because motor type determines many other attributes found in Motion Console, it is essential that attributes in the Motor Summary window are the first ones configured.

Motor Summary Window

The four configuration pages are:

  • Config-- General motor, stepper, and encoder configuration table.
  • Events-- Dedicated I/O and encoder event configuration table.
  • IO-- Transceiver and User I/O configuration table.
  • SinComm-- Sinusoidal Commutation configuration table.

There are also two status pages:

  • Status-- Fault and Limit event status display.
  • IO-- Dedicated I/O, Tranceiver I/O and User I/O status display.

Configuration Attributes: "Config" Tab Page

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for Motor object. For more information, see Object Summary Windows.

Amp Enable -- When checked, the amp is enabled. When unchecked, the amp is disabled.

Type -- See MPIMotorType.

  • Servo -- Configure a servo-type motor (including DC brush/brushless and linears) for ± 10V servo output.

  • Stepper -- Configure step/direction, pull up/down, or clockwise/counterclockwise type motor for stepper output. See the XCVR Configuration section to determine whether to set for step/dir or CW/CCW.

Encoder Phase -- Determines which direction of motor movement results in incrementing or decrementing encoder counts. It is very important to use the correct encoder phasing so that positive voltage will result in increasing counts and vice-versa.
NOTE: phasing can also be reversed by reconfiguring the A+/- and B+/- encoder wires, e.g., swapping the A+ and A- wires.

  • (not reversed) -- Encoder phasing is passed to the controller directly, as wired.
  • Reversed -- Inverts direction of actual position traveled for given encoder feedback.

Encoder Term -- Encoder termination.

  • Enabled -- Enables 100 O resistor between complimentary encoder signals. Use this setting for XMP controllers without SIM4 modules.
  • (not enabled) -- Disables 100 O resistor between complimentary encoder signals. Use this setting for XMP controllers with SIM4 modules, using analog interpolated feedback.

Encoder Type --

  • Incremental -- Standard incremental-type encoders. No absolute position information stored.
  • ABS 0 -- Configures encoder feedback for absolute encoders. Not all absolute encoders are supported; please contact MEI.

Encoder Cnts/Rev -- (Used with ABS 0 above.) Encoder counts per revolution. Used primarily for sinusoidal commutation. See MEIMotorEncoder.

Amp Disable Delay -- Delay (in seconds) before disabling amplifier on events that cause an Abort.

Brake Mode -- (None / Delay) None signifies the motor brake functionality is not enabled on the XMP. Delay signifies that the brake functionality is enabled on the XMP. Setting Brake Mode to delay does not require a non-zero delay. For more information, please see the Motor Brake (brake enable/disable delay) page. See MPIMotorBrakeMode.

Brake Enable Delay -- Delay (in seconds) between releasing the brake and enabling the motor. For more information, please see the Motor Brake (brake enable/disable delay) page. See MPIMotorBrake.

Brake Disable Delay -- Delay (in seconds) between enabling the brake and disabling the motor. For more information, please see the Motor Brake (brake enable/disable delay) page. See MPIMotorBrake.

Fault Config -- A mask of motor fault bits. The masked motor fault bits will be monitored by the controller's motor object. If any masked motor fault bit is active (TRUE), the motor's dedicated amp fault input (MEIMotorDedicatedInAMP_FAULT) is set active (TRUE). The support for motor fault bits is node/drive specific. During SynqNet network initialization, the SqNodeLib automatically configures the faultMask based on the node type. See the node/drive manufacturer's documentation for details. See MEIMotorFaultConfig.

User Fault Action -- The action taken in the event of a User Fault. The criteria for a User Fault can be set on the SqNode Config Summary page. For more information, see MEIMotorConfig and MEISqNodeConfigUserFault.

DAC Offset -- Adds an offset value to the Motor's DAC Output signal. Valid values are +10V through -10V.

AUX DAC Offset -- Adds an offset value to the Motor's Auxiliary DAC Output signal. Valid values are +10V through -10V.

Configuration Attributes: "Events" Tab Page

The generation of Motor events is based upon the Motor configuration attributes.

Motor events are state changes in the motor object that can be programmed to trigger a particular action. The status of motor events can be monitored in the Event Status page of the Motor Summary window. Motor events are passed up to the Motion Supervisor object (via Filter and Axis objects) and can be monitored as event status flags on the Status tab page on the Motion Supervisor Summary window. If action is taken when the event is triggered, then the event status flag is "sticky," i.e., stays on until explicitly cleared by the user. This allows the user to determine which motor(s) caused an error. Events have some or all of the below configurable attributes.

Triggers

Triggers listed on the Motor Summary / Events tab page include:

Triggers can be a state change (e.g., Amp Fault Trigger or Hardware Negative Limit Trigger) or positional information (e.g., Error Limit Trigger).

  • Inverted -- I/O polarity is inverted.
  • (not inverted) -- Condition triggers event.

Actions

Actions listed on the Motor Summary / Events tab page include:

Actions are taken when an event is triggered (see "Triggers" section above). In all cases, the following acions are available:

None -- No action taken. The event status will be flagged only while the condition of the event is met. For all other actions, the event status is "sticky."

Stop -- Stop the motor within the Stop Time defined in the Motion Supervisor / General Config tab page associated with the motion of this motor. There is no effect on the state of the axis (axes) or Motion Supervisor(s) associated with the motor. The event status is "sticky," but it will clear the next time motion is commanded.

E-Stop -- Stop the motor within the E-Stop Time defined in the Motion Supervisor / General Config tab page associated with the motion of this motor. The Axis (or Axes) and Motion Supervisor(s) associated with the motor will be left in an error state.

E-Stop, Abort -- Same as E-Stop action (above), except that the motor amplifier is disabled after the motor stops. An additional delay can be defined by setting the Amp Disable Delay attribute on the Motor Summary / General Config tab page.

Abort -- Disable the motor amplifier. A delay can be inserted before disabling the amplifier by setting the Amp Disable Delay attribute on the Motor Summary / General Config tab page.

Duration

Minimum amount of time, in seconds, that the Trigger condition must exist for the event to trigger.

Direction

The Direction attribute, when Enabled, characterizes the Hardware Negative or Positive Limit Trigger directionally.

When not enabled, the event will always be triggered, even when the motor is not in motion. When enabled, both hardware and software limit events are triggered when the motor is commanded to move only in the Direction the limit is associated with.

Configuration Attributes: "I/O" Tab Page

Tranceiver (XCVR) configurations are controlled from the Motor Summary / I/O tab page. Input-output status can be monitored by viewing the I/O status page at the bottom of the window. You can remove all references to XCVR and User I/O under this tab.

XCVR A[B, C] Config -- Configures transceiver (XCVR) for use.

  • Input -- XCVR configured to receive an input signal.
  • Output -- XCVR configured to send an output signal.
  • Step -- XCVR configured for step mode. (XCVR A and B only.)
  • Dir[ection] -- XCVR configured for direction mode. (XCVR A and B only.)
  • CW -- Clockwise. (XCVR A and B only.)
  • CCW -- Counterclockwise. (XCVR A and B only.)
  • Quad A -- Standard quadrature operation (A). (XCVR A and B only.)
  • Quad B -- Standard quadrature operation (B). (XCVR A and B only.)
  • Compare -- XCVR C only.
  • Diag -- XCVR C only.

XCVR A[B, C] Invert -- Inverts the polarity of XCVR configured for Output (incl. step, etc.) if Inverted is selected.

XCVR A[B, C] Out Level -- Active or (not active).

User Out: Invert -- Inverts the polarity of output bit (Inverted), or normal.

User I/O: Out Level -- When Active, internal logic sets bit level to high.

Configuration Attributes: "SinCom" Tab Page

Mode --

  • None -- Non-commutated.
  • Closed Loop Mode -- Commutated, closed loop.
  • Open Loop Mode -- Commutated, open loop.
  • Simulate -- Sets the motor commutation mode to MEIXmpCommModeSIMULATE.

Length -- Number of encoder counts per revolution for a rotary motor and the number of counts of one electrical cycle length for a linear motor.

Scale -- (Type float) Total number of commutation points per motor revolution, divided by the total number of encoder counts per revolution (i.e., Length).

Output Level -- Sets the DAC level during open-loop commutation. Output level is in DAC units (i.e., 32,767 = 10V).

Offset -- Expressed in units of commutation table points (i.e., 1024). 1024 table points equal 360 electrical degrees.

Phase Delta -- Usually set to 120 degrees for a three-phase, brushless motor with 120 degrees of phase separation. [120 degrees is represented by 341 commutation table points (i.e., 1024/3).] Switchable options include: 0 degrees; 90 degrees; 120 degrees.
NOTE: 90 degrees is normally reserved for a two- or four-phase motor.

  • (Normal) -- Phasing is unaltered.
  • Reversed -- Phasing is reversed 120 degrees.

Status Attributes: "Status" Tab Page

This page displays the status of motor events, as well as several general stats flags. DAC output level is also displayed. For all event status attributes, see the corresponding EventType.

Fault Bit, Amp -- Status of the Amp Motor Fault bit. See MEIMotorFaultMaskAMP.

Fault Bit, Drive -- Status of the Motor Fault bit. See MEIMotorFaultMaskDRIVE.

Fault Bit, Watchdog -- Status of the Watchdog Motor Fault bit. See MEIMotorFaultMaskWATCHDOG.

Fault Bit, Checksum -- Status of the Checksum Motor Fault bit. See MEIMotorFaultMaskCHECKSUM.

Fault Bit, Feedback -- Status of the Feedback Motor Fault bit. See MEIMotorFaultMaskFEEDBACK

Fault Bit, Amp Not Powered -- Status of the Amp Not Powered Motor Fault bit. See MEIMotorFaultBitAMP_NOT_POWERED.

Fault Bit, Drive Not Ready -- Status of the Drive Not Ready Motor Fault bit. See MEIMotorFaultBitDRIVE_NOT_READY.

Amp Fault -- Amp Fault Event status. See MPIEventTypeAMP_FAULT.

Home Limit -- Home Limit Event status. See MPIEventTypeHOME.

Position Err Limit -- Position Error Limit Event status. See MPIEventTypeLIMIT_ERROR.

HW Neg. Limit -- Hardware Negative Limit Event status. See MPIEventTypeLIMIT_HW_NEG.

HW Pos. Limit -- Hardware Positive Limit Event status. See MPIEventTypeLIMIT_HW_POS.

SW Neg. Limit -- Software Negative Limit Event status. See MPIEventTypeLIMIT_SW_NEG.

SW Pos. Limit -- Software Positive Limit Event status. See MPIEventTypeLIMIT_SW_POS.

Encoder Fault -- Encoder Fault event status. See MPIEventTypeENCODER_FAULT.

Broken Wire -- Broken wire on the primary encoder input signals. See MEIStatusMaskBROKEN_WIRE.

Illegal State -- Illegal encoder logic state on the primary encoder input signals. See MEIStatusMaskILLEGAL_STATE.

Broken Wire 2 -- Broken wire on the secondary encoder input signals. See MEIStatusMaskBROKEN_WIRE_SECONDARY.

Illegal State 2 -- Illegal encoder logic state on the secondary encoder inputs. See MEIStatusMaskILLEGAL_STATE_SECONDARY.

DAC Level -- DAC output level in volts.

Aux DAC Level -- Auxiliary DAC output level in volts.

Primary Feedback -- Feedback position of the primary encoder. See mpiMotorFeedback.

Secondary Feedback -- Feedback position of the secondary encoder. See mpiMotorFeedback.

Status Attributes: "I/O" Tab Page

This page displays Motor I/O status. For Dedicated I/O status, see also mpiMotorIoGet.

Amp Enable -- Amp Enable output status.

Amp Enable Bit -- Status of the Amp Enable dedicated motor output. See MEIMotorDedicatedOutAMP_ENABLE.

Brake Release -- Status of the Brake Release dedicated motor output. See MEIMotorDedicatedOutBRAKE_RELEASE.

Amp Fault -- Status of the Amp Fault dedicated motor input. See MEIMotorDedicatedInAMP_FAULT.

Brake Applied -- Status of the Brake Applied dedicated motor input. See MEIMotorDedicatedInBRAKE_APPLIED.

Home Sensor -- Status of the HOME dedicated motor input. See MEIMotorDedicatedInHOME.

+ HW Limit -- Status of the Positive Hardware Limit dedicated motor input. See MEIMotorDedicatedInLIMIT_HW_POS.

- HW Limit -- Status of the Negative Hardware Limit dedicated motor input. See MEIMotorDedicatedInLIMIT_HW_NEG.

Index -- Status of the Index dedicated motor input. See MEIMotorDedicatedInINDEX.

Feedback Fault -- Status of the Feedback Fault dedicated motor input. See MEIMotorDedicatedInFEEDBACK_FAULT.

Captured -- Status of the Captured dedicated motor input. See MEIMotorDedicatedInCAPTURED.

Hall A -- Status of the Hall A dedicated motor input. See MEIMotorDedicatedInHALL_A.

Hall B -- Status of the Hall B dedicated motor input. See MEIMotorDedicatedInHALL_B.

Hall C -- Status of the Hall C dedicated motor input. See MEIMotorDedicatedInHALL_C.

Amp Active -- Status of the Amp Active dedicated motor input. See MEIMotorDedicatedInAMP_ACTIVE.

Warning -- Status of the Warning dedicated motor input. See MEIMotorDedicatedInWARNING.


SynqNet Objects

.

SynqNet Objects

SynqNet objects are the SynqNet networks that are supported by a motion controller. It represents the physical network. It contains information about the network state, number of nodes, and status.

Configuration Attributes: "Config" Tab Page

All SynqNet attributes are read-only in Motion Console.

Initialize -- Press this button to bring up the SynqNet network. This will start the network initialization process. Please see the Overview of Network Initialization for details.

Shutdown -- Press this button to perform an automatic shutdown of the SynqNet network. To bring up the network again, press the Initialize button.

Save Topology -- Press this button to save the SynqNet topology information to the controller's flash memory.

Clear Topology -- Press this button to clear the saved SynqNet topology information from the controller's flash memory.

Save To Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for SynqNet object. For more information, see Object Summary Windows.

Recovery Mode -- Configures how the network is to respond to a fault condition. For more information, see MEISynqNetRecoveryMode.

Configuration Attributes: "Info" Tab Page

All Info attributes are read-only.

Network Type -- The type of network topology discovered during network initialization (String, Ring, etc.). See MEISynqNetInfo.

Node Offset -- The starting number for the first node on the SynqNet network. For example, If SynqNet 0 has three nodes (Node 0-2), then the Node Offset for SynqNet 1 will be 3 because Node 3 is the next available node. See MEISynqNetInfo.

Node Count -- Number of Nodes on the SynqNet network. See MEISynqNetInfo.

Status Attributes: "Status" Tab Page

Status attributes are read-only. More information on events can be found under MPIEventType / MEIEventType.

State -- The state of the SynqNet network. (DISCOVERY, ASYNQ, SYNQ, or SYNQ RECOVERING) See MEISynqNetState for more information.

Dead Event -- The SynqNet network was shutdown due to a communication failure.

Rx Failure Event -- Generated if the controller fails to receive packet data.

Tx Failure Event -- Generated if the controller fails to transmit packet data.

Node Failure Event -- Generated when any node's upstream or downstream packet error rate counters exceed the failure limit.

Recovery Event -- Generated when data traffic is redirected around a faulty node.

CRC Err. IN 0 -- The number of CRC errors that are received at the IN port. See CRC Error Counters for more information. See MEISynqNetStatus.

CRC Err. OUT 0 -- The number of CRC errors that are received at the OUT port. See CRC Error Counters for more information. See MEISynqNetStatus.

Failed Node Mask -- Each bit in this mask represents a failed node (0x1 = node 0, 0x2 = node 2, 0x4 = node 3, etc.). See MEISynqNetFailedNodeMask.


SqNode Objects

.

SqNode Objects

SqNode objects are the connected nodes on a SynqNet network. SynqNet supports up to 32 nodes supporting up to 32 motors on one SynqNet network.

Configuration Attributes: "Config" Tab Page

Binary Download -- Downloads a binary file to the node which allows communication for normal operation between the controller and the node. Unless the Drive vendor has already installed the .sff file at the factory, an appropriate binary file will need to be downloaded. To determine which .sff file is appropriate for your node, please refer to the Node Binary Files: Product Table. Multiple files may be downloaded to multiple nodes/drives.

Save to Flash -- Pre-selects the current settings for saving to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for this object. For more information, see Object Summary Windows.

The Alarm configuration attributes configure the trigger conditions for the Node Alarm output bit. See MEISqNodeConfigAlarm for more information.

Alarm Mask -- One bit per drive/motor. Configures the node alarm output to trigger when the Amp Fault dedicated input of the motor is TRUE. See MEISqNodeConfigAlarm.

Alarm Not Cyclic -- Specifies whether or not a node can receive an alarm when it is not in cyclic mode. When checked, a node alarm can be asserted in any mode. Otherwise, a node alarm can only be asserted in cyclic mode. See MEISqNodeConfigAlarm.

Alarm ioAbort -- Specifies the effect an IO abort will have on the node alarm output. When checked, an IO abort will trigger a node alarm. See MEISqNodeConfigAlarm.

The following attributes specify the limit conditions for SynqNet node packet rate errors. See MEISqNodeConfigPacketError for more information.

Upstream Err. Fault Limit -- Packet error rate limit on the IN port to generate a fault. See MEISqNodeConfig.

Upstream Err. Fail Limit -- Packet error rate limit on the IN port to generate a failure. See MEISqNodeConfig.

Downstream Err. Fault Limit -- Packet error rate limit on the OUT port to generate a fault. See MEISqNodeConfig.

Downstream Err. Fail Limit -- Packet error rate limit on the OUT port to generate a failure. See MEISqNodeConfig.

The User Fault configuration attributes specify the trigger conditions for a user fault. See MEISqNodeConfigUserFault for more information.

User Fault Address -- The controller address to trigger off of.

User Fault Mask -- A bit mask ANDed with the value at the controller address.

User Fault Pattern -- A bit pattern compared to the masked value at the controller address. When the masked value equals the pattern, the user trigger is TRUE.

Configuration Attributes: "IO Abort" Tab Page

SynqLost Enable -- When checked, the controller will generate an I/O Abort Action when a SynqNet node drops out of SYNQ (cyclic) mode to SYNQ_LOST mode.

SynqLost Invert -- When checked, the controller will invert the trigger polarity.

NodeDisable Enable - When checked, the controller will shutdown the node via IoAbort when the node disable is active.

NodeDisable Invert -- Inverts trigger polarity of the signal. When not checked, it will have normal polarity. If checked, it will have inverted polarity.

PowerFault Enable -- An input bit to the SynqNet node. The power fault circuit is node-specific, but is usually connected to an analog power monitor. Typically, when the DAC power or other analog component power is either too high or drops below a threshold, the power fault is triggered.

PowerFault Invert -- Inverts trigger polarity of the signal. When not checked, it will have normal polarity. If checked, it will have inverted polarity.

User Fault -- The controller will generate an I/O Abort Action when the User Fault is triggered. The conditions for generating a User Fault are configured on the Config tab page.

Configuration Attributes: "Info" Tab Page

Node Name -- A string that represents the SynqNet node type. See MEISqNodeInfoId.

Exact Match -- "Yes" when all ID components have been matched to a supported configuration. See MEISqNodeInfoId.

Unique -- The SynqNet node manufacturer determines this unique value to track a single product. See MEISqNodeInfoId.

Drive Count -- The number of drives interfaces that the SynqNet node supports.

Motor Count -- Number of motors mapped to the node.

Motor Offset -- The starting number for the first motor on the SynqNet node. Example: If Node 0 has three motors (Motor 0-2), then the Motor Offset for Node 1 will be 3 because Motor 3 is the next available motor.

Type -- This is a unique identification number that can be used to identify the type and manufacturer of the node.

Option -- The product option code within a product series.

Switch ID -- If a node/drive has an address switch on its faceplate, Switch Id will be the value to which the switch is set. If an ID switch is not supported by the node, this value will be set to -1 (0xFFFFFFFF).

FPGA Type -- There are two FPGA Types that are used, Boot and Runtime. For more information about these FPGA types, please see the Binary Images section under SynqNet Technology. See MEISqNodeFpgaType.
Boot - The FPGA that is initially used when the SynqNet network is initialized for the
first time. It enables the node to communicate with the controller. A runtime
image will need to be downloaded before any motors can move.
Runtime - The FPGA that is used for normal operation.

FPGA Vendor/Device -- The unique indentification number of the FPGA. For more information, please refer to the Node Binary Files: Product Table. See MEISqNodeInfoFpga.

FPGA Version -- The version of the FPGA. See MEISqNodeInfoFpga.

Model Number -- The model number of the node (if available). See MEISqNodeInfoId.

Serial Number -- The serial number of the node (if available). See MEISqNodeInfoId.

Status Attributes: "Status" Tab Page

SqNode status attributes display read-only data of each node. These are non-configurable.

For more information on Error Rates and Counters, see MEISqNodeStatusPacketError.

Upstream Err. Rate -- Number of upstream packet errors per cycle.

Upstream Err. Count -- Number of upstream packet errors.

Downstream Err. Rate -- Number of downstream packet errors per cycle.

Downstream Err. Count -- Number of downstream packet errors.

For more information on the CRC error counters, see the CRC Error Counters section.

CRC Err. OUT 0 -- CRC error counter for the OUT 0 port.

CRC Err. IN 0 -- CRC error counter for the IN 0 port.

For more information concerning the following events, see MPIEventType / MEIEventType.

IO Abort -- Generated when the node I/O Abort is activated. See MEIEventTypeSQNODE_IO_ABORT.

Node Disable -- Generated when the Node Disable input signal transitions from inactive to active. See MEIEventTypeSQNODE_NODE_DISABLE.

Node Alarm -- Generated when the node alarm output signal transitions from inactive to active. See MEIEventTypeSQNODE_NODE_ALARM.

Analog Power Fault -- Generated when the node's power failure input bit transitions from inactive to active. See MEIEventTypeSQNODE_ANALOG_POWER_FAULT.

User Fault -- Generated when the node's user configurable fault is triggered. See MEIEventTypeSQNODE_USER_FAULT.

Node Failure -- Generated when a node's upstream or downstream packet error rate counters exceed the failure limit. To recover from a node failure, the network must be shutdown and reinitialized. See MEIEventTypeSQNODE_NODE_FAILURE.


CAN Network Summary

.

CAN Network Summary

CAN Configuration Attributes

The CAN Network Summary window lists CAN Network attributes in two tab pages: "Config" and "Version."

Configuration Attributes: "Config" Tab Page

The Config window displays the user configurable parameters of CAN.

FW Upload -- allows the user to get a copy of the current CAN firmware.

FW Download -- allows the user to upgrade the CAN firmware.

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for CAN Network object. For more information, see Object Summary Windows.

Bit Rate -- see the Bit Rate table below. See MEICanConfig.

Cyclic Period -- the period between sending consecutive SYNC messages (milliseconds). A value of zero will disable the SYNC messages from being produced. See MEICanConfig.

Health Period -- the period (milliseconds) used for checking the health of nodes.
A value of zero will disable the health checking protocol.
For nodes that use the node guarding protocol, this is the node guarding period.
For nodes that use the heartbeating protocol, this is the heartbeat consumer time (the heartbeat producers are half this period). See MEICanConfig.

Node Number -- the node number of the XMP on the CAN network. See MEICanConfig.

Inhibit Time -- this coefficient defines the minimum time between two successive PDO messages. See MEICanConfig.

Configuration Attributes: "Version" Tab Page

The Version window is not user-configurable.

BL Version -- the version number of the CAN bootloader. See MEICanVersion.

FW Version -- the CAN firmware version number. See MEICanVersion.

FW Rev -- the CAN firmware revision number. See MEICanVersion.

FW Sub-Rev -- the CAN firmware sub-revision number. See MEICanVersion.

Status Attributes: "Status" Tab Page

Bus State -- the CAN bus will be in one of the following states: off, operational, or passive. See MEICanStatus.

Tx Error Counter -- the current value of the transmit error counter. See MEICanStatus.

Rx Error Counter -- the current value of the receive error counter. See MEICanStatus.

Message Rate -- allows the user to specify the Node Guard and Heartbeat times for the health protocols. See MEICanStatus.

Tick -- a Counter that is incremented every 1ms. See MEICanStatus.

SW Rx Overflow -- A flag indicating that the software receive buffer on the XMP has overflowed. 0 indicates that the buffer has never overflowed and 1 indicates that the buffer has overflowed. See MEICanStatus.

HW Rx Overflow -- A flag indicating that the hardware receive buffer on the XMP has overflowed. 0 indicates that the buffer has never overflowed and 1 indicates that the buffer has overflowed. See MEICanStatus.

Bit Rate

The CANOpen standard defines a set of bit rates (see table below) that can be supported. Any CANOpen node must support at least one of these bit rates. All the nodes on the CAN network must be operating at the same bit rate. Any of these standard bit rates can be used with the XMP.

Due to the electrical characteristics of a CAN network, the maximum length of a CAN network (and the corresponding drop lengths) is dependent upon the bit rate that is chosen. See MEICanBitRate. See the table below.

CANOpen Bit Rates
Bit Rate | Max Bus Length (m) | Max Drop Length (m) | Max Cumulative Drop Length (m)
1M | 25* | 2 | 10
800k | 50* | 3 | 15
500k | 100 | 6 | 30
250k | 250 | 12 | 60
125k | 500 | 24 | 120
50k | 1000 | 60 | 300
20k | 2500 | 150 | 750
10k | 5000 | 300 | 1500


CAN Node Summary

.

CAN Node Summary

CAN Node Configuration Attributes

The CAN Node Summary window lists CAN Node attributes in two tab pages: "Config" and "Info."

Configuration Attributes: "Config" Tab Page

The Config window displays the user configurable parameters of CAN.

Save to Flash -- Pre-selects the current settings and saves them to flash memory. For more information, please see the Save to Flash section.

View Sub-objects -- Shows all sub-objects for CAN Node object. For more information, see Object Summary Windows.

DO Transmission Type -- the current state of the digital output bit on the specified CAN node.

AO Transmission Type -- the current state of the analog output bit on the specified CAN node.

DI Transmission Type -- - the current state of the digital input bit on the specified CAN node.

AI Transmission Type -- the current state of the analog input bit on the specified CAN node.

Configuration Attributes: "Info" Tab Page

The Info window is not user-configurable.

DO Count -- the number of digital outputs supported on this node. The CANOpen protocol only allows the number of digital inputs and outputs to be interrogated in multiples of eight, i.e. if a node has one digital output the "digitalOutputCount" will return eight.

AO Count -- the number of analog outputs supported on this node.

DI Count -- the number of digital inputs supported on this node. The CANOpen protocol only allows the number of digital inputs and outputs to be interrogated in multiples of eight, i.e. if a node has one digital output the "digitalOutputCount" will return eight.

AI Count -- the number of analog inputs supported on this node.

Health Type -- The CANOpen protocol being used to check the health of this node. The health type is either Node Guarding or Heart Beating. See MEICanHealthType.

Status Attributes: "Status" Tab Page

Live -- the system will either be "live" or "dead."

NMT State -- CANOpen protocol Network Management state. See MEICanNMTState.


I/O CAN Summary

.

I/O Summary

The I/O Summary is different from other Summary windows in two ways. First, the type of I/O objects that can be displayed are broken out into sub-types. Each sub-type is displayed in its own tab page. For example, there are tab pages for CAN I/O and Motor I/O. Secondly, unlike other Summary windows, objects are represented as rows and attributes are represented in columns.

Configuration Attributes: "CAN I/O" Tab Page

This window displays a breakdown of the I/O for a CAN system. See MEICanDigitalIO.

Type -- The CAN I/O objects are sorted by type. Each type is color-coded. The table below describes the I/O types.

  • Digital Output (DO) -- red
  • Analog Output (AO) -- blue
  • Digital Input (DI) -- yellow
  • Analog Input (AI) -- green

Value -- The Value attribute for an Input I/O object is read-only. For Digital I/O, the value is represented as a checkbox. Checked is HIGH, unchecked is LOW. For Analog I/O, the value is a floating point number normalized to be between -1 and 1.

Configuration Attributes: "Motor I/O" Tab Page

This window displays the I/O associated with motor objects. See MPIMotorIo.

The number of I/O objects associated with a motor depends on the type of SynqNet Node that the motor is mapped to. If the motor is not mapped to a SynqNet Node, then it has no I/O. See Motor I/O for more information.

Type -- The choices for the types of I/O depend on the type of SynqNet Node that the motor is mapped to.

Out - Value to write to the bit. Checked is HIGH, unchecked is LOW.

In - Value read from the bit.

Back to Table of Contents


Introduction

.

Introduction

To fully understand Motion Console, Motion Scope and the VM3 utility, you will need to experiment with hardware. Ideally, a test stand has been obtained for this purpose so that you may experiment with the XMP to the fullest extent possible. This reduces risks to personnel and property. (If you are new to XMP, your first motion experiments should not be with a 20-ton wrecking crane!) This section will assist you in getting your hardware connected. You should then proceed to the Motion Console section to begin using your XMP motion controller.


Required Materials

.

Required Materials

  • XMP controller card(s)

  • VHDCI cable ("VHDCI" = Very High Density Connector Interface) One cable for every two motors (servo or stepper). Each controller card accepts 1-4 cables, depending upon its configuration.

  • Screw terminal connector (STC-136) for connecting one or two VHDCI cables to your motion hardware.

  • Host computer

  • Servo amplifier(s) or stepper motors

  • Hand tools (sufficient to open host computer and install controller card, secure cables, etc.)


Safety Precautions

.

Safety Precautions

Mechanical Hazards

The following mechanical precautions should always be observed, especially when operating large, powerful components:

Crush-Collision Danger to Personnel -- Even small mechanical components can exert sufficient force to crush or injure you! Before powering your motion control system, verify that personnel, including their hands, fingers and feet are clear of the safety zone. If you have not already done so, define a safety zone, then employ barriers and/or clearly marked boundary lines so that personnel are excluded from the zone. Before powering motion control components, verify that all personnel remain outside the safety zone.

Crush-Collision Hazard to Equipment -- The same precautions applied to personnel should be observed for equipment. Components can be damaged or destroyed due to collision with other components or fixed hardware.

Component Hazards -- Motion control may be applied to components which themselves present hazards. These include welders, saws, lasers, presses, cutters, etc. Be aware that the introduction of movement to a component extends the reach and range of that component's hazards. In addition, any object can be made dangerous if suddenly jarred loose or pitched due to sudden, wild movements. When testing new applications, it is recommended that you begin at very low speeds, then slowly increase to the design speed.

Electrical Hazards

Electrocution Hazard -- Some motion control systems utilize high voltages and currents which present hazards to personnel. During installation and servicing of components:

  • Power off all electrical components and accessories connected to your motion control system.

  • Unplug electrical devices from their source of power. Safe-lock all power plugs to prevent them from being plugged in during servicing.

  • Allow sufficient time for components using capacitors to discharge fully before making connections.

  • Do not repower any components until installation is complete and personnel are clear of component spaces.

ESD -- Due to the use of sensitive microelectronics, all XMP boards are subject to damage due to electrostatic discharge (ESD). When handling XMP components, users are advised to observe basic ESD precautions, including the use of grounding straps and grounding mats. Removed XMP components should always be stored in protective ESD bags and/or cases.


Hardware Requirements and Installation

.

Hardware Requirements and Installation

Hardware: Controllers

Controller hardware requirements and detailed installation instructions are detailed in the Analog-XMP Hardware section.

Hardware: SIM4 Modules

Installation instructions and hardware requirements for scale interpolation modules (or "SIM4 modules") are detailed in Application Note 206, "SIM4 Option: Installation and Calibration," available from Motion Engineering. Hardware: Sinusoidal Commutation Installation instructions and hardware requirements for utilizing sinusoidal commutation are detailed in Application Note 203, "Sinusoidal Commutation," available from Motion Engineering.

Software

Operating System -- Operates on WindowsNT 4.0, or Windows 95/98, or 2000. Detailed software installation instructions are included with the current release note of your software version.


Motion Scope Home

.

Introduction
Installing and Launching Motion Scope
User Interface
Quick-Start Guide
Toolbar Functions
 | File Menu Items
 | View Menu Items
 | Pane Menu Items
 |  | Display
 |  | Export
 |  | Import
 |  | Mode
 |  | Print
 |  | Traces
 |  | Trigger
 | Trace Menu Items
 | Window Menu Items
Other Data and Display Features
 | MaxBuffer (ms) and SampleSize (samples)
 | XRange and XOffset Fields
 | YScale and YOffset Fields
 | XRangeBar and YRangeBar
 | Zoom and Step Buttons
 | Trace and AutoScale Menu Items
Direct Cursor Measurement of Traces


Introduction

.

Introduction

Motion Scope plots and traces IO signal data from the motion controller. It is similar in its presentation to an oscilloscope, and provides a utility for checking and troubleshooting motion control systems. It is a purely "passive," read-only utility, with no ability to write data, or control motion. Combined with the Motion Console and VM3 utilities, Motion Scope serves as the system designer's eyes while working with the XMP motion control system. Motion Scope can also be used in conjunction with the designer's motion control application.

If you are a new user of Motion Scope, please see the Quick-Start Guide to Using Motion Scope.


Installing and Launching Motion Scope

.

Installing and Launching Motion Scope

Both Motion Scope and Motion Console are installed using a dedicated InstallShield software release package. To launch Motion Scope, locate and double-click its application icon.


Motion Scope User Interface

.

Motion Scope User Interface

Motion Scope is designed to function as a virtual "oscilloscope," tracing signal data and presenting it visually to the user. Signal data can be assigned separate colors (see Trace / Color section below).

In addition, Motion Scope data can be exported for use by third-party programs and spreadsheets. See the "Export" section for more information.


Motion Scope Quick-Start Guide

.

Motion Scope Quick-start Guide

This section will guide you through the most basic steps of using Motion Scope. It does not describe how to utilize advanced features, but it should prove helpful to new users. Three quick-start scenarios are presented below:

Scenario A: How to use the built-in Demo feature. No XMP controller required.
Scenario B: How to use Motion Scope motion data from XMP controller configured for stepper motors with simulated (step loopback) feedback.
Scenario C: How to use Motion Scope with Motion Console or application. Motion data from XMP controller with real motion system.

Select a scenario (e.g., "B"), then follow the steps labeled with that letter below.

1. Launch Motion Scope

Double click on the Motion Scope icon to launch the utility. A pane is displayed for XMP Controller 0:

Motion Scope start-up screen.

If you wish to close this pane, click on the Close icon [image] in the upper-right corner.

2. Open and Configure a New Pane

If a pane is not already visible, the Motion Scope screen will appear blank, as shown here:

Motion Scope start-up screen.

To open a new (or additional) pane, click on the File / New menu option. You will be presented with the Pane Mode panel:

The Pane Mode panel identifies the source of signal data to be plotted. Depending upon your scenario, use the following list as a setting guide:

Scenario A: To Quickly Demonstrate Motion Scope's Features

If you wish to quickly demonstrate Motion Scope's features without connecting to real signal data, use the built-in Demo option. You should set your Pane Mode options as follows:

Data Source | Demo
Acquire Cycle | 50 ms(default setting)
RedrawTime | 200 ms (default setting)

Scenario B: To Use Motion Scope Using Simulated Feedback Data

Motion Console can be used to generate simulated data, which is then viewed using Motion Scope. The simplest way to do this is to run Motion Console on the same platform where Motion Scope is installed. Set your Pane Mode options as follows:

Data Source | Device (MPI)
Controller Number# | 0
Acquire Cycle | 50 ms(default setting)
RedrawTime | 200 ms (default setting)

Scenario C: To View Real Signal Data with Motion Scope

If you intend to use Motion Scope to view real motion control data, set your Pane Mode options as follows:

Data Source | Device (MPI) -(if controller card resides within same platform where Motion Scope is installed)
Controller Number# | # of contoller card - (On platforms running a single control card, set this to 0; otherwise, enter the number of the active controller.)
-OR-
Data Source | Client (MPI) - (if controller card resides on a remotely networked platform, separate from where Motion Scope is installed)
Controller Number# | # of contoller card (On platform where control card resides)
Port | of platform where controller is installed
Server | IP address of platform where controller is installed
Acquire Cycle | 50 ms (default setting)
RedrawTime | 200 ms (default setting)

The Motion Console set-up for generating fake signal data is included below in Step #3.

Click the OK button to enter settings into the Pane Mode panel and close.

3. Configure Trace Settings

At this point, you have a blank pane with no traces. The next step is to tell Motion Scope which signal data to trace. This is done using the Pane / Traces menu item.

Scenario A: To Quickly Demonstrate Motion Scope's Features

If you have configured the new pane to run the built-in Demo (from Step 2-A above), you have only four sources of signal data available to you. All of them are "fake" and exist only in your computer's memory. Now, let's look at them.

Click either on the Pane / Traces menu item, or use the Traces button at the top-middle of the display pane to access the Select Traces Set panel:

In the left column of the panel are listed the four sources of signal data available to you. They consist of:

  • ActualPosition
  • ActualVelocity
  • PositionError
  • ControlOutput

Remember, the displayed signals consist of "fake," archival data for demonstration purposes only. They do not correspond to anything real on your motion controller.

To select demo data for tracing, click on the signal(s) to be plotted, then click on the Add==> button near the bottom-left corner of the panel. The selected signal(s) will be listed to the right, within the "Trace Set for Pane" window. If you make a mistake, or want to deselect a signal, highlight the signal with your mouse, then click on the Delete button on the right side of the pane.

Click the OK button to close the Select Traces Set panel.

Scenario B: To Use Motion Scope Using Simulated Feedback Data

After you have configured the new pane to view simulated data from an XMP controller (from Step #2B above), Then you need to configure the XMP controller for step controller for step motor control with sinusoidal feedback:

  • Disconnect your XMP controller from all external motion control hardware. (i.e., leave the controller in the computer, but disconnect all external cables between the card and motion equipment.) This will allow you to practice with Motion Console and Motion Scope in complete safety.

  • Launch Motion Console.

  • Use the Object Explorer to map Axis 0 to Motion Supervisor 0 (MS 0).

  • Map Motor 0 to Filter 0 and Filter 0 to Axis 0.

  • Open the Motion Supervisor Summary / General Config tab page for Controller 0.

  • Set the Motion Type field to either Trapezoidal or S-curve.

  • On the Motion Supervisor / Actions page, switch Repeat Mode to Enable.

  • Open the Motor Summary / General Config tab page.

  • Set the Type field to Stepper.

  • Switch the Step Loopback field to Enabled.

  • Open the Axis Summary / Motion tab page.

  • Set Position 1 to 0.

  • Set Position 2 to 10000.

  • Set Velocity, Acceleration and Deceleration to 100000.

Your Motion Console panels should appear similar to those shown here:

  • Set Motion Console in "motion" by clicking on the Move to Farthest Position button You should see the Command and Actual Position fields on the Axis Summary panel count back and forth between the Position 1 and 2 values (simulating a back-and-forth motion). This will continue running until you click on the MS Summary panel's Stop icon.

  • If you experience difficulty, recheck your Motion Console settings. If the system appears to be hung, click on the Stop icon on the MS Summary panel and the Clear Fault button, then retry the Move to Farthest Position button.

With the XMP controller generating the simulated data, you are now ready to use Motion Scope to view the data. Click either on the Pane / Traces menu item, or use the Traces button at the top-middle of the display pane to access the Select Traces Set panel:

In the left column of the panel are listed the signal data available to you. Remember that for this example we have configured Motion Console to utilize Axis 0; therefore only Ax 0 signals will produce interesting traces. All other non-configured signals will generate flat, "dead" traces.

To select data for tracing, click on the signal(s) to be plotted, then click on the Add==> button at the bottom of the panel. The selected signal(s) will be listed to the right, within the "Trace Set for Pane" window. If you make a mistake, or want to deselect a signal, highlight the signal with your mouse, then click on the Delete button on the right side of the pane.

For this example, click on the Ax 0 Cmd Pos and Ax 0 TC. Velocity signals.

Click the OK button to close the Select Traces Set panel.

Scenario C: To View Real Signal Data with Motion Scope

If you have configured the new pane to view real motion controller data (from Step #2C above), you may now proceed to setting your hardware into motion and using Motion Scope to view controller data. We will follow a procedure similar to Step #3B above, except that you do not need Motion Console. The intent here is to establish a simple, repeated motion with your hardware, then trigger Motion Scope at the point of interest to you.

If Using Motion Console...
If you wish to use Motion Console to command motion, configure it now to operate your hardware. Motion Console is detailed in separate chapters of this manual. Ideally, you should establish a simple, repeating motion that can be examined over and over.

If Using a Motion Control Application...
If you wish to examine motion details as hardware is commanded by a motion control application, set your application up now. Again, a simple, repeating motion is preferred.

You are now ready to use Motion Scope to view the data. Click either on the Pane / Traces menu item, or use the Traces button at the top-middle of the display pane to access the Select Traces Set panel:

In the left column of the panel are listed the signal data available to you. Any signal data can be plotted, but only active signals will produce interesting traces. All other non-configured signals will generate flat, "dead" traces.

To select data for tracing, click on the signal(s) to be plotted, then click on the Add==> button at the bottom of the panel. The selected signal(s) will be listed to the right, within the "Trace Set for Pane" window. If you make a mistake, or want to deselect a signal, highlight the signal with your mouse, then click on the Delete button on the right side of the pane.

Click the OK button to close the Select Traces Set panel.

4. Configure Trigger

The next step consists of configuring the trigger to start Motion Scope. Because Motion Scope has a limited memory buffer, it cannot acquire and display data indefinitely. You must configure it to acquire data during the time of particular interest to you.

Triggering operates the same, regardless of how you have configured your Trace panel, or whether you are working with real or fake data.

Click either on the Pane / Trigger menu item, or use the Trigger button at the top-middle of the display pane to access the Trigger Conditions panel:

For quick-start purposes, we will trigger manually. Other forms of triggering are discussed in the "Trigger" section.

  • Set "Start Condition"
  • To manually trigger Motion Scope, select the Go button menu item.
  • Set "End Condition"
  • To halt tracing manually, select the Stop button menu item.
  • Set "Trigger Detection"
  • Select the Status Data Stream menu item.
  • Click the OK button to close the Trigger Conditions panel.

5. Generate a Trace!

The final step consists of making a trace with Motion Scope. At this point, you should have followed Steps #1-4 above to configure your pane, select the traces you want, and set up manual triggering. Signal data--either real or simulated--should now be available for plotting.

To trigger a plot, click on the Go button located at the front of the display pane. You should see the data trace begin on the left side, then sweep right and continue.

Your pane may appear as shown here:

When triggering manually, Motion Scope will continue tracing data until the Stop button is clicked.

In the "Motion Scope Feature Reference" section, you may learn more about Motion Scope's features, or contact MEI for assistance.


File Menu Items

.

Motion Scope Toolbar Functions

File Menu Items

File menu items found in Motion Scope match those found in most Windows programs. They may be accessed either through the File pull-down menu, or (in the case of New, Open and Save), by clicking on icons located within the toolbar.

NOTE: Motion Scope files consist of Motion Scope settings, not traces. To save traces, use a print screen command (Print Scrn key) from within the Windows operating system to copy the screen's image to your computer clipboard. Once the screen is copied in this fashion, you may use a graphics program to edit and save the image.

New-- Opens a new Motion Scope file.

Open-- Opens the selected Motion Scope file. If the selected file includes trace data, you can then choose to import the data by checking the "Include data" checkbox at the bottom of the "Open" dialog box. You can also select the file to be opened as read-only by checking the "Read-only" checkbox. In this case, the pane associated with the file will not be "active," (i.e. data acquisition will be disabled). If the selected file does not include data, then the "Include data" and "Read-only" checkboxes are disabled. See screenshots below.

Close-- Closes the selected Motion Scope file.

Save-- Saves the selected file to a directory specified by the user.

Save As-- Assigns a new file name to the current file.

Print-- Prints the selected file as it appears on the display panel.

Print Setup-- Accesses your computer's printer setup utility.

Exit-- Quits the Motion Scope utility.


View Menu Items

.

View Menu Items

View menu items permit you to alter the layout of the Motion Scope panel by enabling/disabling various toolbars and menus. Refer to the diagram below for the location of each View menu item.

Each menu item is fully described in its own section below.

NOTE: Movable control bars-- All control bars may be moved from the display panel to your computer's desktop area by clicking and dragging with the mouse. Control bars continue to operate normally while not on the panel.


Pane Menu Items

.

Pane Menu Items

A "pane" is a viewing area within Motion Scope's main frame, and Pane menu items are at the heart of what Motion Scope does. They allow you to select which IO signal data is plotted, how plots are triggered, and how they are displayed. Motion Scope can display multiple panes simultaneously, one per controller.


Display

.

Display

The Pane Display Settings panel sets the X- and Y-axis plotting characteristics for Motion Scope. Menu Items include:

Y-axis / Connect points -- When enabled, traces are displayed with the Y-axis plotted as a continuous line between sample points. When disabled, Y-axis sample points are plotted as discrete points.

X-axis menu items:

Sample Band -- When enabled, a blue sample band is added to the bottom of the plot which indicates individual samplings. Immediately below the blue sample band, separate Gain Index and Custom Drive Mode bands are visible when zoomed-in to higher magnification using the Zoom In button (see below).

  • Gain Index (0 = red, 1 = yellow, 2 = orange, 3 = green)
  • Custom Drive Mode

Sample Numbers -- Changes the X-axis units from milliseconds (default) to sample numbers.

NOTE: Enabling this menu item will affect the Range units displayed within the Range bar near the top of the Motion Scope
panel.


Export

.

Export

The Export command allows the export of Motion Scope trace data in text (*.txt) format for third-party programs such as spreadsheets (e.g., Microsoft Excel). Exported data is tab and new line-delineated. Tabs delineate individual fields of data, new lines delineate a sample's worth of data. A segment from a typical presentation for a dual trace ("Ax 0 Cmd Pos" and "Ax 0 Act Pos") is shown below:

The leftmost column is the sample number ("Sample #"), followed by columns for "Ax 0 Cmd Pos" and "Ax 0 Act Pos," respectively.

The text file name defaults to the current Controller number. For example, in the Save As panel above, the File name field defaults to "Controller 0.txt," which reflects the currently active controller.


Import

.

Import

The Import command allows the import of Motion Scope trace data in text (*.txt) format from third-party programs such as spreadsheets (e.g., Microsoft Excel). You can only import data that is tab and new line-dilineated. See Export section for an example of a properly formatted .txt file. NOTE: In Microsoft Excel, you can save data in a spreadsheet as a *.txt file by selecting “Text (Tab delimited) (*.txt)” from the Save As Type menu options.


Mode

.

Mode

The Pane Mode panel is the first panel presented when opening a new (File / New) trace pane. Through it, the user informs the Motion Scope software which source of signal data to use, and what the data access and redraw cycles are.

Data Source -- The actual source of data to be traced. Three menu items:

Demo -- Built-in data traces for demonstration and training purposes. NOTE: This setting is not used for signal data measurements!

Device (MPI) -- Standard, default option for examining signal data from controller cards installed within the host computer running Motion Scope.

Controller # -- PCI-assigned controller card whose signal data is to be accessed.

Client (MPI) -- Option for examining signal data from a controller card installed within a remotely networked client computer.

Controller # -- PCI-assigned controller card whose signal data is to be accessed. Port-- Port number of client computer to be accessed.

Server -- IP address (XXX.XXX.XXX.XXX) of client computer to be accessed.

Acquire Cycle Time -- Time between acquisitions of view data from the controller. Data is appended to the memory buffer.

Redraw Time -- Cycle time to write (plot) signal data in memory buffer to display pane.


Print

.

Print

"Print" the contents of the active pane. The Print Setup dialog box will appear. You can also print by clicking, File > Print.


Traces

.

Traces

"Traces" refer to the actual signal data plot(s) generated on a display pane. The Traces menu item may be selected either by clicking on Pane / Traces in the pull-down menu, or by clicking on the Traces button on the main display.

The following "Select Traces Set" panel will appear:

On the left side of the panel are listed some of the possible signal data which can be traced. They are selected by clicking with the mouse, then clicking on the Add==> button below.

Click on the signal data to be traced , then on the Add==> button. The signal data will be added to the Trace Set for Pane list.

  • To select all signal data between two listings, hold down the Shift key while selecting with the mouse.
  • To select two or more signal data, hold down the Ctrl key while selecting each with the mouse.

NOTE: Motion Scope is defaulted to autoscale all of the traces selected unless otherwise specified. To turn off autoscale, go to the Manual Scaling section.

Trace Ordering -- Once a list is defined in the "Trace Set for Pane" window, you may order the arrangement by using the Trace Ordering switch. There are three menu items:

UserName -- Orders the list by user name.

MapName -- Orders the list by map name.

Address -- Orders the list by memory address (as ordered within the controller's firmware memory). TIP: click this menu item again to reverse the order.

Trace Ordering menu items arrange signal data on the Trace Set for Pane window by user name, map name, or memory address.

Modify Trace

Modify Trace menu items create, edit and close individual traces. These menu items are accessed on the right side of the Select Traces Set panel:

New and Edit-- Clicking on either the New or Edit button displays the Edit Trace Properties panel. If no trace is currently listed or selected within the "Trace Set for Pane" window, only the New button may be used.

Name-- Name assigned to the new or edited trace. Trace names can be assigned to correlate to specific axes, such as "X," "Y," etc.

Address-- Hexadecimal memory address to be assigned to the selected trace. NOTE: An Address must be specified for each Name. To determine the memory address of signal data, use the VM3 utility.

In the example below, SystemData.SampleCounter is shown on the VM3 screen with its hexadecimal address. When this address (0x00028010) is entered into the Address field of the Edit Traces Properties window, it may be plotted on the Motion Scope grid. The data's name (SystemData.SampleCounter) is manually entered into the Name field. Configure the Trigger window, then plot the data. Notice that the plot of SystemData.SampleCounter, which records time, is a constantly increasing line.

Plot of SystemData.SampleCounter data.

Bitmasking -- Allows bitmasking of current trace address. The following fields are used:

Masking Enabled -- When enabled, the data is masked. Mask-- Bit pattern to be masked (bitwise ANDed with mask).

Normalize Right-- If a Mask has zeros in its lower-order bit(s), the data value is shifted to the right. This is especially convenient for viewing binary, two-state values.

Data type-- Specifies the data type of the value stored at the Address. The following data types are selectable:

long -- Data is a long integer (32 bits).

float -- Data is a floating decimal point value (32 bits).

unsigned long -- Data is an unsigned, long integer (32 bits).

Display as hex -- When selected, data stored at the Address is displayed in hexadecimal form. If not selected, data stored at the Address is displayed in its default format.

Units -- Units applied to the vertical (Y) axis of the display pane. The following units are selectable:

Counts -- Encoder counts.

Counts/sec -- Encoder counts per second.

MilliSecs -- Milliseconds.

MilliVolts -- Millivolts.

None -- No units are applied to the vertical axis.

OK -- Enters settings and closes the Edit Trace Properties panel.

Cancel -- Closes the Edit Trace Properties panel without changing settings. Note Demo traces (available from the Pane / Mode menu item) cannot be edited.

Status Banding

The Status Banding menu item within the "Select Traces Set" panel turns on-off separate trace bands at the top of the pane for monitoring IN_COARSE and IN_FINE status on a single axis. Two color schemes are used: green = FALSE; red = TRUE.

Trace showing use of Status Banding menu items.

In above, the Status Banding menu item has been enabled for the axis indicated by the Axis field. Command velocity (trapezoidal profile) reveals motor movement. As the command position (curved profile) crosses the IN_COARSE position value at [image] , the IN_COARSE band (topmost band) changes color from green-FALSE, to red-TRUE. (Meaning, the position of the axis is now within the IN_COARSE envelope of the target position.) As the axis reaches the target position, it enters the IN_FINE envelope at [image] , and the lower (IN_FINE) status band changes color from green-FALSE, to red-TRUE.

NOTE: The IN_COARSE status band remains green-FALSE for all conditions if the servo-stepper system is not commanded (e.g., dead or disconnected). Green can be interpreted as "not in position," which usually, but not always, means "moving."

Manual Scaling

Motion Scope is defaulted to autoscale all of the traces selected unless otherwise specified. To turn off the autoscale feature, you will need to individually modify each trace you do not want Motion Scope to autoscale. Click the Traces button. In the "Select Traces Set" window. Select a trace and click the Edit button.

Make sure you clear both auto scaling check boxes.

Repeat for any traces you want to scale manually. When scaling manually, use the YScale and YOffset for adjusting scaling.


Trigger

.

Trigger

The Trigger Conditions panel may be accessed in either of two ways:

  • Click on the Pane / Trigger menu item.
  • Click on the Trigger button.

Trigger includes menu options for beginning and ending signal data acquisition, such as by manually clicking on the Go and Stop buttons, or through the use of external inputs such as motor movement.

The Trigger Conditions panel is divided into four different sections, each of which is described below, along with their respective menu items.

Start Condition

Start Condition defines the triggering event used to start signal data acquisition. This may be either user-triggered, or activated automatically using an outside condition.

Go button -- Traces are started when the Go button is clicked on the front of the display pane. Selecting this option displays two support buttons on the front of the display pane:

  • Go -- Tracing begins immediately after the Go button is clicked.
  • Stop -- Tracing is halted when the Stop button is clicked.

Motion Start -- Tracing begins when movement is detected in the Motion Supervisor chosen for tracing after the Arm button is clicked on the display pane. Selecting this option displays two support buttons on the front of the display pane:

  • Arm -- The Arm button is displayed on the display pane whenever Motion Start is selected. Tracing does not begin until the Arm button has been clicked; tracing ends according to the condition set in the "End Condition" box of the Trigger Conditions panel (see below).

  • Repeat -- The Repeat button is used to continue data acquisition beyond a single pane, after the Arm button has been clicked. The previous move data will be overwritten and the new move data will be displayed.

External Event -- (Not yet implemented.)

Pre-Trigger (ms) -- [Usable only when Motion Start enabled.] Amount of data to include with plot before triggered data.1

End Condition

The End Condition defines how tracing is to be halted.

Stop button -- Tracing ends when the Stop button is clicked on the main display panel.

Buffer Full -- Tracing ends when the data buffer has filled. NOTE: the data buffer size is set by the MaxBuffer field on the main display pane and may be as large as 50000 ms.

Motion Done -- Tracing ends when motion halts (i.e., when MotionDone condition is TRUE).

External Event -- (Not yet implemented in Version 1.19.07.)

Trigger Source

If either the Start Condition or End Condition fields are set to Motion Start or Motion End respectively, the Trigger Source field will be enabled. This field specifies which Motion Supervisor is used to trigger start and/or end of tracing.

Trigger Detection

Trigger detection may be implemented either by monitoring changes to motion status in the data stream (Status Data Stream), or by polling the controller for status (Status Poll). Note that changes to the motion status can be extremely fast, and may go undetected. Under most conditions, selection of the Status Data Stream menu item is recommended.

1. Acquisition of data is ongoing, even before the start of tracing. When a Pre-trigger time is entered, the display will include buffered data of Pre-trigger length with the triggered trace.


Trace Menu Items

.

Trace Menu Items

The Trace pull-down menu features one menu item:

  • Color -- This feature is used to custom-color individual traces to distinguish them.

  • Edit -- Open the Edit Trace Properties dialog box. This is the same dialog box that is documented in the Traces section.

To use the Color menu item, first select the trace to be colored from the pull-down Trace field in the upper-left corner of the main Motion Scope panel. Next, click on Trace / Color to access the Color panel.

Colors may be chosen directly from the pallet provided, or click on the Define Custom Colors>> button to access the custom color function. Custom colors are defined in one of two ways:

  • Move the cursor to a point of the spectrum pallet which best approximates the desired color.

  • Enter the correct values for: Hue, Saturation, Luminosity, Red, Green, and Blue to render the desired color.

To add the color to the custom color to the pallet, click on the Add to Custom Colors button.

To set the selected trace to the new color and close the Color panel, click on the OK button.


Window Menu Items

.

Window Menu Items

Window menu items control the manner in which two or more Motion Scope panels are displayed. There are two menu items:

Cascade -- Presents panels in a "cascading" format.

Tile -- Presents panels in a "tiled" format.

Note that in either format panels may be dragged and sized to suit the user. (The Windows menu items merely set up the initial presentation.) Note that the Tile format is useful for comparisons between multiple plots.


MaxBuffer (ms) and SampleSize (samples)

.

Other Data and Display Features

In addition to the data and display menu items described above, there are other basic display features built into Motion Scope. These menu items control qualities such as presentation and data buffer size.

MaxBuffer (ms) and SampleSize (samples)

The MaxBuffer and SampleSize fields occupy the same portion of the Motion Scope control panel; when one is selected, the other is deselected. Both serve the same function: setting the amount of memory to be used for recording data. Both also affect X-axis scaling of the display pane.

  • The Max Buffer field is displayed when the Display / X-Axis / Sample Numbers menu item is not selected. This value is entered in milliseconds and may be set up to 50000 ms (50 seconds).

  • The SampleSize field is displayed when the Display / X-Axis / Sample Numbers menu item is selected. This value is entered in samples and may be set up to 200000.

MaxBuffer and SampleSize set the amount of buffered memory available for tracing. As new signal data is written to the memory buffer, old signal data is permanently lost. Therefore, you should set this value to a size at least as large as the event to be traced.

Note that as the size of MaxBuffer and SampleSize increases, the width of the XOffset slider bar decreases. (See "XOffset" section below.) This is because, for larger samples, the displayed portion of the data shown in the pane represents a smaller portion of the whole.


XRange and XOffset Fields

.

XRange and XOffset Fields

The XRange value controls the scale of the X-axis. As this value is changed, plots are stretched and compressed horizontally; simultaneously, X-axis units change at the bottom of the display pane. XRange units of measurement depend upon whether MaxBuffer (units in milliseconds) or Sample Size (units in samples) is selected in the Pane / Display window. You may enter XRange values in one two ways:

  • Manual entry in the XRange field (click with cursor and enter value).
  • Use of Zoom Bar functions.

As XRange is increased-decreased, X-axis units are rescaled to fit the display pane.

The XOffset value controls which X-axis portion of the buffered data (see "MaxBuffer" section above) is displayed inside the pane. XOffset may be adjusted by moving the slider bar left-right, or by entering a value into the XOffset field manually.


YScale and YOffset Fields

.

YScale and YOffset Fields

YScale sets Y-axis scaling of data selected in the Trace field. You may enter YScale values in one of two ways:

  • Manual entry in the YScale field (click with cursor and enter value).
  • Use of YScale slider bar.

IMPORTANT! Displayed Y-axis units apply only to data selected in the Trace field! As different data is selected using the Trace pull-down menu, Y-axis values change. Verify that the correct data is selected in Trace field before reading units.

YOffset is used to offset displayed Trace plots vertically. This can be especially useful when trying to separate one data plot from another (e.g., "Ax 0 Com Pos" versus "Ax 0 Act Pos").

You may enter YOffset values in one two ways:

  • Manual entry in the YOffset field (click with cursor and enter value).
  • Use of YOffset slider bar.

To realign offset data plots, use AutoScale and (if applicable) zoom Full Out.


XRange and YRange Bar

.

XRange and YRange Bar

XRangeBar - The XRangeBar provides another way of modifying the XScale and XOffset of either the currently selected trace or all traces.

Left Click + Drag - Move selected trace.

Shift + Left Click - Same as above, but applied to all traces.

YRangeBar - The YRangeBar provides another way of modifying the YScale and YOffset of either the currently selected trace or all traces. The functionality of the YRangeBar is broken down into the following parts:

High Span --

Left Click +Drag - Nudge selected trace up. This decreases the YOffset.

Shift + Left Click - Same as above, but applied to all traces.

Ctrl + Left Click - Extend the YRangeBar up to the clicked location for the selected trace. This affects both the YOffset and the YScale.

Ctrl + Shift + Left Click - Same as above, but applied to all traces.

Low Span-- behaves as the High Span, but in the opposite direction.

Slider --

Left Click + Drag - Move selected trace. This only affects the YOffset.

Shift + Left Click + Drag - Same as above, but applied to all traces.

Ctrl + Left Click - Shorten the Slider to the clicked position for the selected trace.

Shift + Ctrl + Left Click - Same as above, but applied to all traces.

Left Double-Click - Step in for the selected trace.

Shift + Left Double-Click - Same as above, but applied to all traces.

Right Double - Click - Step out for the selected trace.

Shift + Right Double-Click - Same as above, but applied to all traces.


Zoom and Step Buttons

.

Zoom and Step Buttons

When traces are generated, the pane automatically scales the X-axis to the XRange size, and scales the Y-axis to accommodate the full vertical range of the data. Zoom and Step buttons are used to magnify portions of a pane by rescaling a selected area. Zoom buttons rescale both X- and Y-axis; the Step button rescales only the X-axis. To select an area for zooming or stepping, click and drag with the mouse to form a box cursor over the area of interest, then select one of the zoom buttons below.

Zoom In -- Magnifies area within box cursor by rescaling both X- and Y-axis.

Zoom Out -- Resizes previously zoomed-in area of pane to last used X- and Y-axis scaling.

Full Out -- Returns X- and Y-axis scaling of pane to their original (starting) values. The pane's X-axis is resized to its full XRange value.

Step In -- Magnifies area within box cursor by rescaling only the X-axis.

Step Out -- Resizes previously stepped or zoomed-in area of pane to last used X-axis scaling.


Trace and AutoScale Menu Items

.

Trace and AutoScale Menu Items

Trace -- The Trace field lists all currently plotted signal data using a pull-down menu. Y-axis scaling applies only to data currently selected from the Trace field.

NOTE: You may also select traces by clicking on them with the right mouse button. The color of the selected trace can be toggled by clicking the left and right mouse buttons anywhere within the pane.

AutoScale button -- Automatically scales the vertical, Y-axis of the display pane according to the range of data points plotted within the space afforded by the user-sized window. Selection of this menu item disables the YScale and YOffset fields (see the "YScale and YOffset Fields" section). To manually scale other traces, go to the Manual Scaling section.


Direct Cursor Measurement of Traces

.

Direct Cursor Measurement of Traces

Motion Scope permits direct measurement of selected traces to determine X- and Y-axis values. This is done by clicking and dragging with the mouse (left button) while simultaneously holding down the Ctrl key.

The X- and Y-axis values for the cursor intersection are framed by fields at the lower-right and upper-left corners, respectively.

 Back to Table of Contents


mtReset Utility

.

The mtReset Utility is used to reset the multiturn data on ABS encoders. This utility is only applicable to drives that support multiturn data.

Arguments

At the command line, type one of the following options:
ex: C:\mei\20020513\XMP\bin\WinNT>mtreset

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-motor | Motor number.

Examples

C:Mei\20020513\Xmp\Bin\WinNT>mtreset -control 1
C:Mei\20020513\Xmp\Bin\WinNT>mtreset -motor 2


Reset Utility

.

The Reset Utility resets the controller.
NOTE: No confirmation of the reset action is given.

Usage

At the command line, type "reset":
ex: C:\mei\20030325\XMP\bin\WinNT>reset

Examples

C:Mei\20030325\Xmp\Bin\WinNT>reset


Server Utility

.

The Server Utility allows MPI and MPX applications running on remote computers to control local motion controller cards by connecting via a TCP/IP connection.

Usage

At the command line, type one of the following options:
ex: C:\mei\XMP\bin\>server -control 1

server [-control #] [-listen # (3300)]

Where

-control n | Specifies that controller n in the machine is to be used. NOTE: Controller 0 is the first controller in a machine.
-listen portId | Listens for connections on TCP/IP port portId.

Examples

C:Mei\Xmp\Bin\>server
C:Mei\Xmp\Bin\>server -control 1
C:Mei\Xmp\Bin\>server -listen 3000
C:Mei\Xmp\Bin\>server -control 1 -listen 3000


sqCmd Utility

.

The synqCmd Utility sends low-level service commands to a node or drive.

Arguments

At the command line, type one of the following options:
ex: C:\mei\20020513\XMP\diag\WinNT>synqCmd -server 'gemini'

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-addr # | The service channel address that is sent down to the FPGA/drive (default = 0).
-channel # | The Service channel (default = 0) 0, 1, 2, ...map to drive processor 0, 1, 2, ... 0xFE maps to the node logic (FPGA) 0xFF is a null channel
-data # | Data that is sent down to the FPGA/drive (default = 0).
-memory # | The Memory Space. 0 - Data 1 - Program 2 - I/O 3 - Direct Command (default = 3)
-node # | Node address on the SynqNet network (default = 0).
-quiet | Stops descriptive messages from being generated.
-read # | Specifies a service channel read.
-size # | The data size. Either 8, 16, 24, or 32 bits. (default = 32)
-write # | Specifies a service channel write.

Usage

FILENAME
Service Command Read | x | x |  |  |  | x | x | x | x |
Service Command Write | x |  | x |  |  | x | x | x | x | x
General Service Command | x |  |  | x |  |  |  |  | x | x
Put SynqNet into Asynq. mode | x |  |  |  | x |  |  |  |  |

Examples

C:\mei\20020513\xmp\diag\WinNT>sqCmd -write -addr 0x1000 -data 1


sqDriveConfig Utility

.

The sqDriveConfig Utility is used to upload and download drive parameters.

Usage

At the command line, type one of the following options:
ex: C:\mei\20030513\XMP\bin\WinNT>sqdriveconfig

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-node # | SynqNet Node address.
-drive # | Drive Index relative to the node.
-motor # | Motor number associated with the drive.
-get | Copy drive parameters from drives to this file. If a filename is specified that does not exist already exist, one will be automatically created with that filename.
-set | Copy drive parameters from this file to the drives.
-overwrite | Overwrite the config file if it already exists.
-map | Name of an alternative drive map file.
-verbose | Show a verbose description of drive parameters being changed.
-warning | Only generate a warning message if a drive parameter set fails.

Examples

C:Mei\20030513\Xmp\Bin\WinNT>sqDriveConfig -get config.dc

C:Mei\20030513\Xmp\Bin\WinNT>sqDriveConfig -set config.dc -node 0

C:Mei\20030513\Xmp\Bin\WinNT>sqDriveConfig -set config.dc -node 0 -drive 1

C:Mei\20030513\Xmp\Bin\WinNT>sqDriveConfig -get config.dc -node 0 -map newDrives.dm


sqDriveMonitor Utility

.

The sqDriveMonitor Utility is used to configure the monitor data that is being sent from the drive.

Arguments

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-node # | Node address on the SynqNet network (default = 0).
-drive # | Index of the drive relative to the node (default = 0)
-motor # | The MPI motor object mapped to the drive (default = 0)
-memory # | Address of the memory location for monitoring.
-index # | Index into the monitor table for monitoring.
-monitorA | Specifies monitor A
-monitorB | Specifies monitor B
-monitorC | Specifies monitor C
-poll | Continuously poll all the drive monitors.

Usage

FILENAME
Set Monitor A | x |  |  |
Set Monitor B |  | x |  |
Set Monitor C |  |  | x |
Poll the Monitor Data |  |  |  | x
- You can use either -node and -drive, OR just -motor to specify the desired drive interface.
- Either -memory OR -index can be used.

Examples

To set drive monitor write 1 to address 0x1000 of the data memory of drive processor 0 on node 0.
       C:Mei\20020513\Xmp\Bin\WinNT>sqdrivemonitor -monitorA -index 2

To poll the drive monitors.
       C:Mei\20020513\Xmp\Bin\WinNT>sqdrivemonitor -poll
       Node 0 Drive 0
       Monitor A      (index   2)      0xFFFE
       Monitor B      (index   5)      0x0001
       Monitor C      (index  10)      0x0080
       Press Return to exit


sqDriveMsg Utility

.

The sqDriveMsg Utility displays all the faults and warnings present on the specified drive.

Arguments

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-node # | Node address on the SynqNet network (default = 0).
-drive # | Index of the drive relative to the node (default = 0)
-motor # | The MPI motor object mapped to the drive (default = 0)

Usage
FILENAME
Show all faults and warnings
- You can use either -node and -drive, OR just -motor to specify the desired drive interface.

Examples

To see the faults and warnings for drive 0 on node 1.
       C:Mei\20020513\Xmp\Bin\WinNT>sqdrivemsg -node 1
       Fault Count = 1
       Fault Read: 0x20: Invalid hall state
       Warning Count = 2
       Warning Read: 0x1: Bus Under-Voltage
       Warning Read: 0x4: Phase-Finding is required


sqDriveParam Utility

.

The sqDriveParam Utility allows control of the drive parameters on a SynqNet node. Typically, this utility is used for viewing or changing a single drive parameter.

The diagram below shows how the drive parameter actions affect the drive parameters in the drive.

Arguments

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-node # | Node address on the SynqNet network (default = 0).
-drive # | Index of the drive relative to the node (default = 0)
-motor # | The MPI motor object mapped to the drive (default = 0)
-read # | Read the specified parameter.
-write # | Write tot he specified parameter.
-action # | Perform the drive parameter action.
-data # | Data that is written to the drive parameter (default = 0)
-type # | The data type of the drive parameter: unsigned8 unsigned16 unsigned32 (default) signed8 signed16 signed32 hex enumerated mask character single string
-store | Copies the parameter table from the Drive Processor's RAM to its local non-volatile memory.
-restore | Loads the parameter table in the Drive Processor's RAM with a set of factory default parameters.
-clear | Loads the default parameter table into both the current runtime and stored parameter tables
-reload | Copies the default parameter table to the current RAM version.
-calculate | Causes the Drive Processor to re-compute the set of internal variables that are derived from the motor's parameter list that is now in RAM.

Usage

FILENAME
Read Drive Parameter | x |  |  |  |  |  |  |  | x |
Write Drive Parameter |  | x |  |  |  |  |  |  | x | x
Drive Parameter Action |  |  | x |  |  |  |  |  |  |
Clear Drive Parameters |  |  |  | x |  |  |  |  |  |
Save Drive Parameters |  |  |  |  | x |  |  |  |  |
Calculate using Parameters |  |  |  |  |  | x |  |  |  |
Restore Drive Parameters |  |  |  |  |  |  | x |  |  |
Reload Drive Parameters |  |  |  |  |  |  |  | x |  |
- You can use either -node and -drive, OR just -motor to specify the desired drive interface.

Examples

To read drive parameter 6 from node 0 (node and drive zero are assumed since zero is their default values)
C:Mei\20020513\Xmp\Bin\WinNT>sqdriveparam -read 6
    parameter 6 is 300

To write 200 to drive parameter 20h to drive 1 on node 3
C:Mei\20020513\Xmp\Bin\WinNT>sqdriveparam -write 0x20 -data 200
    -node 3 -drive 1

To write 10 to drive parameter 20h to motor 3
 C:Mei\20020513\Xmp\Bin\WinNT>sqdriveparam -write 0x20 -data 200
    -motor 3

To read drive parameter 5 from node 0
C:Mei\20020513\Xmp\Bin\WinNT>sqdriveparam -read 5 -type hex
    parameter 5 is FFE0H

Store the drive parameter on node 1
 C:Mei\20020513\Xmp\Bin\WinNT>sqdriveparam -store -node 1


sqNodeFlash Utility

.

The sqNodeFlash Utility downloads node/drive images to a SynqNet node/drive.

Usage

At the command line, type one of the following options:
ex: C:\mei\2000513\XMP\bin\WinNT>sqnodeflash

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-file | File to be downloaded.
-drive # | Index of the drive relative to the node (default = 0)
-node # | Node address on the SynqNet network (default = 0).
-erase | Erase the node FPGA.

Examples

C:Mei\2000513\Xmp\Bin\WinNT>sqnodeflash


sqNodeMemory Utility

.

The SqNodeMemory Utility can be used to read or write to a SynqNet node's memory. This utility is similar to VM3, except it is used to manually change fields for the node/drive instead of the controller. Command line arguments can be used to specify the controller number and client/server operation.

To start the sqNodeMemory Utility, type sqNodeMemory at the command prompt.
(ex: E:\mei\XMP\bin\WinNT>sqNodeMemory)

Usage

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.

Examples

C:Mei\2000513\Xmp\Bin\WinNT>sqnodememory -control 1


sqService Utility

.

The sqService Utility is mainly used as a development tool for building SynqNet nodes. It is a GUI that is used for sending single-service commands and initialization messages to a node at startup.

WARNING!
sqService is a low level tool that is designed to be used by MEI engineers and SynqNet Drive Partners. Under normal conditions, a customer should NOT use this utility unless otherwise specified by an MEI applications engineer.


sqTopologySave

.

The sqTopologySave Utility rediscovers the current network topology, saves the topology to XMP flash memory, and then resets the network.

WARNING!
For safety reasons, saving topogy to flash will clear out some XMP object configurations (including Block, Motor, and Capture objects).

Usage

At the command line, type one of the following options:
ex: C:\mei\20030513\XMP\bin\WinNT>sqTopologySave -control 2

-? | Help
-control # | Controller number (default = 0)
-server # | Name or IP address of the host running server.exe
-port # | TCP/IP port on the host computer (default = 3300)
-trace # | Bit mask to specify trace information outputs.
-clear | Clear the network topology information from flash memory.

Examples

C:\Mei\20030513\xmp\bin\WinNT>sqTopologySave -control 2


Trace Utility

.

The Trace Utility displays all valid MPI trace bit masks which can be used as a command line argument (-trace bitMask) to utility programs that support tracing. The trace utility will take a trace bitMask (hex) as a command-line argument and display the corresponding trace definitions.

How to Use the Trace Utility


Version Utility

.

The Version Utility displays version information about the motion controller card, as well as the current version of the installed MPI DLL file.

Usage

for Windows:

At the command line, type one of the following options:
ex: C:\mei\XMP\bin\>version -control 1

version [-control n] [-server host [-port portId]]

for VxWorks:

At the command line, type one of the following options:
ex: C:\mei\XMP\bin\>ver -control 1

ver [-control n] [-server host [-port portId]]

Where

-control n | Specifies that controller n in the machine is to be used. NOTE: Controller 0 is the first controller in a machine.
-server host | Connects to a remoted machine whose name or IP address is host. NOTE: The host must be running the server utility.
-port portId | Specifies that TCP/IP port portId is to be used for the server connection.

Examples

C:Mei\Xmp\Bin\>version
C:Mei\Xmp\Bin\>version -control 1
C:Mei\Xmp\Bin\>version -server Jupiter


VM3 Home

.

Introduction
Installing and Running VM3
VM3 Layout and Hot Keys
Board Data Panel (F1)
VM3 Data Panels and Header Files
Commands Panel (F2)
Auto Panel (F3)
Hex Panel (F4)
Decimal Panel (F5)
Float Panel (F6)
Dump/Save Panel (F8)
Reset Panel (F9)
Toggle Panel (F10)
Command Line Options


Introduction

.

Introduction

VM3 is the third version of the "View Memory" utility written for MEI motion controllers; earlier versions (VM and VM2) worked with DSP-series controllers. The VM3 utility allows you to view and alter data stored in memory on the XMP-series controller card. This includes data inside and outside the SHARC DSP processor. When using VM3 to alter data on motion controllers, exercise extreme caution at all times:

DANGER! Changes made to memory take effect immediately, including data designed for motion components such as motors and encoders. Verify that personnel are clear of the movement zone and equipment is safeguarded BEFORE making any changes to memory data. Always operate equipment with an emergency off switch (EMO) at the ready, especially when writing and testing new software configurations.


Installing and Running VM3

.

Installing and Running VM3

VM3 is installed with each full XMP software installation, along with Motion Console, Motion Scope and various system files. The VM3 executable (vm3.exe) is normally located within the XMP/bin/Win95 and WinNT paths. The utility is launched from the DOS command prompt by entering vm3.

When booting, VM3 first examines data in the xmpNNLN.xmp file to map memory, where NNN is the firmware version number. It is necessary that the version of VM3 you are running matches the firmware version of the xmpNNN.map file; otherwise, the system will fault or request an update.


VM3 Layout and Hot Keys

.

VM3 Layout and Hot Keys

VM3 is organized into panels and functions, each of which is assigned a function key. The "Board Data" panel is accessed by pressing the F1 key, the "Commands" panel is accessed with the F2 key, and so on.

Function Key Assignments, VM3
Function Key | Description
Esc | Exits VM3
F1 | Board Data panel. XMP board configuration.
F2 | Commands panel. Data organized by command number.
F3 | Auto panel. Memory organized by object. Data is automatically displayed in most commonly used form, either hexadecimal or decimal.
F4 | Hex panel. Memory organized by object. All data is displayed in hexadecimal form.
F5 | Decimal panel. Memory organized by object. All data is displayed in decimal form.
F6 | Float panel. Memory organized by object. All data is displayed in floating decimal point form.
F7 | Recorder panel. (Not implemented in this version.)
F8 | Dump/Save panel. Dumps xmp memory to xmpdump.bin.
F9 | Reset. Resets motion controller (reloads from flash).
F10 | Toggle. Toggles the screen between a 32-bit format and a 16-bit format.

Within panels, various control keys permit you to move the cursor between lines of data, and between objects:

Command Keys
Command Key | Description
PgUp/PgDn | Moves forward-backward through data.
Ctrl + PgUp / PgDn | Moves to next class of object.
Ctrl- | Moves to next instance within the object class.
Ctrl-Home | Jumps to first memory address.
Ctrl-End | Jumps to last memory address.
R | Moves to beginning of RipTide Data.
> | Follows data pointer, pushing current location onto address stack.
< | Pops pointer from address stack, making it the current location.


Board Data Panel (F1)

.

Board Data Panel (F1)

The start-up panel contains data about the controller board, including software and hardware configuration.

Board Data VM3 Panel

Board Type -- XMP controller board installed. Two settings:

01 | Hammerhead 1
02 | XMP standard (includes both PCI and CPCI).

FPGA Prom Version -- FGPA (Field Programmable Gate Array) Version type on controller board.

XXX --

Undetermined -- VM3 cannot determine version of FPGA PROM

Board Revision -- Revision designator for XMP board. Two options: 01-- Old version. 02-- New version.

01 | Old version
02 | New version

Signature -- Only one signature is used: C0FFEE. This confirms that firmware has been successfully loaded onto the board. Any other signature--or a missing signature--indicates that the board lacks firmware and/or is malfunctioning.

Maximum Axes -- Maximum number of axes configurable on the XMP controller. This is hardware-dependent, and ranges between 1 and 24 axes. Standard XMP boards can accommodate up to 8 axes; additional axes may be added via an expansion board.

Enabled Motors -- Number of Motors currently configured for the XMP controller.

Enabled Filters -- Number of Filters currently configured for the XMP controller.

Enabled Axes -- Number of Axes currently configured for the XMP controller card. This number cannot exceed the Maximum Axes value.

Enabled Motion Supervisors -- Number of Motion Supervisors currently configured for the XMP controller.

Enabled Program Sequencers -- Number of Program Sequencers currently configured for the XMP controller.

Software ID -- Firmware number. This is usually a three-digit number (e.g., 266, etc.).

Revision -- Firmware revision number.

Sub-Revision -- Firmware minor revision number.

Developmental -- N/A.

Option -- Optional number for custom firmware identifier.

Timer -- Cumulative timer counts. To reset the motion controller and zero the timer, use the F9 key.

Sample Period -- Samples per second. Default is 20 kHz (19999). Each tick is 50 nanoseconds.

Command Buffer Address -- Location of command buffer.

Map File -- Map file utilized in current configuration (e.g., xmpNNN.map, where NNN is the firmware version number). NOTE: NNN must be the same as the firmware number.

1. The "Hammerhead" board (FPGA Prom Version 01) is a prototype controller card which preceded the standard XMP-series controller.


VM3 Data Panels and Header Files

.

VM3 Data Panels and Header Files

XMP data structures displayed on VM3 panels correspond to data structures in the xmp.h header file. Consider the following example:

In this example, data structures MEIXmpSystemData and MEIXmpData (bottom), located in the header file xmp.h, are represented in VM3 as shown (top).


Commands Panel (F2)

.

Commands Panel (F2)

Pressing the F2 key displays external memory (i.e. memory located on XMP board componenets other than the SHARC DSP processor), organized by command number. The first address in this memory block is 0x00400000.

Commands VM3 Panel


Auto Panel (F3)

.

Auto Panel (F3)

Pressing F3 displays memory data, arranged by object, with data values displayed in either hexadecimal, decimal, or float format. Objects with pointers have their data preceded by an asterisk (e.g., *0x0028026 on the sixth memory data line below). The choice of which data format to use is determined automatically, with data generally displayed in its most commonly used format.

Auto VM3 Panel


Hex Panel (F4)

.

Hex Panel (F4)

Pressing F4 displays memory data, arranged by object, with data values displayed in hexadecimal format only.

Hex VM3 Panel


Decimal Panel (F5)

.

Decimal Panel (F5)

Pressing F5 displays memory data, arranged by object, with data values displayed in decimal format only.

Decimal VM3 Panel


Float Panel (F6)

.

Float Panel (F6)

Pressing F6 displays memory data, arranged by object, with data values displayed in floating decimal format.

Float VM3 Panel


Dump/Save Panel (F8)

.

Dump/Save Panel (F8)

Pressing F8 dumps memory data to the file, "Xmpdump.bin" in the local directory. This file can be loaded later into VM3 for further inspection.

Dump VM3 Panel


Reset Panel (F9)

.

Reset Panel (F9)

Pressing F8 resets the motion controller (reloads from flash).


Toggle Panel (F10)

.

Toggle Panel (F10)

Pressing F10 toggles the display of the screen between a 32-bit format and a 16-bit format. In VM3, since most of the XMP data is 32-bit, the default setting shows all of the data in a 32-bit format (long, hex, or float). However, for viewing 16-bit data like the Riptide, DAC, and Dedicated Input/Output, it is easier to understand the data when viewing the data in a 16-bit format. Pressing F10 allows the viewing mode to switch between a 32-bit and 16-bit format.

Toggle VM3 Panel


Command Line Options

.

Command Line Options

VM3 supports eight command line options: -control #, -delay, -map, -load, -save.

-control, -server, -port
These options allow the control of various controllers on different servers, ports and/or traces.

The -control option allows the usage of any controller that is properly mapped. The default control number is zero.

The -server option allows the usage of controllers located on different host and remote servers.

The -port option allows the usage of controllers using different port settings. For instance:

  • To use VM3 with controller 1 on the host machine, type: vm3 -control 1

  • To use VM3 with controller 2 on a remote host named "Orion" using TCP/IP port number 5000, type: vm3 -control 2 -server Orion -port 5000

-delay
The -delay option determines how often the VM3 screen is refreshed. The default value is 10 milliseconds. Setting the delay to a smaller value will cause the screen to be updated more frequently. Setting the delay to 0 will update the screen as fast as possible, but will cause noticeable delay in other applications. Since most video monitors do not refresh more often than every 10 milliseconds, there is usually no advantage gained by lowering the delay.

For example, the command: vm3 -delay msec (8) will cause the screen to refresh every 8 milliseconds.

-map
The -map option allows the loading of an alternative map file.

For example, the command: vm3 -map myfile.map will cause VM3 to use the file "myfile.map" instead of using the default map file. The default map file is XmpNNN.map where NNN is the firmware version number.

-load
The -load option causes VM3 to browse the firmware memory images from a file. Only the MEIXmpData{} and MEIXmpBufferData{} structures are loaded. This feature works in conjunction with the -save option.

For example, the command: vm3 -load Xmpdump.bin will load the previously saved “Xmpdump.bin” file for viewing.

-save
The -save option specifies the name to be used for saving memory images when F8 is pressed. The -save option does not need to be specified to save memory images when F8 is pressed. The default is “Xmpdump.bin.”

For example, the command: vm3 -save dump1.bin will save the memory images to the “dump1.bin” file. Memory images will continue to be saved to this file when F8 is pressed for the remainder of the session.

Back to Table of Contents


PDF / Notes

.

Select a section below.


HTML Help Home

.

HTML Help

An HTML Help version of MEI's Technical Support website is also available. Some of its key features include:

  • global searches with keywords highlighted in the html pages

  • global index

  • a user-friendly, expandable table of contents

  • ability to access MEI's documentation when no Internet connection
    is available.

  • abillity to access the documentation that matches a particular release.

If you just wish to use the HTML Help version as a standalone utility, you only need to download the *.chm file to your hard drive. To open MEI's HTML Help, simply double-click the *.chm file.

If you wish to integrate the HTML Help version with MSDN, you will need both the *.chi and *.chm files. For more information about integrating with MSDN, go to the Integration with MSDN page.

The following versions of HTML Help are available for the following software releases. To review changes that have been made to the MPI/MEI software libraries since that release, please refer to the General Release Note.

20030605 (synqnet phase II)

Help File | Filename | Last Revised
 | coming soon! | 11Jun2003
 | coming soon! | 11Jun2003

20021212 (synqnet phase II)

Help File | Filename | Last Revised
 | mei20021212.chm | 13Feb2003
 | mei20021212.chi | 13Feb2003

20020117.1.3 (analog)

Help File | Filename | Last Revised
 | mei20020117_1_3.chm | 01Apr2002
 | mei20020117_1_3.chi | 01Apr2002


Integration with MSDN

.

Integrate MEI's
HTML Help file with the MSDN library!

Why should I integrate with MSDN?

Many software programmers who author code using MS Visual Studio are accustomed to using the MSDN library as one of their main resource tools. By integrating MEI's HTML Help with MSDN, you will be able to perform global searches and use the F1 button within MS Visual Studio for MEI-specific terms. For example, you can select MPIControlConfig within MS Visual Studio, press F1, and MEI's documentation page for MPIControlConfig will appear.

How do I integrate with MSDN?

Step 1
Download a freeware program from the web called MSDN Integration Utility by Codejock Software. Go to http://www.codeproject.com/winhelp/msdnintegrator.asp and click on the MSDN Integration Utility link. In order to integreate MEI's HTML Help version to MSDN, you will need to download two files to your hard drive:(support_motioneng.chi and support_motioneng.chm. You can find these files at http://support.motioneng.com/pdf_notes/htmlhelp/home.htm.

Step 2
Click on the MSDNIntegrator.exe file. The following window should appear.

Step 3
Locate the support_motioneng.chi and support_motioneng.chm files. Insert a Title for the new library that you're adding to MSDN, and insert a Unique Identifier for the library.

Step 4
Click the Integrate with MSDN button.

Step 5
Open the MSDN Library. You should now see MEI's On-line Documentation library as an option. CONGRATULATIONS! You have successfully integrated MEI's On-line Documentation into MSDN!


PDF Documents Home

.

This section provides a list of the print-friendly PDFs of MEI's documentation, as well as a few helpful PowerPoint presentations.

Unless you are printing out only a few selected pages, it is recommended that you use the pdf versions for larger print jobs. Although the html versions are printable from your browser, the pdf versions will produce the most consistent and reliable results.

Any of the files listed below can be saved to your computer for future viewing. Simply rt-click on the link and Save Target As / Save Link As.

To Download Adobe Acrobat Reader 5, click the button to the left.

Application Notes | Release Notes | Manuals and Guides | MPI Software

Application Notes

An Application Note provides a more in-depth explanation on a particular topic, product, or feature.

Doc # | Title | Revision | Last Revised
203 | Sinusoidal Commutation | B | 05Apr2000
206 | SIM4 Option: Installation and Calibration | D | 04Jan2001
207 | XMP Gantry Configurations | 2 | 18Jun2001
208 | PT and PVT Path Motion for the XMP | A | 20Jan2000
215 | User Limits | C | 22Apr2002
218 | XMP-Pulse-PCI Installation Instructions | A | 25Jun2001
218 | Errata to XMP-Pulse-PCI Installation Instructions | A | 13Jun2001
9D00-0130 | MPI/XMP Data Tracing | A | 15Mar2001
9D00-0162 | The XMP CANOpen Interface | D | 23Jan2003
9D00-0184 | Scaling PID Tuning Parameters for Different Controller Sample Rates | A | 25Oct2001

Release Notes

A Release Note provides a brief explanation of the latest changes to a particular version of the MPI Library and its Firmware. It includes documentation on the following sections: General Changes, Incremental Changes, Bug Fixes, Outstanding Bugs, and Updates of Motion Console and Motion Scope.

PDF | Title | Firmware Version | Library Version | Last Revised | Doc #
 | MPI/XMP Firmware and Library | 459B1 | 20030620.1.1 | 26Jun2003 | DCR 706

Manuals and Guides

PDF | Title | Last Revised | Doc #
 | SynqNet-XMP Quick Start Guide | 21Oct2002 | DCR 643
 | Analog-XMP Quick Start Guide | 12Mar2002 | DCR 642
 | MPX Quick Start Guide for Visual Basic | 23Sept2002 | 9D00-0232
 | MPX Quick Start Guide for LabVIEW | 23Sept2002 | 9D00-0233
 | XMP Motion Controller Hardware Installation (Analog) | Mar2002 | M001-0066
 | DSP Series Motion Controller Installation | Mar2002 | M001-0001
 | DSPpro Series Motion Developer's User Manual | Mar2002 | M001-0024
 | DSP & DSPpro Series C Programming Reference | Mar2002 | M001-0002
 | DSP & DSPpro Series Sample Applications Reference | Mar2002 | M001-0003

MPI Software

For users who prefer to view the software documentation using Acrobat Reader or wish to print out large portions of the documentation, the MPI Software documentation is now available in pdf format. The MPI/MEI library has been organized by objects. Click on any of the objects below to download a pdf version of that object's documentation. A composite pdf of all the objects is also available below.

MPI Library: 20030620.1.1
Last Modified: June 25, 2003

For a pdf that includes all of the MPI objects, click here (3.7MB).

Axis | EventMgr | Path
CAN | Filter | Platform
Capture | Flash | Recorder
Command | Global* | Sequence
Compare | Message* | Service
Control | Motion | SqNode
DriveMap | Motor | SynqNet
Event | Notify | Trace*
EventMask | Object* |


Table of Contents

Select an MPI/MEI Object

MPI Library: 20030620.1.1

Axis | EventMgr | Path
CAN | Filter | Platform
Capture | Flash | Recorder
Command | Global* | Sequence
Compare | Message* | Service
Control | Motion | SqNode
DriveMap | Motor | SynqNet
Event | Notify | Trace*
EventMask | Object* |


PowerPoint Presentations Home

.

PowerPoint | Title | Last Revised
 | Introduction to Servo Control & PID Tuning | Aug 01
 | XMP Single Axis Tuning: PIV | Sept 01

NOTE: If you have trouble viewing the file in your browser, save the file to your Desktop and open it in MS PowerPoint. To save, rt-click on the link and "Save Target As."


Motion Engineering

This page uses frames, but your browser doesn't support them.


Motion Engineering, Inc.

This page uses frames, but your browser doesn't support them.


This presentation contains content that your browser may not be able to show properly. This presentation was optimized for more recent versions of Microsoft Internet Explorer.

If you would like to proceed anyway, click here.


‹header›
‹date/time›
‹footer›
‹#›


Click to edit Master title
Click to edit Master text styles
Second level
Third level
Copyright 2001, Motion Engineering, Inc.


Notes
Outline
Introduction to Servo Control & PID Tuning
Presented to:
Agenda
Introduction to Servo Control Theory
PID Algorithm Overview
Tuning & General System Characterization
Oscillation Characterization
Feed-forward Terms
Dual-loop Control
Introduction to
Servo Control Theory
Positioning a Load
Servo positioning systems are designed to precisely move a load along an axis of a coordinate system.
Positioning with Servo Motors
A servo motor can be used to move a load in conjunction with a lead screw.
Position Feedback
It is theoretically possible, but not practical, to calculate the required motor current
Exact physical properties of system components must be identified and must not change
Position feedback is used to provide the control system with motor shaft position
Enables the control system to ensure that the load gets to the commanded position
Servo Positioning with Feedback
An optical encoder is used to provide the control system with position feedback
PID Algorithm Overview
Servo Control with PID
PID is the most commonly used servo control algorithm
Proportional
Integral
Derivative
PID systems can be understood by way of analogous physical models
Understanding the Proportional Term
Proportional term is analogous to the spring constant in a damped harmonic oscillator system
Error = Desired position - Actual position
Understanding the Derivative Term
Derivative term is analogous to a “pot of honey” in a damped harmonic oscillator system
Limitations of “PD” Control
“PD” systems are very effective for servo control, but they break down when friction in the system is high
Understanding the Integral Term
Integral term contributes to the output in proportion to the sum of the error over time
Tuning & General
System Characterization
What is Tuning?
Tuning \ tün·ing verb : The art of adjusting PID gains to optimize the motion of your system.
Tuning – First Step is Safety
Before doing anything related to tuning your servo motors, you must be sure your system is in a safe configuration
Refer to Introduction to Servo Tuning handout
Be sure to check wiring and set software limits to appropriate values
Tuning – Getting Started
Initial tuning will concentrate on P & D gains
Reminder: P » spring constant
D » damping factor
General guidelines
P is usually a small (0 – 10) positive integer
D is usually = 10 * P
Tuning – Setting Initial P & D Gains
Set initial values for P & D
Command a motion and use Motion Console to graph Actual Position versus Time
If the motor doesn’t move at all, or doesn’t closely reach the target position, try doubling the P gain
Analyze graphs if motor is underdamped, overdamped, or critically damped.
An ideally tuned system is just under critically damped (underdamped).
Tuning – Underdamped Motor
If your system is underdamped, you will notice a large oscillation at the end of the move
Try increasing D gain
You can also decrease P gain, but increasing gains are recommended at this stage
Tuning – Overdamped Motor
If your system is overdamped, the motor will either take very long to complete the move or not get to the target position at all
Try increasing P gain
You can also decrease D gain, but increasing gains are recommended at this stage
Tuning – Critically Damped Motor
If your system is critically damped, you should not see much oscillation at the end of the move, and the motor should get to the target position fairly quickly.
Tuning – Determining “In Position”
If your final positioning accuracy can vary by several counts, a slightly underdamped system can get to the target position faster.
Tuning – General Guidelines
When tuning, use moves that are similar to the moves that you will use in your application
Using the most aggressive moves (highest acceleration and/or longest time) will result in best results.
When increasing K & D, use these guidelines:
Dnew = Dold * (multiple)
Pnew = Pold * (multiple)2
Tuning – Using the Integral Term
Integral term can be used in two modes:
Standing only (recommended)
Always
When used in standing only, the Integral term only contributes to the servo command when the command position has stopped changing
Tuning – Initial Guidelines for I Term
Start with I = 1
I values are generally very small positive integers
Command a move, and graph error versus time
At the end of the move, the I term should pull the error down to zero
Keep increasing the I gain until the error begins to oscillate, then revert to previous value.
After tuning for the I gain, go back and double-check values for P & D gains.
Generally after tuning for the I gain, you will need to either reduce P gain or increase D gain by 1-10%.
Oscillation Characterization
Three General Types of Oscillation
High-frequency oscillation
Frequency of ½ or less of the sample rate
Sometimes results in an audible high-frequency hum
Oscillation is generally imperceptible to the human eye
Generally indicates a D gain that is too large
“Middle” frequency oscillations
Period in between high- and low-frequency oscillations
Generally indicates a P gain that is too large
Approximately 1/10 of high-frequency
Three General Types of Oscillation
Low-frequency oscillation
Period greater than several samples
Sometimes results in an audible low-frequency hum or rattle
Oscillation is sometimes perceptible to the human eye
Generally indicates an I gain that is too large
Approximately 1/10 of middle-frequency
Identifying High-Frequency Oscillations
This graph indicates a motor tuned with a D gain that is too large
Identifying Low-Frequency Oscillations
This graph indicates a motor tuned with an I gain that is too large
Identifying Middle-Frequency Oscillations
This graph indicates a motor tuned with an P gain that is too large
Oscillations due to Mechanical Issues
Some kinds of oscillations can be caused by problems with the mechanical system
Can be identified when changing PID gains doesn’t affect the period of the oscillations
If period of oscillation is proportional to the velocity of the move, a mechanical problem is usually the cause
Only solution is to fix the mechanical problem.
Feed-forward Terms
Introduction to Feed-forward
Feed-forward terms use the commanded trajectory to send a signal to the amplifier that predicts the required signal
Since PID systems respond based on error, this can almost always improve system response
PID does not have to “wait” for large error to build up before trying to catch up
Three Types of Feed-forward
Acceleration feed-forward (Aff)
Used to compensate for inertia
Friction feed-forward (Fff)
Used to compensate for classical kinetic friction
Velocity feed-forward (Vff)
Used to compensate for viscous friction (friction that is proportional to velocity)
Feed-forward Effect on Servo Command
Tuning for Feed-forward Terms
Command a move
Graph error versus time
Identify shape of error graph and try to match the effect of one or more of the three types of feed-forward
Apply feed-forward term and re-test with a move in the same direction
Identifying the need for Aff
The following graph of error versus time has a profile similar to the effect of Aff, therefore, Aff should be applied.
Identifying too much Aff
The following graph shows when too much Aff has been applied. Therefore, Aff needs to be reduced.
Identifying the need for Vff
The following graph of error versus time has a profile similar to the effect of Vff, therefore, Vff should be applied.
Dual-loop Control
Introduction to Dual-loop Control
Servo response of systems with backlash caused by lead screw or gearing can be improved through the use of dual-loop control.
A second encoder is added to the load so that the control system is aware of both the position of the motor shaft as well as the position of the load.
The encoder on the motor shaft is configured as the velocity encoder, and the encoder on the load is configured as the position encoder.
Dual-loop - Control Algorithm
Dual-loop Control – Encoder Resolution
When using dual-loop control, it is recommended that the velocity encoder resolution is higher than that of the position encoder
This results in better velocity estimation, especially at low speeds
Optimal ratios for velocity encoder resolution to position encoder resolution are between 3:1 and 10:1
Ratios of greater than 10:1 are possible, but not much more benefit is gained at greatly increased cost
Ratios of 1:1 or less are generally not recommended
Thank you!

Questions?


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Introduction to Servo Control & PID Tuning
Presented to:


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Agenda
•Introduction to Servo Control Theory
•PID Algorithm Overview
•Tuning & General System Characterization
•Oscillation Characterization
•Feed-forward Terms
•Dual-loop Control


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Positioning a Load
•Servo positioning systems are designed to precisely move a load along an axis of a coordinate system.
Load
Axis of movement


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Introduction to
Servo Control Theory


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Positioning with Servo Motors
•A servo motor can be used to move a load in conjunction with a lead screw.
Load
Motor
Lead screw


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Position Feedback
•It is theoretically possible, but not practical, to calculate the required motor current
-Exact physical properties of system components must be identified and must not change
•Position feedback is used to provide the control system with motor shaft position
-Enables the control system to ensure that the load gets to the commanded position
•


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Servo Positioning with Feedback
•An optical encoder is used to provide the control system with position feedback
Load
Motor
Control System
Command signal
Position feedback
Optical encoder


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
PID Algorithm Overview


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Servo Control with PID
•PID is the most commonly used servo control algorithm
-Proportional
-Integral
-Derivative
•
•PID systems can be understood by way of analogous physical models


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Understanding the Proportional Term
•Proportional term is analogous to the spring constant in a damped harmonic oscillator system
•Error = Desired position - Actual position
Spring with spring constant k
Load
Actual position
Desired position
Hooke’s law:
F = k * ( - D x )
PID Equivalent:
OutputP = P * (Error)


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Understanding the Derivative Term
•Derivative term is analogous to a “pot of honey” in a damped harmonic oscillator system
Load
Damping effect:
F = - b * v
Where –b is a damping term proportional
to velocity
PID Equivalent:
OutputD = D * D error
Pot of Honey
Pot of honey provides a damping force proportional to velocity


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Understanding the Integral Term
•Integral term contributes to the output in proportion to the sum of the error over time
•
•
Load
Actual position
Desired position
OutputI = I * (S error)
Since the I term builds up with the sum of the error over time, the effect is to generate a force that pulls the load into the desired position.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Limitations of “PD” Control
•“PD” systems are very effective for servo control, but they break down when friction in the system is high
•
•
Load
Actual position
Desired position
When the actual position is very close to the desired position, both error and
D error are very small.
This results in an output that is too low to overcome any friction in the system.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning & General
System Characterization


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
What is Tuning?
•Tuning \ tün·ing verb : The art of adjusting PID gains to optimize the motion of your system.
•


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – First Step is Safety
•Before doing anything related to tuning your servo motors, you must be sure your system is in a safe configuration
-Refer to Introduction to Servo Tuning handout
•
•Be sure to check wiring and set software limits to appropriate values
•


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Getting Started
•Initial tuning will concentrate on P & D gains
-Reminder: P » spring constant
D » damping factor
-
•General guidelines
-P is usually a small (0 – 10) positive integer
-D is usually = 10 * P
•


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Setting Initial P & D Gains
1.Set initial values for P & D
2.Command a motion and use Motion Console to graph Actual Position versus Time
3.If the motor doesn’t move at all, or doesn’t closely reach the target position, try doubling the P gain
4.Analyze graphs if motor is underdamped, overdamped, or critically damped.
5.An ideally tuned system is just under critically damped (underdamped).
1.
1.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Underdamped Motor
•If your system is underdamped, you will notice a large oscillation at the end of the move
•Try increasing D gain
-You can also decrease P gain, but increasing gains are recommended at this stage
Actual position
Command position


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Overdamped Motor
•If your system is overdamped, the motor will either take very long to complete the move or not get to the target position at all
•Try increasing P gain
-You can also decrease D gain, but increasing gains are recommended at this stage
Actual position
Command position


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Critically Damped Motor
•If your system is critically damped, you should not see much oscillation at the end of the move, and the motor should get to the target position fairly quickly.
Actual position
Command position


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Determining “In Position”
•If your final positioning accuracy can vary by several counts, a slightly underdamped system can get to the target position faster.
Actual position
Command position
Range of acceptable error


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – General Guidelines
•When tuning, use moves that are similar to the moves that you will use in your application
-Using the most aggressive moves (highest acceleration and/or longest time) will result in best results.
•When increasing K & D, use these guidelines:
-Dnew = Dold * (multiple)
-Pnew = Pold * (multiple)2


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Using the Integral Term
•Integral term can be used in two modes:
1.
1.Standing only (recommended)
2.Always
•
•When used in standing only, the Integral term only contributes to the servo command when the command position has stopped changing


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning – Initial Guidelines for I Term
•Start with I = 1
-I values are generally very small positive integers
•Command a move, and graph error versus time
•At the end of the move, the I term should pull the error down to zero
•Keep increasing the I gain until the error begins to oscillate, then revert to previous value.
•After tuning for the I gain, go back and double-check values for P & D gains.
-Generally after tuning for the I gain, you will need to either reduce P gain or increase D gain by 1-10%.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Oscillation Characterization


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Three General Types of Oscillation
•High-frequency oscillation
-Frequency of ½ or less of the sample rate
-Sometimes results in an audible high-frequency hum
-Oscillation is generally imperceptible to the human eye
-Generally indicates a D gain that is too large
•“Middle” frequency oscillations
-Period in between high- and low-frequency oscillations
-Generally indicates a P gain that is too large
-Approximately 1/10 of high-frequency
-


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Oscillations due to Mechanical Issues
•Some kinds of oscillations can be caused by problems with the mechanical system •Can be identified when changing PID gains doesn’t affect the period of the oscillations •If period of oscillation is proportional to the velocity of the move, a mechanical problem is usually the cause •Only solution is to fix the mechanical problem.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying High-Frequency Oscillations
•This graph indicates a motor tuned with a D gain that is too large


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying Low-Frequency Oscillations
•This graph indicates a motor tuned with an I gain that is too large


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying Middle-Frequency Oscillations
•This graph indicates a motor tuned with an P gain that is too large


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Feed-forward Terms


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Introduction to Feed-forward
•Feed-forward terms use the commanded trajectory to send a signal to the amplifier that predicts the required signal
-Since PID systems respond based on error, this can almost always improve system response
•
•PID does not have to “wait” for large error to build up before trying to catch up


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Three Types of Feed-forward
•Acceleration feed-forward (Aff)
-Used to compensate for inertia
•
•Friction feed-forward (Fff)
-Used to compensate for classical kinetic friction
-
•Velocity feed-forward (Vff)
-Used to compensate for viscous friction (friction that is proportional to velocity)


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Feed-forward Effect on Servo Command
Commanded trapezoidal velocity profile
Text Box: velocity
velocity
time
Acceleration feed-forward has additive effect on servo command during acceleration, no effect during slew, and subtractive effect during deceleration
Aff
Fff
Vff
Friction feed-forward has additive effect on servo command at all times during move.
Velocity feed-forward has additive effect on servo command directly proportional to velocity profile.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Tuning for Feed-forward Terms
1.Command a move
2.
2.Graph error versus time
3.
3.Identify shape of error graph and try to match the effect of one or more of the three types of feed-forward
4.
4.Apply feed-forward term and re-test with a move in the same direction


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying the need for Aff
•The following graph of error versus time has a profile similar to the effect of Aff, therefore, Aff should be applied.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying too much Aff
•The following graph shows when too much Aff has been applied. Therefore, Aff needs to be reduced.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Identifying the need for Vff
•The following graph of error versus time has a profile similar to the effect of Vff, therefore, Vff should be applied.


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Dual-loop Control


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Introduction to Dual-loop Control
•Servo response of systems with backlash caused by lead screw or gearing can be improved through the use of dual-loop control.
•
•A second encoder is added to the load so that the control system is aware of both the position of the motor shaft as well as the position of the load.
•
•The encoder on the motor shaft is configured as the velocity encoder, and the encoder on the load is configured as the position encoder.
•


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Dual-loop - Control Algorithm


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Dual-loop Control – Encoder Resolution
•When using dual-loop control, it is recommended that the velocity encoder resolution is higher than that of the position encoder
-This results in better velocity estimation, especially at low speeds
•
•Optimal ratios for velocity encoder resolution to position encoder resolution are between 3:1 and 10:1
-Ratios of greater than 10:1 are possible, but not much more benefit is gained at greatly increased cost
-Ratios of 1:1 or less are generally not recommended


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Thank you!

Questions?


Motion Engineering

Copyright 2001, Motion Engineering, Inc.
Three General Types of Oscillation
•Low-frequency oscillation
-Period greater than several samples
-Sometimes results in an audible low-frequency hum or rattle
-Oscillation is sometimes perceptible to the human eye
-Generally indicates an I gain that is too large
-Approximately 1/10 of middle-frequency
•


‹header›
‹date/time›
‹footer›
‹#›
Click to edit Master notes styles
Second Level
Third Level
Fourth Level
Fifth Level
Proposed MOCON Screen for Single Axis Tuning.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Lot’s of Audible Noise on Test Stand,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Proposed MOCON Screen for Single Axis Tuning.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Error Green Actual Velocity, Red Commanded velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Error Green Actual Velocity, Red Commanded velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


‹header›
‹date/time›
Motion Engineering Proprietary & Confidential
Page ‹#›
Motion Engineering, Inc.


Click to edit Master title style
Click to edit Master text styles
Second level
Third level
Fourth level
Fifth level
‹date/time›
‹footer›
‹#›


Notes
Outline
Slide 1
Single Axis MOCON
Set Kpv with no Smoothing Filter
Set Kpv with no Smoothing Filter
Kpv too low with no Smoothing Filter
Kpv too High with no Smoothing Filter
Kpv Acceptable with no Smoothing Filter
Adjust Kpv with Smoothing Filter
Set Kpv with Smoothing Filter
Kpv too Low with Smoothing Filter
Kpv too High With Smoothing Filter
Kpv Acceptable with Smoothing Filter
Adjust Kpp
Set Kpp
Kpp too low
Kpp acceptable
Kpp too High
Adjust Kvff
Set Kvff
Kvff Acceptable
Adjust Kip
Set Kip
Kip low
Kip Acceptable
Kip too High
Set Acceleration Feedforward.
Set Kaff
Jerk and Acceleration Profiles Kaff=0
Kaff is set
Viewing Axis Object with VM3
Filter Tool
Filter Tool Features


Motion Engineering, Inc.

XMP Single Axis Tuning
PIV

September 2000


Motion Engineering, Inc.

Single Axis MOCON
2
Proposed MOCON Screen for Single Axis Tuning.


Motion Engineering, Inc.

Set Kpv with no Smoothing Filter
3
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Kpv too low with no Smoothing Filter
5
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Kpv too High with no Smoothing Filter
6
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Lot’s of Audible Noise on Test Stand,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Kpv Acceptable with no Smoothing Filter
7
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Adjust Kpv with Smoothing Filter
8
Proposed MOCON Screen for Single Axis Tuning.


Motion Engineering, Inc.

Kpv too Low with Smoothing Filter
10
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kpv too High With Smoothing Filter
11
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kpv Acceptable with Smoothing Filter
12
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Adjust Kpp
13


Motion Engineering, Inc.

Kpp too low
15
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kpp acceptable
16
Position Error – Black
Commanded Velocity - Red
Actual Velocity – Green
DAC OUT - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kpp too High
17
Position Error – Black
Commanded Velocity - Red
Actual Velocity – Green
DAC Out Yellow
Yellow DAC
Black Error Green Actual Velocity, Red Commanded velocity


Motion Engineering, Inc.

Adjust Kvff
18


Motion Engineering, Inc.

Kvff Acceptable
20
Position Error – Black
Commanded Velocity - Red
Actual Velocity – Green
Position Error – Black
Commanded Velocity - Red
Actual Velocity – Green
DAC OUT - Yellow
Yellow DAC
Black Error Green Actual Velocity, Red Commanded velocity


Motion Engineering, Inc.

Adjust Kip
21


Motion Engineering, Inc.

Kip low
23
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kip Acceptable
24
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kip too High
25
Commanded Velocity – Black
Actual Velocity – Green
DAC Out - Yellow
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Set Acceleration Feedforward.
26


Motion Engineering, Inc.

Jerk and Acceleration Profiles Kaff=0
28
Commanded Velocity – Red
Actual Velocity – Green
DAC Out - Purple
Commanded Jerk – Brown
Commanded Acceleration – Green
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Kaff is set
29
Commanded Velocity – Red
Actual Velocity – Green
DAC Out - Purple
Commanded Jerk – Brown
Commanded Acceleration – Green
Yellow DAC
Black Commanded Velocity , Green Actual Velocity


Motion Engineering, Inc.

Viewing Axis Object with VM3
30


Motion Engineering, Inc.

Filter Tool
31


Motion Engineering, Inc.

Filter Tool Features
32
1.Designs Low Pass, Notch and Custom Filters
2.Filters specified in Analog Domain
3.Mapped to digital domain with bilinear Transform
4.Prewarping performed for Low Pass and Notch Filters
5.Saves Filter Coefficients to a file
6.Loads Filter Coefficients from a file.
7.6 Biquad blocks for PID
8.5 Biquad blocks for PIV
9.


Motion Engineering, Inc.

Set Kpv with no Smoothing Filter
4
Important XMP Settings
1.Kvff = 1
2.Kpp=0
3.Error limit should be set for move distance
4.Position error limit action set to abort
Parameters to be adjusted
1.Kpv
2.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Set Kpv with Smoothing Filter
9
Important XMP Settings
1.Kvff = 1
2.Kpp=0
3.Error limit should be set for move distance
4.Position error limit action set to abort
Parameters to be adjusted
1.Kpv
2.Ka1 is varied from 0 to 1 after Kpv is set.
3.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Set Kpp
14
Important XMP Settings
1.Kvff = 0
2.Kpv value already set
3.Ka1 value already set
4.Error limit should be set for move distance
5.Position error limit action set to abort
Parameters to be adjusted
1.Kpp
2.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Set Kvff
19
Important XMP Settings
1.Kpp value already set
2.Kpv value already set
3.Ka1 value already set
4.Error limit should be set for move distance
5.Position error limit action set to abort
Parameters to be adjusted
1.Kvff is set to one
2.
Note: Kvff is set to 1 if the same encoder is used For both position feedback and the
velocity estimate In a dual loop system Kvff will be the ratio of The velocity encoder to the position
encoder for a given distance.
1.
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Set Kaff
27
Important XMP Settings
1.Kip value already set
2.Kvff value already set
3.Kpp value already set
4.Kpv value already set
5.Ka1 value already set
6.Error limit should be set for move distance
7.Position error limit action set to abort
Parameters to be adjusted
1.Kaff
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Motion Engineering, Inc.

Set Kip
22
Important XMP Settings
1.Kvff value already set
2.Kpp value already set
3.Kpv value already set
4.Ka1 value already set
5.Error limit should be set for move distance
6.Position error limit action set to abort
Parameters to be adjusted
1.Kip
Yellow DAC
Black Commanded Velocity , Green Actual Velocity
Test Stand Quiet,
Fix’s more resolution or 1/t


Microsoft HTML Help Compiler 4.74.8702

Compiling s:\mainsupport\mei20030620.1.1.chm

HHC3004: Warning: capture1.c.html : The HTML tag "= 0) {		long	position[2] = {0, 0};        re..." is not a valid HTML tag (it does not begin with an alphanumeric character).
HHC3004: Warning: motorfbak.c.html : The HTML tag "= 0) {                <font color="#008800"" is not a valid HTML tag (it does not begin with an alphanumeric character).
HHC3004: Warning: sqevent1.c.html : The HTML tag "= 0) {        MPIEventStatus  eventStatus;  ..." is not a valid HTML tag (it does not begin with an alphanumeric character).
HHC3004: Warning: sqnodeevent1.c.html : The HTML tag "= 0) {       <font color="#008800"" is not a valid HTML tag (it does not begin with an alphanumeric character).
HHC3004: Warning: sqstatus1.c.html : The HTML tag "(netInfo.nodeOffset + netInfo.nodeCount);       ..." is not a valid HTML tag (it does not begin with an alphanumeric character).
HHC3004: Warning: opr1.htm : The HTML tag "=)</td" is not a valid HTML tag (it does not begin with an alphanumeric character).

Compile time: 3 minutes, 30 seconds
1,682	Topics
12,651	Local links
41	Internet links
1,170	Graphics

Created s:\mainsupport\mei20030620.1.1.chm, 50,331,934 bytes
Compression decreased file by 30,541,192 bytes.


FrontPage Configuration Information

In the HTML comments, this page contains configuration information that the FrontPage Explorer and FrontPage Editor need to communicate with the FrontPage server extensions installed on this web server. Do not delete this page.


CD-ROM Version of the Documentation

.

For users who write application code on a system that does not have an Internet connection, it may be helpful to have a CD-ROM version of the documentation. This will provide you another way of accessing the documentation.

If you are interested in receiving a CD-ROM version of our documentation, please email us at sales@motioneng.com. Please be sure to include the version of the MPI library (ex: 20021212.1.7) that you are currently using.


MEI's On-line Technical Support

Welcome to Motion Engineering on the Web!
For full access to the support site, please complete this simple registration form. By becoming a member, you'll get the most up-to-date information available, exclusive web-only features, and much more.

The information you provide remains confidential and is not shared with any third party. Please see our privacy policy for more information.

Already registered? If yes, click here.
Legal Notice | Tech Email | Feedback | tel: (805) 681-3300 | fax: (805) 681-3311
Copyright 2002 Motion Engineering


MEI's On-line Technical Support

Thank You for registering!

You now have full access to the support site.

Remember, the information you provide remains confidential and is not shared with any third party. Please see our privacy policy for more information.

Legal Notice | Tech Email | Feedback | tel: (805) 681-3300 | fax: (805) 681-3311
Copyright 2002 Motion Engineering


Motion Engineering, Inc. | Copyright Notice© 1995-2002

Legal Notice

COPYRIGHT

Copyright Motion Engineering, Inc., 1995-2003. All Rights Reserved.

TERMS OF USE

By accessing the documentation within this website, you acknowledge that the data and information that is provided throughout this website is intended for the informational purposes of Motion Engineering Inc.(MEI) and its customers. Motion Engineering Inc. reserves the right to update the information on these pages as it deems necessary without notice to the user. The information that is contained on these pages is constantly updated and is intended to provide the most recent and up-to-date documentation.

The documentation found herein may be different than the documentation that was given at a particular software release. Motion Engineering Inc. does not guarantee that the information found on this website is still valid for previous software releases. Therefore, it is the responsibilty of the user to decipher whether or not the information on this website is still relevant to a particular release of software.

DISCLAIMER

MEI shall not be responsible for any errors or omissions contained at this website, and reserves the right to make changes without notice. Accordingly, all MEI and third party information is provided "AS IS."

MEI DISCLAIMS ALL WARRANTIES WITH REGARD TO THE INFORMATION (INCLUDING ANY SOFTWARE) PROVIDED, INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU.

In no event shall MEI be liable for any damages whatsoever, and in particular MEI shall not be liable for special, indirect, consequential, or incidental damages, or damages for lost profits, loss of revenue, or loss of use, arising out of or related to the MEI website or the information contained in it, whether such damages arise in contract, negligence, tort, under statute, in equity, at law or otherwise.

This website contains proprietary and confidential information of Motion Engineering, Inc., and is protected by federal copyright law. The contents of the website may not be disclosed to third parties, translated, copied, or duplicated in any form, in whole or in part, without the express written consent of Motion Engineering, Inc.


What has Changed?

"Out with the old, in with the new."

Why did we change the website?

Current Version
http://support.motioneng.com
Version 1.0

Some Weaknesses

  • Kept the manual-style format (breakdown by chapters). Didn't take full advantage of a cross-linking web environment. It was too linear.
  • No global search functionality. Although there was a hardware and utility-specific search engine.
  • Unable to bookmark a particular page (on certain browsers) because of the use of Frames in the design.
  • Limited interface that was not flexible. Original interface did not allow for the addition of subtopics like SynqNet, MPX, Bode Tool, etc.

What has changed?

New Version
http://support2.motioneng.com
Version 2.0

New Features

  • Elimination of manual style format. Documentation is broken down by topics; no more chapters.
  • Global search functionality (coming soon)
  • Ability to bookmark a particular page. Useful for sending direct links to customers via email to point them to a specific page of documentation. Also useful for customers who visit a particular part of the website regularly and wish to bookmark it.
  • New Interface
    • use of javascript pulldown bars for navigation. Very flexible. Can easily add new sections.
    • quick links
    • faqs
  • Addition of Message, Bode, Flash, Version, and Server Utility documentation.
  • Addition of MPX documentation
  • Addition of SynqNet documentation
  • Updated HTML Help version of the website. This is used for integrating MEI's documentation within MSDN. (coming soon)

WIP

  • Global Search Engine
  • SynqNet Technology
    • Fill-in documentation for topics
  • SynqNet Hardware
    • Drive documentation (what do we document on our side?)
  • MPI Software Documentation
    • Add navigational header to MPI Software data types and methods
    • Add documentation for SynqNet and Block objects.
  • MPX Software Documentation
    • add diagrams where necessary
    • add documentation to "Concepts" section
    • add sample applications
  • Update MoCon section so that is reflects support for SynqNet and CAN
  • Anything else?


Use the form below to search for documents in this web containing specific words or combinations of words

Use the form below to search for documents in this web containing specific words or combinations of words. The text search engine will display a weighted list of matching documents, with better matches shown first. Each list item is a link to a matching document; if the document has a title it will be shown, otherwise only the document's file name is displayed. A brief explanation of the query language is available, along with examples.

Search for:

Query Language

The text search engine allows queries to be formed from arbitrary Boolean expressions containing the keywords AND, OR, and NOT, and grouped with parentheses. For example:

information retrieval
finds documents containing 'information' or 'retrieval'

information or retrieval
same as above

information and retrieval
finds documents containing both 'information' and 'retrieval'

information not retrieval
finds documents containing 'information' but not 'retrieval'

(information not retrieval) and WAIS
finds documents containing 'WAIS', plus 'information' but not 'retrieval'

web*
finds documents containing words starting with 'web'

Back to Top
Author information goes here.
Copyright © 2001 [OrganizationName]. All rights reserved.
Revised: 06/18/03.


Web Posting Information

Web Publishing Information

The HTML comments in this page contain the configurationinformation that allows users to edit pages in your web using the Microsoft Web Publishing Wizard or programs which use the Microsoft Web Publishing Wizard such as FrontPad using the same username and password they would use if they were authoring with Microsoft FrontPage. Please refer to the Microsoft's Internet SDK for more information on the Web Publishing Wizard APIs.


Motion Engineering, Inc. | Privacy Policy

MEI believes protecting your privacy is important. The following is our Support Site privacy policy and we hope it clarifies how MEI processes and uses certain information collected via the Support Site website (http://support.motioneng.com). This policy varies from the way information is collected via our main public site (http://www.motioneng.com).

Information Collection
At times we may request that you voluntarily supply us with personal information, such as your name, email address, and postal address, to access the support site or for purposes such as corresponding with us, submitting questions, and participating in an online survey. This information is for internal use only and is not shared with any third parties outside of Motion Engineering, Inc.

Like many other commercial websites, the MEI website may use a standard technology called a "cookie" to collect information about how you use the site. Cookies are identifiers which a website can send to your browser to keep on your computer to facilitate your next visit to our site. You can set your browser to notify you when you are sent a cookie, giving you the chance to decide whether or not to accept it. The information we collect and analyze is used to improve our website for you.

Information Use
If you provide us with your email or postal address, or have done so in the past, we will ask you if we can use it to send you updates on the latest MEI products and technology notes. If you do not want us to contact you, you can choose to "opt out," and MEI will respect your wishes.

Because MEI operates globally, we make company information available to our worldwide business units. As part of this process, the personal information that you have provided to us may be sent to other MEI business units around the world. However, we do not share your profile with anyone else outside of MEI without your consent, and no one else can access your information.

Declining Email
Although most customers tell us they appreciate receiving MEI technical news, bulletins, and other information, we recognize the importance of providing you with choices. At any time, you may request to discontinue receiving these emails from us by simply replying to the email and informing us of your preferences. All email that you receive from MEI will tell you how to decline further emails.

Thank you for your support of these policies and Motion Engineering, Inc.

Last updated October 30, 2002
© 2002 Motion Engineering, Inc. All rights reserved.


This is a working copy of the support site that should replace the existing support.motioneng.com site when the PR is released at the end of Apr 2003.

NOTE: Should only copy over the following folders:
- Software-MPI
- Utilities
- Technology>SynqNet

-Dean Onishi
Apr-2-03


Good Version. Rollover sample from Objects home page in Tech Support 1. Messed up version on default.htm in Tech Support 2. Rollover doesn't work.
Good Version. Rollover on default.htm in Tech Support 2. Rollover works.


Select Your Version of the MPI

.

Select Your Version of the MPI

SynqNet Phase II

MPI Library: 20030620.1.1
Firmware: 459B1
MPX: N/A
Rincon: 211
Node FPGA: 0x020C
To see what has changed, please see the General Release Note for the 20030620.1.1 release.

NOTE: The documentation for this particular release can be found on http://support.motioneng.com. It has up-to-date documentation and is synchronized with the latest version of the 20030620.1.1 release.

HTML Help Version - No Internet connection is required.

Download HTML Help Version coming soon!

MPI Library: 20021212.1.9
Firmware:
MPX: N/A
Rincon: 140
Node FPGA: 0x0103
To see what has changed, please see the General Release Note for the 20021212.1.9 release.
To see the original, please see the General Release Note for the 20021212 release.

HTML Help Version - No Internet connection is required.

Download HTML Help Version (20021212)

Analog

MPI Library: 20020117.1.8
Firmware: 434A1
MPX: 01.01.07
To see what has changed, please see the General Release Note for the 20020117.1.8 release.
To see the original, please see the General Release Note for the 20020117 release.

NOTE: The documentation for this particular release can be found on http://support1.motioneng.com.

HTML Help Version - No Internet connection is required.

Download HTML Help Version (20020117.1.3)


FrontPage Run-Time Component Page

You have submitted a form or followed a link to a page that requires a web server and the FrontPage Server Extensions to function properly.

This form or other FrontPage component will work correctly if you publish this web to a web server that has the FrontPage Server Extensions installed.

Click the <Back> arrow to return to the previous page.


Software FAQs

.

Software FAQs

- What is the MPI?

- Why was the MPI developed?

- What are the prerequisites for learning the MPI?

- What is the difference between 'mpi' and 'mei' data types and methods?

- What is the MPX?

- What is the difference between the MPI and MPX in terms of functionality, authoring code, etc.?

- Should I use the MPI or the MPX to author code?

- How can I perform a silent installation of MEI software (MDK) in a user defined directory?

- How can I verify that MEI software (MDK) has already been installed?

- What is the difference between a node and a motion block on a SynqNet Motion Network?

What is the MPI?

The Motion Programming Interface (MPI) defines a set of object-oriented, C-language functions and data types that you can use to develop motion control applications. The MPI is designed to be independent of the motion controller hardware used, as well as the platform (operating system & compiler) on which the motion control application is built.

To support the MPI, a platform must be 32-bit (e.g. Windows NT). Most 32-bit platforms are capable of multi-threading and multi-tasking, and the MPI has built-in features that simplify the design and development of these types of applications.

Why was the MPI developed?

The MPI is a C language, object-oriented interface that makes it easy to develop motion control applications that run on different types of platforms. Programs written using the MPI range from simple, single-task, single-controller applications to complex multi-task applications that use mutiple motion controllers. The MPI hides platform-specific and firmware implementation details while providing a rich set of functions to control motion at any desired level.

What are the prerequisites for learning the MPI?

You do not need to be a master programmer, but you do need a solid foundation in C. The XMP is a C-programmable motion controller that uses object-oriented programming. Familiarity with C will allow you to quickly attack potentially complex implementation issues. Some familiarity with the basic concepts of motion control is required to understand how to use the sample applications. With no concept of motion control, it is dificult to know what parameters to set to make a motion.

What is the difference between 'mpi' and 'mei' data types and methods?

The purpose of the MPI/MEI prefixes was to prevent any possible conflict with any symbols already defined in the supported operating systems and in C-language and third-party libraries.

  • MPI/MEI - data symbol (data type)
  • mpi/mei - code symbol (method)

The “MEI/mei” prefix denotes additions or extensions to the MPI that usually pertain to the XMP. For example, the MEIAxisConfig{} data structure contains XMP-specific axis configuration parameters that extend the MPI-defined axis configuration parameters (beyond what is already defined in MPIAxisConfig).

Earlier versions of the MPI classified objects or features as generic (MPI) or target-specific (MEI). Generic features were supposed to apply to any motion control design, while target-specific features were only applicable to the XMP. This differentiation has been abandoned for the most part, but backward compatibility has caused some separation of these features to remain. MPI data descriptions are contained in header files in the MPI/include directory while MEI data descriptions are in XMP/include. The documentation emphasizes the type (MPI or MEI) for each feature.

What is the MPX?

The MPX is an ActiveX API (application programming interface) to MPI-compatible controllers (currently only the XMP family). It is an alternative way of writing code for users who do not want to write C code using the standard MPI libraries.

What is the difference between the MPI and MPX in terms of functionality, authoring code, etc.?

The MPI can only be used by C and C++ compilers while the MPX can be used by any language that supports ActiveX controls -- including scripting languages.

The MPX only runs on Windows while the MPI can be used on many more operating systems.

The MPX is easier to use for most tasks, but for complicated tasks it can be more difficult to use, in which case it is better to use the MPI.

The MPX is programmed using the MPI, so everything that is possible with the MPX is possible with the MPI.

Should I use the MPI or the MPX to author code?

The MPX is easier to use for most tasks. There are some tasks that the MPX does not currently support where the MPI would need to be used. Typically, you should program using the MPI if one of the following is true:

  • If the MPX does not provide the functionality you need
  • If the overhead of running an ActiveX control is unacceptable
  • If you are programming on a platform other than Windows

Otherwise, you can program using the MPX.

How can I perform a silent installation of MEI software (MDK) in a user defined directory?

In the command line prompt, type the following:

Win32Setup /v"/qn INSTALLDIR=\"C:\Program Files\Mei\" INSTALLLEVEL=32767" /s

How can I verify that MEI software (MDK) has already been installed?

Check the Winnt\System32 directory to see if the mpivc*.dll file exists. We currently use the mpivc40.dll, mpivc60.dll, and mpivc60d.dll, depending on the version of software installed.. When the MEI software is uninstalled, the MPI *.dll is removed.

What is the difference between a node and motion block on a SynqNet Motion Network?

A node is a place on a network where something happens. For example, CAN is an I/O network that connects I/O nodes (places to hook up digital or analog inputs and outputs).

A motion block refers to a node on a SynqNet Motion Network that is related to motion. A motion block has connections for motors, encoders, I/O, etc.


Quick-Link Pinouts

Quick-Links to Connector Pinouts

SynqNet-XMP
Controller I/O
HD15
Micro-D
RJ-45
Backplane Bus Interface
CAN
Rear I/O Bus

Analog-XMP
 PCI Bus
CPCI-3U Bus
CPCI-6U Bus
PMC Bus

PCI Main I/O
PCI Expansion I/O
CPCI-3U I/O
CPCI-6U Main, Front I/O
CPCI-6U Expansion, Front I/O
CPCI-6U Main, Rear I/O
CPCI-6U Expansion, Rear I/O
DSP
 CPCI
LC
PCX
STD
LC
PCX
104X


eXMP-LCF Controller

eXMP-LCF
Pinout Information

I/O Connectors | Tranceiver Connectors | Serial (COM) Connectors |
Ethernet Connector | Power Connector |
See Note on Optical Coupling and Transceiver Circuits

I/O Connectors

J1: Axes 0-1
50-pin 0.50 Series D-Sub SCII-2 & 3 A
Pin | MEI Signal | Elect. Signal | Type
1 | VCC_F01 | DC5V 0 |
2 |  | EMST 0 |
3 | User I/O | CLR 0 | 01
4 |  | SYNCOFF 0 |
5 |  | RESERVED |
6 | Amp Flt 1 | ALM+ 0 | I1
7 | OGND | ALM- 0 |
8 | OGND | COM 0 |
9 |  | DIFERR 0 |
10 | XCVRE MOT 0- | CWP+ A0 | X1
11 | XCVRE MOT 0+ | CWP- A0 | X1
12 | XCVRF MOT 0- | CCWP- A0 | X1
13 | XCVRF MOT 0+ | CCWP+ A0 | X1
14 | XCVRE MOT 1+ | CWP+ B1 | X1
15 | XCVRE MOT 1- | CWP- B1 | X1
16 | XCVRF MOT 1- | CCWP- B1 | X1
17 | XCVRF MOT 1+ | CCWP+ B1 | X1
18 | Amp En 1 Col | SVON B1 | 01
19 |  | +OT B1 |
20 |  | -OT B1 |
21 | Home/Lim Rtn 1* | Home Rtn 1 | I2
22 | Home 1 | IPOS B1
23 | User I/O 0* | 24 VDC Rtn |
24 | User I/O Rtn 0 | Retract 0 |
25 | Amp Flt 0 | RDY 0 | I1
26 | Enc 1 A+ | CHA B1 | E1
27 | Enc 1 A- | CHA B1 | E1
28 | Enc 1 B+ | CHA B1 | E1
29 | Enc 1 B- | CHA B1 | E1
30 | Enc 1 Z+ | CHZ B1 | E1
31 | Enc 1 Z- | CHZ B1 | E1
32 | Cmd Dac Out 1+ | AIN+ B1 |
33 | Cmd Dac Out 1- | AIN- B1 |
34 | Amp En 0 Col | SVON A0 | 01
35 |  | +OT A0 |
36 |  | -OT A0 |
37 | Home/Lim Rtn 0* | Home Rtn 0 | I2
38 | Home 0 | IPOS A0
39 | Home 0_24V |  |
40 | Home 1_24V |  |
41 | Retract 0_24V |  |
42 | Enc 0 A+ | CHA A0 | E1
43 | Enc 0 A- | CHA A0 | E1
44 | Enc 0 B+ | CHB A0 | E1
45 | Enc 0 B- | CHB A0 | E1
46 | Enc 0 Z+ | CHZ A0 | E1
47 | Enc 0 Z- | CHZ A0 | E1
48 | SGND | SGND 0 |
49 | Cmd Dac Out 0+ | AIN+ A0 |
50 | Cmd Dac Out 0- | AIN- A0 |

J2: Axes 2-3
50-pin 0.50 Series D-Sub SCII-2 & 3 A
Pin | MEI Signal | Elect. Signal | Type
1 | VCC_F23 | DC5V 2 |
2 |  | EMST 2 |
3 | User I/O 3 | CLR 2 | 01
4 |  | SYNCOFF 2 |
5 |  | RESERVED |
6 | Amp Flt 3 | ALM+ 2 | I1
7 | OGND | ALM- 2 |
8 | OGND | COM 2 |
9 |  | DIFERR 2 |
10 | XCVRE MOT 2+ | CWP+ A2 | X1
11 | XCVRE MOT 2- | CWP- A2 | X1
12 | XCVRF MOT 2- | CCWP- A2 | X1
13 | XCVRF MOT 2+ | CCWP+ A2 | X1
14 | XCVRE MOT 3+ | CWP+ B3 | X1
15 | XCVRE MOT 3- | CWP- B3 | X1
16 | XCVRF MOT 3- | CCWP- B3 | X1
17 | XCVRF MOT 3+ | CCWP+ B3 | X1
18 | Amp En 3 Col | SVON B3 | 01
19 |  | +OT B3 |
20 |  | -OT B3 |
21 | Home/Lim Rtn 3* | Home Rtn 3 | I2
22 | Home 3 | IPOS B3
23 | User I/O 2* | 24V Rtn |
24 | User I/O Rtn 2 | Retract 1 |
25 | Amp Flt 2 | RDY 2 | I1
26 | Enc 3 A+ | CHA B3 | E1
27 | Enc 3 A- | CHA B3 | E1
28 | Enc 3 B+ | CHA B3 | E1
29 | Enc 3 B- | CHA B3 | E1
30 | Enc 3 Z+ | CHZ B3 | E1
31 | Enc 3 Z- | CHZ B3 | E1
32 | Cmd Dac Out 3+ | AIN+ B3 |
33 | Cmd Dac Out 3- | AIN- B3 |
34 | Amp En 2 Col | SVON A2 | 01
35 |  | +OT A2 |
36 |  | -OT A2 |
37 | Home/Lim Rtn 2* | Home Rtn 2 | I2
38 | Home 2 | IPOS A2
39 | Home 2_24V |  |
40 | Home 3_24V |  |
41 | Retract 1_24V |  |
42 | Enc 2 A+ | CHA A2 | E1
43 | Enc 2 A- | CHA A2 | E1
44 | Enc 2 B+ | CHB A2 | E1
45 | Enc 2 B- | CHB A2 | E1
46 | Enc 2 Z+ | CHZ A2 | E1
47 | Enc 2 Z- | CHZ A2 | E1
48 | SGND | SGND 2 |
49 | Cmd Dac Out 2+ | AIN+ A2 |
50 | Cmd Dac Out 2- | AIN- A2 |

J4: Axes 4-5
50-pin 0.50 Series D-Sub SCII-2 & 3 A
Pin | MEI Signal | Elect. Signal | Type
1 | VCC_F45 | DC5V 2 |
2 |  | EMST 4 |
3 | User I/O 5 | CLR 4 | 01
4 |  | SYNCOFF 4 |
5 |  | RESERVED |
6 | Amp Flt 3 | ALM+ 4 | I1
7 | OGND | ALM- 4 |
8 | OGND | COM 4 |
9 |  | DIFERR 4 |
10 | XCVRE MOT 4+ | CWP+ A4 | X1
11 | XCVRE MOT 4- | CWP- A4 | X1
12 | XCVRF MOT 4- | CCWP- A4 | X1
13 | XCVRF MOT 4+ | CCWP+ A4 | X1
14 | XCVRE MOT 5+ | CWP+ B5 | X1
15 | XCVRE MOT 5- | CWP- B5 | X1
16 | XCVRF MOT 5- | CCWP- B5 | X1
17 | XCVRF MOT 5+ | CCWP+ B5 | X1
18 | Amp En 5 Col | SVON B3 | 01
19 |  | +OT B3 |
20 |  | -OT B3 |
21 | Home/Lim Rtn 5* | Home Rtn 5 | I2
22 | Home 5 | IPOS B5
23 | User I/O 4 | 24V Rtn |
24 | User I/O Rtn 4* | Retract 2 |
25 | Amp Flt 4 | RDY 4 | I1
26 | Enc 5 A+ | CHA B5 | E1
27 | Enc 5 A- | CHA B5 | E1
28 | Enc 5 B+ | CHA B5 | E1
29 | Enc 5 B- | CHA B5 | E1
30 | Enc 5 Z+ | CHZ B5 | E1
31 | Enc 5 Z- | CHZ B5 | E1
32 | Cmd Dac Out 5+ | AIN+ B5 |
33 | Cmd Dac Out 5- | AIN- B5 |
34 | Amp En 4 Col | SVON A4 | 01
35 |  | +OT A4 |
36 |  | -OT A4 |
37 | Home/Lim Rtn 4* | Home Rtn 4 | I2
38 | Home 4 | IPOS A4
39 | Home 4_24V |  |
40 | Home 5_24V |  |
41 | Retract 2_24V |  |
42 | Enc 4 A+ | CHA A4 | E1
43 | Enc 4 A- | CHA A4 | E1
44 | Enc 4 B+ | CHB A4 | E1
45 | Enc 4 B- | CHB A4 | E1
46 | Enc 4 Z+ | CHZ A4 | E1
47 | Enc 4 Z- | CHZ A4 | E1
48 | SGND | SGND 4 |
49 | Cmd Dac Out 4+ | AIN+ A24 |
50 | Cmd Dac Out 4- | AIN- A4 |

J5: Axes 6-7
50-pin 0.50 Series D-Sub SCII-2 & 3 A
Pin | MEI Signal | Elect. Signal | Type
1 | VCC_F67 | DC5V 6 |
2 |  | EMST 6 |
3 | User I/O 7 | CLR 6 | 01
4 |  | SYNCOFF 6 |
5 |  | RESERVED |
6 | Amp Flt 7 | ALM+ 6 | I1
7 | OGND | ALM- 6 |
8 | OGND | COM 6 |
9 |  | DIFERR 6 |
10 | XCVRE MOT 6+ | CWP+ A6 | X1
11 | XCVRE MOT 6- | CWP- A6 | X1
12 | XCVRF MOT 6- | CCWP- A6 | X1
13 | XCVRF MOT 6+ | CCWP+ A6 | X1
14 | XCVRE MOT 7+ | CWP+ B7 | X1
15 | XCVRE MOT 7- | CWP- B7 | X1
16 | XCVRF MOT 7- | CCWP- B7 | X1
17 | XCVRF MOT 7+ | CCWP+ B7 | X1
18 | Amp En 7 Col | SVON B7 | 01
19 |  | +OT B7 |
20 |  | -OT B7 |
21 | Home/Lim Rtn 7 | Home Rtn 7 | I2
22 | Home 7 | IPOS B7
23 | User I/O 6 | 24V Rtn |
24 | User I/O Rtn 3 | Retract 3 |
25 | Amp Flt 6 | RDY 6 | I1
26 | Enc 7 A+ | CHA B7 | E1
27 | Enc 7 A- | CHA B7 | E1
28 | Enc 7 B+ | CHA B7 | E1
29 | Enc 7 B- | CHA B7 | E1
30 | Enc 7 Z+ | CHZ B7 | E1
31 | Enc 7 Z- | CHZ B7 | E1
32 | Cmd Dac Out 7+ | AIN+ B7 |
33 | Cmd Dac Out 7- | AIN- B7 |
34 | Amp En 6 Col | SVON A6 | 01
35 |  | +OT A6 |
36 |  | -OT A6 |
37 | Home/Lim Rtn 6 | Home Rtn 6 | I2
38 | Home 6 | IPOS A6
39 | Home 6_24V |  |
40 | Home 7_24V |  |
41 | Retract 3_24V |  |
42 | Enc 6 A+ | CHA A6 | E1
43 | Enc 6 A- | CHA A6 | E1
44 | Enc 6 B+ | CHB A6 | E1
45 | Enc 6 B- | CHB A6 | E1
46 | Enc 6 Z+ | CHZ A6 | E1
47 | Enc 6 Z- | CHZ A6 | E1
48 | SGND | SGND 6 |
49 | Cmd Dac Out 6+ | AIN+ A6 |
50 | Cmd Dac Out 6- | AIN- A6 |

Tranceiver Connectors

J3: XCVRs for LCF (Set 1)
40-pin 0.050 Series D-Sub
Pin | MEI Signal | Elect. Signal | Type
1 | XCVRC Mot 0+ | ADDR 0+ | X1
2 | XCVRC Mot 0- | ADDR 0- | X1
3 | XCVRD Mot 0- | ADDR 1- | X1
4 | XCVRD Mot 0+ | ADDR 1+ | X1
5 | XCVRC Mot 2- | ADDR 2- | X1
6 | XCVRC Mot 2+ | ADDR 2+ | X1
7 | XCVRC Mot 1+ | CLOCK LO+ 1 | X1
8 | XCVRC Mot 1- | CLOCK LO- 1 | X1
9 | XCVRD Mot 1+ | CLOCK HI+ 1 | X1
10 | XCVRD Mot 1- | CLOCK HI- 1 | X1
11 | XCVRA Mot 0- | SENSE 0- | X3
12 | XCVRA Mot 0+ | SENSE 0+ | X3
13 | XCVRB Mot 0- | SENSE 1- | X3
14 | XCVRB Mot 0+ | SENSE 1+ | X3
15 | XCVRA Mot 1- | SENSE 2- | X3
16 | XCVRA Mot 1+ | SENSE 2+ | X3
17 | XCVRB Mot 1- | SENSE 3- | X3
18 | XCVRB Mot 1+ | SENSE 3+ | X3
19 | XCVRA Mot 2- | SENSE 4- | X3
20 | XCVRA Mot 2+ | SENSE 4+ | X3
21 | XCVRB Mot 2- | SENSE 5- | X3
22 | XCVRB Mot 2+ | SENSE 5+ | X3
23 | XCVRA Mot 3- | SENSE 6- | X3
24 | XCVRA Mot 3+ | SENSE 6+ | X3
25 | XCVRB Mot 3- | SENSE 7- | X3
26 | XCVRB Mot 3+ | SENSE 7+ | X3
27 |  | +24 VDC |
28 |  | +24 VDC |
29 |  | +24 VDC |
30 | XCVRD Mot 2+ | ADDR 3+ | X1
31 | XCVRD Mot 2- | ADDR 3- | X1
32 |  | 24V COMM |
33 |  | 24V COMM |
34 |  | 24V COMM |
35 | XCVRD Mot 3- | SPARE XCVR 1- | X1
36 | SGND | SGND | 100 ohm to DGND
37 | XCVRD Mot 3+ | SPARE XCVR 1- | X1
38 |  |  |
39 | XCVRC Mot 3- | SPARE | X1
40 | XCVRC Mot 3+ | SPARE | X1

J6: XCVRs for LCF (Set 2)
40-pin 0.050 Series D-Sub
Pin | MEI Signal | Elect. Signal | Type
1 | XCVRC Mot 0+ | ADDR 0+ | X1
2 | XCVRC Mot 0- | ADDR 0- | X1
3 | XCVRD Mot 0- | ADDR 1- | X1
4 | XCVRD Mot 0+ | ADDR 1+ | X1
5 | XCVRC Mot 2- | ADDR 2- | X1
6 | XCVRC Mot 2+ | ADDR 2+ | X1
7 | XCVRC Mot 5+ | CLOCK LO+ 2 | X1
8 | XCVRC Mot 5- | CLOCK LO- 2 | X1
9 | XCVRD Mot 5+ | CLOCK HI+ 2 | X1
10 | XCVRD Mot 5- | CLOCK HI- 2 | X1
11 | XCVRA Mot 4- | SENSE 8- | X3
12 | XCVRA Mot 4+ | SENSE 8+ | X3
13 | XCVRB Mot 4- | SENSE 9- | X3
14 | XCVRB Mot 4+ | SENSE 9+ | X3
15 | XCVRA Mot 5- | SENSE 10- | X3
16 | XCVRA Mot 5+ | SENSE 10+ | X3
17 | XCVRB Mot 5- | SENSE 11- | X3
18 | XCVRB Mot 5+ | SENSE 11+ | X3
19 | XCVRA Mot 6- | SENSE 12- | X3
20 | XCVRA Mot 6+ | SENSE 12+ | X3
21 | XCVRB Mot 6- | SENSE 13- | X3
22 | XCVRB Mot 6+ | SENSE 13+ | X3
23 | XCVRA Mot 7- | SENSE 14- | X3
24 | XCVRA Mot 7+ | SENSE 14+ | X3
25 | XCVRB Mot 7- | SENSE 15- | X3
26 | XCVRB Mot 7+ | SENSE 15+ | X3
27 |  | +24 VDC |
28 |  | +24 VDC |
29 |  | +24 VDC |
30 | XCVRD Mot 2+ | ADDR 3+ | X1
31 | XCVRD Mot 2- | ADDR 3- | X1
32 |  | 24V COMM |
33 |  | 24V COMM |
34 |  | 24V COMM |
35 | XCVRD Mot 7- | SPARE XCVR 2- | X1
36 | SGND | SGND | 100 ohm to DGND
37 | XCVRD Mot 7+ | SPARE XCVR 2- | X1
38 |  |  |
39 | XCVRC Mot 7- | SPARE | X1
40 | XCVRC Mot 7+ | SPARE | X1

RS-232 Serial Connectors (COM)

J7: COM 2
9-pin M D-Sub
Pin | Port 2 (COM 2)
1 | CD2
2 | RXD2
3 | TXD2
4 | DTR2
5 | GND2
6 | DSR2
7 | RTS2
8 | CTS2
9 | RIN2

J8: COM 1/Console
9-pin M D-Sub
Pin | Signal
1 | CD1
2 | RXD1
3 | TXD1
4 | DTR1
5 | GND1
6 | DSR1
7 | RTS1
8 | CTS1
9 | RIN1

J9: COM 1-4
15-pin F High-denisty D-Sub
Pin | Port 4 (COM 1-4)
1 | GND1
2 | RXD1
3 | GND2
4 | RXD2
5 | GND3
6 | RXD3
7 | TXD4
8 | GND4
9 | TXD1
10 | GND5
11 | TXD2
12 | GND6
13 | TXD3
14 | GND7
15 | RXD4

Ethernet Connector

J10: RJ-45 Ethernet Connector
Pin | Signal
1 | TD+
2 | TD-
3 | RD+
4 |
5 |
6 | RD-
7 |
8 |

Power Connector

J11: Power Connector
Pin | Signal
1 | +24 VDC
2 | 24 VDC Common


ASPWorldOnline.com License Agreement

User License Agreement
You must read through this agreement and agree to its terms. If you do not agree to the terms of this agreement, do not download or install the software.

Please read this agreement prior to the download of the software as no refund will be issued for failing to review this agreement.

Terms of Service
The following are the terms and conditions for use of NetLogin developed by ASPWorldOnline.com. BY DOWNLOADING AND INSTALLING NETLOGIN, YOU ARE AGREEING TO BE BOUND BY THE TERMS OF THIS USER AGREEMENT.

User Agreement
  1. General Copyright.
    NetLogin is the proprietary copyrighted material of ASPWorldOnline.com and use of the software is subject to the terms and conditions set forth herein. Except as expressly provided herein, ASPWorldOnline.com and its suppliers do not grant any express or implied right under any patents, copyrights, trademarks, or trade secret information of ASPWorldOnline.com or its suppliers. Any reproduction, distribution, transmission, or publication of NetLogin or its underlying code is expressly prohibited and may result in civil and criminal penalties. Violators will be prosecuted to the maximum extend under law.
  2. User Requirements.
    All users of NetLogin are not to change any copyright notices listed on any of the product pages.
  3. Deployment.
    Users may modify the code to make NetLogin fit into their site or to add functionality, but cannot, under any circumstance, re-distribute any part of the code. Additionally, users must leave the copyright information intact in each of the source files, and cannot use any of the software code in other projects without the prior written consent of ASPWorldOnline.com.
  4. Licensing.
    You must purchase a license in order to use any software products from ASPWorldOnline.com. This license allows for the deployment of NetLogin on a single web site on a single web server. It does not allow for deployment on multiple web servers. If multiple servers are required, please contact ASPWorldOnline.com for licensing arrangements. This license requires you to maintain the copyright information listed on the bottom of each of the product pages.
  5. Warranties.
    NetLogin is provided "as is" without any express or implied warranties. ASPWorldOnline.com hereby disclaims all warranties and conditions with regard to the software, including all implied warranties and conditions of merchantability, fitness for a particular purpose, title and non-infringement. In no event shall ASPWorldOnline.com or its suppliers be liable for any special, indirect, or consequential damages or any damages whatsoever resulting from any procurement of substitute goods or services, any business interruption, or any loss of use, data, or profits, whether in any action of contract, negligence, or other tortuous action arising out of or in connection with the use or performance of NetLogin provided by ASPWorldOnline.com even if ASPWorldOnline.com is advised of the possibility of such damage. ASPWorldOnline.com may make improvements and/or other changes to NetLogin at any time without notice.
  6. Possible Changes.
    ASPWorldOnline.com reserves the right to terminate a user's right to use NetLogin at any time, with or without cause. ASPWorldOnline.com also reserves the right to modify this User Agreement at any time, and users who download NetLogin specifically agree to be bound by such changes, whether or not they receive actual notice of such changes. Accordingly, we urge you to visit ASPWorldOnline.com web site periodically to review the current and effective terms and conditions for the use of NetLogin.
  7. Responsibility.
    User agrees that ASPWorldOnline.com will not be held responsible for any threatening, defamatory, obscene, illegal, or offensive content or conduct of any other party or any infringement of another's rights, including intellectual property rights. User agrees that ASPWorldOnline.com is not responsible for any content procured or sent using NetLogin in any way.
  8. Indemnification.
    Users agree to indemnify and hold harmless ASPWorldOnline.com and it's suppliers, subsidiaries, parent companies, officers, and employees harmless from any claim or demand for damages, including reasonable attorney's fees, asserted by any third party due to or arising out of the user's use of NetLogin.
  9. Governing Law.
    This agreement is governed by the laws of the province of Ontario in the country of Canada. Those who download NetLogin in other countries do so at their own risk and are responsible for compliance with local law. Users cannot use or export NetLogin if in violation of Canadian export laws and regulations.
  10. No Joint Venture.
    User agrees that no joint venture, partnership, employment, or agency relationship exists between the user and ASPWorldOnline.com as a result of this agreement or the use NetLogin. If any part of this agreement is determined to be invalid or unenforceable pursuant to applicable law, it shall not affect the validity of the entire agreement. Additionally, such invalid provision shall be deemed superseded by a valid, enforceable provision and the remainder of the agreement shall continue in effect. Unless other specified herein, this agreement represents the entire agreement between the user and ASPWorldOnline.com related to NetLogin and supersedes any and all prior or contemporaneous communications between the user and ASPWorldOnline.com.
  11. No Waiver of Rights.
    No delay or failure to take action represents a waiver of the rights inherent to ASPWorldOnline.com.
  12. Restricted Governmental Rights.
    If NetLogin is download for or on behalf of the Government of Canada, its agencies, and/or instrumentalities, it is provided with limited rights.

Any and all rights not expressly granted herein are reserved.

ASPWorldOnline.com
289 King's Hwy
Eldee, Ontario, Canada
P0H 2J0
Email: license@aspworldonline.com
Phone: 705-476-5092

Copyright (c) 2001 ASPWorldOnline.com All Rights Reserved


NetLogin Installation Guide

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
Installation Guide
This installation guide should assist you in getting NetLogin installed and operating on your system. If you are a Microsoft FrontPage user, then the installation process is even easier as FrontPage does half the work for you. Click here if you are using FrontPage.
System Requirements
  • Windows 95/98 or Windows NT4.0 / 2000
  • Internet Information Server 4.0 +
  • Active Server Pages
  • ODBC Drivers / Data Source Names
Specific Requirements
  • External SMTP Component

To enable email notifications, you will one of the following FREE external SMTP components:

Dimac JMail - http://www.dimac.net
Persits ASPEmail - http://www.aspemail.com

  • External Encryption Component

To provide encryption, you will need the following external encryption component:

Persits ASPEncrypt - http://www.aspencrypt.com
Getting Started
  • Unzip the contents of this distribution into a subdirectory off the root of your web folder.
    (e.g. c:\inetpub\wwwroot\netlogin).
    When unzipping the file with WinZip, make sure to check "Use Folder Names" as the product comes with files and folders that are inter-related.
  • Unzip the contents of the database into a subdirectory outside of the root directory of your web. You may place the database anywhere you wish, but security can be an issue.
    (e.g. c:\inetpub\database\netlogin).
    Make sure that the database resides in a subdirectory that has "read/write" permissions.
  • Create an ODBC System Data Source Name with the following parameters:
    Driver: Microsoft Access Drivers
    DSN Name: netlogin-db
    Directory: c:\inetpub\database\netlogin
  • You will need to edit the [ config.asp ] file located in the 'include' directory. For a description of each of the variables, please see the configuration reference file. Click here to view the configuration reference file. Once you have completed the configuration, proceed to the online administration [ www.yoursite.com/netlogin/admin ] to complete the system setup.

**The default email / password is: netlogin@aspworldonline.com / admin

  • You might want to customize the documents listed below. You may use features located in Microsoft FrontPage, such as Shared Borders or Themes.
    - login.asp
    - userinfo.asp
    - viewmessage.asp
    - register.asp
    - recovery.asp
Using NetLogin
ASP Includes must be the very first line on the webpage, above all HTML tags. Only one (1) include statement is required to secure any page within your web. The web page that needs to be protected must have the '.asp' extension even if it contains strictly HTML.

To secure your web pages from the root directory
e.g. http://www.yourcompany.com/customeracct.asp

You would use this include statement:
<!-- #include virtual="/netlogin/secure.asp" -->
We hope that these installation instructions will help you understand the workings of NetLogin as well as facilitate with the configuration and initial setup. You may also want to take a look at our FAQ for some technical details.
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin Configuration Reference

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
"config.asp" Reference Guide
This reference guide should assist you in getting NetLogin configured properly and operating on your system. Each configurable variable (option) listed in "config.asp" is explained below with an example.
g_PathToRoot
This variable is used to tell NetLogin your website URL. Any time a redirection needs to take place, NetLogin uses this information to construct an URL for the user. Example: g_PathToRoot = "http://www.aspworldonline.com"

g_NetLoginDir
This variable tells NetLogin where it is installed. You should not have to change this variable, however, if you install the product in a directory other than the default, you will need to specify the directory here. The directory needs to be inside of your website and you do not need to specify the "/". Example: g_NetLoginDir = "netlogin"

g_NetLoginDSN
This variable tells NetLogin how to connect to the database. In the "config.asp" file, you will find a number of options although only 1 is uncommented (active). There are several ways of connecting to the database.

If you have a FrontPage enabled website, then we recommend that you let FrontPage configure your database connection. However, you will still need to specify the connection in this variable. A typical FrontPage database connection looks like this:
g_NetLoginDSN = Application("netlogin_ConnectionString") - The connection string is the database name that you specified when FrontPage asked you during the database installation.

If you do not have a FrontPage enabled website, we recommend that you copy the database file outside of your website and configure an ODBC System Data Source Name. If your website is being hosted externally, contact your host to create the data source name. Once the data source name has been created, you will need to specify the newly created name in the variable.
Example: g_NetLoginDSN = "netlogin-db"

Alternatively, you can create a dsn-less connection. Although not as secure as a system data source name, you would copy the database to a directory of your choice and specify the parameters to the variable. For example, let's assume you copied the database to a "database" directory inside your website.
Example: g_NetLoginDSN = "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=d:\webs\database\netlogin.mdb;DriverId=25;FIL=MS Access;MaxBufferSize=512;PageTimeout=5"

g_NetLoginSupport
This variable tells NetLogin which email to display in the event that an error occurs in the application. The user will be notified that an error occured and that they should contact support. This would be the email address of your support centre.
Example: g_NetLoginEmail = "support@aspworldonline.com"

***** Versions prior to 2.0.0 *****

g_SMTPServer
This variable tells NetLogin which SMTP mail server to use when sending email notifications. The value of this variable can be in the form of an IP address (127.0.0.1) or a valid domain name. Example: "aspworldonline.com"

g_NetLoginLog
This variable tells NetLogin to log different events to a file. If a user attempts to log in using an inactive account, the event can be logged. If you enable the file logging, you need to specify the file in the next variable or the application will throw up an error. Example: g_NetLoginLog = TRUE -> enabled, g_NetLoginLog = FALSE -> disabled

g_NetLoginLogFile
This variable tells NetLogin which file and location to use when logging events. The directory and file must have read/write permissions or you will receive an "Access Denied" error. Additionally, the file and directory must be located within the website.
Example: g_NetLoginLogFile = "/logs/session.txt"

g_Encryption
This variable tells NetLogin that you want the passwords to be encrypted prior to saving in the database. The password encryption is non-recoverable. They are encrypted using a technology called one-way hash. In order to enable this feature, you will need to purchase and install an external product called ASPEncrypt available at http://www.aspencrypt.com. If you enable this feature without ASPEncrypt configured, the application will throw up an error.
Example: g_Encryption = TRUE -> enabled, g_Encryption = FALSE -> disabled

g_NetLoginPageSize
This variable tells NetLogin how many records to display at a time in the administration section. Under normal circumstances, you probably won't need to change this. Example: g_NetLoginPageSize = 15

g_SSLCert
This variable is used to tell NetLogin that your website is configured with an SSL certificate. If you have the variable enabled, NetLogin will use a secure connection any time sensitive data is being transmitted. i.e. Login and Account Changes.
Example: g_SSLCert = TRUE -> SSL enabled, g_SSLCert = FALSE -> SSL disabled
The other variables that are listed under the "NetLogin Definitions" should not be altered. Doing so, you will not be covered for support.
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin FAQ

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
Frequently Asked Questions
This FAQ should help you get a working knowledge of the features of NetLogin. We have compiled a list of most asked questions regarding the features and structure of NetLogin.
  1. I'm looking at your "config.asp" file and I'm not sure what everything means. What do I need to change in the file?
  2. How do I change the email handler? The default is JMail, but I would like to use ASPEmail or CDONTs.
  3. I have some web pages that need to be secured based on the security level. How do I do that?
  4. How do I change the default country code in the registration form?
  5. Session Variables - NetLogin stores information about the user in the session. How do I access them for use in my pages.
We hope that this FAQ will help you make the most of NetLogin. If you do not see a topic here that perhaps should be added, please feel free to contact us.
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin Installation Guide

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
FrontPage Installation Guide
This installation guide should assist you in getting NetLogin installed and operating on your system.
System Requirements
  • Windows 95/98 or Windows NT4.0 / 2000
  • Internet Information Server 4.0 or above
  • Active Server Pages
  • ODBC Drivers / Data Source Names
Specific Requirements
  • External SMTP Component

To enable email notifications, you will one of the following FREE external SMTP components:

Dimac JMail - http://www.dimac.net
Persits ASPEmail - http://www.aspemail.com

  • External Encryption Component

To provide encryption, you will need the following external encryption component:

Persits ASPEncrypt - http://www.aspencrypt.com
Getting Started
  • Unzip the contents of this distribution into a subdirectory off the root of your web folder.
    (e.g. c:\inetpub\wwwroot\netlogin).
    When unzipping the file with WinZip, make sure to check "Use Folder Names" as the product comes with files and folders that are inter-related.
  • Unzip the contents of the database into a temporary directory of your choice, this should not be your web. Right-click on the appropriate database file and select Copy. Open your FrontPage web and go to the Folder list. Right-Click on the root of your web and select Paste.
  • FrontPage will copy the file and present you with a dialog box similar to the following:

    The default database name will be "database1". Enter netlogin as the database name.
  • You will now be presented with the following the dialog box:

    Click on Yes. Your database will not be available to the browser. That should be it for the database connection.
  • You will need to modify config.asp that is located in the include directory. For a description of each of the variables, please see the configuration reference file. Click here to view the configuration reference file. Once you have completed the configuration, proceed to the online administration [ www.yoursite.com/netlogin/admin ] to complete the system setup.

    **The default email / password is: netlogin@aspworldonline.com / admin
  • You might want to customize the documents listed below. You may use features located in Microsoft FrontPage, such as Shared Borders or Themes.
    - login.asp
    - userinfo.asp
    - viewmessage.asp
    - register.asp
    - recovery.asp
Using NetLogin
ASP Includes must be the very first line on the web page, above all HTML tags. Only one (1) include statement is required to secure any page within your web. The web page that needs to be protected must have the '.asp' extension even if it contains strictly HTML.

To secure your web pages from the root directory
e.g. http://www.yourcompany.com/customeracct.asp

You would use this include statement:
<!-- #include virtual="/netlogin/secure.asp" -->
We hope that these installation instructions will help you understand the workings of NetLogin as well as facilitate with the configuration and initial setup. You may also want to take a look at our FAQ for some technical details.
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin Reference Guide

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
Frequently Asked Questions
Default Country Code
The country code on the registration form defaults to Canada. If you would like to change the default to another country, you will need to make sure the country code exists in the database. It is listed in the "country" table within the database.

To change the default country code:
  1. Open "register.asp" in your editor. This file can be in the root directory.
  2. Look for "'-- Default the variables" in the top portion of the page.
  3. Change:
    sCountry = "ca"

    To:
    sCountry = "us" '(for United States)
  4. Save and exit your editor.
Return to FAQ
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin Reference Guide

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
Frequently Asked Questions
Default Email Hander
NetLogin has the ability to use more than one type of mail handler. However, you can only use one type at a time. If you want to change the default mail handler follow these simple steps:
  1. Open "/include/messages.asp" in your editor.
  2. Change <!-- #include file="jmail.asp"--> to the mail handler that you want to use.

    for example: <!-- #include file="cdonts.asp"-->
  3. Save and exit your editor.
You have the option of using any of the following handlers: jmail.asp, aspemail.asp, cdonts.asp
Return to FAQ
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


NetLogin Reference Guide

Copyright (c) 2001 ASPWorldOnline.com
         Thank you for purchasing NetLogin!
Frequently Asked Questions
Custom Security Levels
NetLogin allows you to use custom security levels to be used in your individual web pages. One of the parameters that NetLogin stores in the session is the security level.

You can access the user's security level using this snippet of ASP code:
<!-- #include virtual="/netlogin/secure.asp"-->
<%
Dim iSecLevel 'as integer

iSecLevel = Session("seclevel")
....
your actions
....
%>
<html>
<head>
<title>My ASP Page</title>
.........
</head>

Alternatively, you can set a parameter in your ASP page that will use the default access denied error page built into NetLogin. You can customize the access denied error page anyway you wish.
<%
g_PageLevelSec = TRUE
iPageLevelSec = 5 'minimum required security level
%>
<!-- #include virtual="/netlogin/secure.asp"-->
<%
....
your asp code
....
%>
<html>
<head>
<title>My ASP Page</title>
.........
</head>

The session is populated with a number of user variables. To see the complete list of session variables, click here.
Return to FAQ
For additional support, please visit our Technical Support Center at http://www.aspworldonline.com/support.
Credit Acknowledgments
Beth Abernathy - Integrated Resource Management (tm)
Thomas Rowe - Ecom-Data Solutions


This is a copy of the software documentation
of (\\Leo\WebSite\MEI PUBLIC\support\Software-MPI\docs) that is identified as "Technical Support 2" in Dreamweaver as it existed on 3-25-03.

This directory will be used to update the Sofware documentation prior to the Production Release, which is scheduled to ship at the end of April 2003.  This working directory is identified as "New Software" in Dreamweaver.

--------------
WARNING!!!
Before overwriting the files on the Support directory, create a .chm version of the documentation as an archive of the latest 20021212 documentation.
--------------

When the documentation has been updated, these files should be copied over to the Support directory and overwrite the existing files. This will ensure that the software documentation coincides with the new PR.  DO NOT overwrite the existing files until the PR has been released. This is directory is to be used solely as a working directory.

-Dean Onishi
 (3-25-03)

MEI's Technical Writer


##################################################################################################
# This file contains the javascript code that you will need to place in all html files that you  #
# want the hits to counted. Depending on the install directory and where you are placing this    #
# code you may need to change the path to your count.asp file, currently this is stats.count.asp #
# this will only work in directories one level up from your stats directory. Use a relative path #
# e.g. ../stats/count.asp for files in sub directories of the stats folder                       #
##################################################################################################

Version: 0.3.0 Beta (Last Update: 16 June 2002)

Revision History
--------------------------------------------------------------------------
16 June 2002 - fixed bug concerning referer
--------------------------------------------------------------------------

--------------------------------------------------------------------------
CUT AND PASTE ALL CODE BELOW THIS LINE INTO THE BODY OF YOUR HTML DOCUMENT
--------------------------------------------------------------------------
<script>
/*
Log Hit
*/
document.write('<img src="stats/count.asp?client='+navigator.appName+'&version='+navigator.appVersion+'&width='+screen.width+'&height='+screen.height+'&color_depth='+screen.colorDepth+'&referrer='+escape(document.referrer)+'&url='+escape(document.URL)+'" />')
</script>


To install the program follow the simple steps below:

Step 1 - Open the .zip file you downloaded and extract all files to a directory on your hard drive, we recommend /stats/.

Step 2 - Go to the directory you extracted the files to and open config.asp using a text editor (notepad is fine).

Step 3 - Enter the URL of the image you want to display to show users that their hit has been counted. fsStats ships with a 1*1px transparent gif file which hides the hit counter from users. This can be found in the images sub directory (hitcounted.gif). Note: a actual or relative URL can be used.

Step 4 - Enter the connection string you will be using. All you will probably have to change is the path to your the database file (log.mdb). The database can be left in the same directory as the rest of the hit counting files, although you may want to place it elsewhere for securty reasons.

Step 5 - Upload all files and folders in the /stats/ directory (or the directory you extracted to) to your webserver. Also upload the database file, the location you upload this to will depend on your connection string.

Step 6 - Add the contents of count_code.txt to any html based file you want the hits to counted. You may need to change the URL of the image in the javascript depending on the location of the file you are adding the hit counter to, see count_code.txt for more details.

Step 7 - Give yourself a couple of hits and then test the hit counter by going to stats/default.asp and see if it works! Further help can be found via our forums (http://www.fswebdesign.com/fsstats/forum/).


MEI Tech-Support

Error: - Your request could not be submitted.
Motion Engineering © 2001


MEI's Tech Email

.

E-mail:

First Name:

Last Name:

Company:

Project:

Telephone: - -

Question:


MEI Tech-Support

* E-mail:
{EMAIL_ERROR}
First Name:

* Last Name:
{LASTNAME_ERROR}
Company:

* Project:
{PROJECT_ERROR}
* Telephone:
{TELEPHONE_ERROR}
* Question:
{QUESTION_ERROR}
*Required Fields


MEI Tech-Support

Your request has been submitted successfully.
Motion Engineering © 2001