//////////////////////////////////////////////////////////////////
//
// Header file for the Planar Motor Controller C++ library
// Version Number: 06.03.048.00
// Release Date: 27/11/2025 (DD/MM/YYYY)
// Change Log: - Override mode, zone speed and zone accel added to Zone_GetStatusEx
//             - Added PMC_MoverID_RegisterIDs
//             - Prefix for AppDesign commands shortened to App
//             - StationIDs for App commands are now 2 bytes long
//             - App_SendXbotToStation split into App_SendXbotToStation and App_SendXbotToStationSpeed
//             - GetFlywayTemp renamed to GetFlywayStatus (old name still present, but deprecated) 
//
//////////////////////////////////////////////////////////////////

#pragma once

#include "PMC_Enums.h"
#include "PMC_Structs.h"
#include <mutex>
#include <condition_variable>
#include <cstring>
#include <cmath>

using namespace std;

namespace PMC
{
    struct PMCDBType
    {
        PMC_USINT XbotStateFieldbusRaw[200];
		PMC_USINT StereoID[127];
		PMC_USINT XbotStatus[127];
		PMC_BOOL XIDScan[127];
		PMC_REAL PosX[127];
		PMC_REAL PosY[127];
		PMC_REAL PosZ[127];
		PMC_REAL PosRx[127];
		PMC_REAL PosRy[127];
		PMC_REAL PosRz[127];
		PMC_REAL FeedbackX[127];
		PMC_REAL FeedbackY[127];
		PMC_REAL FeedbackZ[127];
		PMC_REAL FeedbackRx[127];
		PMC_REAL FeedbackRy[127];
		PMC_REAL FeedbackRz[127];
		PMC_USINT FeedbackXID[127];
        PMC_REAL ForceX[127];
        PMC_REAL ForceY[127];
        PMC_REAL ForceZ[127];
        PMC_REAL ForceRx[127];
        PMC_REAL ForceRy[127];
        PMC_REAL ForceRz[127];
		PMC_ULINT PresentTime_ns[127];
		PMC_REAL PastX[127];
		PMC_REAL PastY[127];
		PMC_REAL PastRz[127];
		PMC_ULINT PastTime_ns[127];
    };

    class PMC_Cpp_API
    {
    private:
        PMC_BYTE* DataFromPMC;
        PMC_BYTE* DataToPMC;
        PMC_UINT PMC_Index;

        PMC_BOOL PMC_found;
        mutex fieldbus_mutex;
        condition_variable cmd_cv;
        mutex cmd_cv_mutex;
        PMC_BOOL cmd_active;
        PMCDBType PMCDB;
        PMC_BYTE ConfiguredFeedbackStreamAxis;
        FEEDBACKTYPECONFIGURED ConfiguredFeedbackType;
        void ClearCmdInputArea(void);
    public:
        PMC_Cpp_API(void);
        ~PMC_Cpp_API(void);
		
        /// @brief Connects to PMC. Must be called before using PMC commands.
		/// @param DataComingFromPMC Pointer to data coming from the PMC
		/// @param DataGoingToPMC Pointer to data going to the PMC
		void ConnectToPMC(PMC_BYTE* DataComingFromPMC,PMC_BYTE* DataGoingToPMC);		
		/// @brief Disconnects from PMC. Should be called once finished using PMC commands
		/// @param  
		/// @return 
		void DisconnectFromPMC(void);

        /// @brief Background work for PMC communication, should be called once and only once per fieldbus cycle.
        /// @param  
        /// @return 
        void AutoRefresh(void);
        /// @brief Measures the 1 ms full duplex throughput of the fieldbus (takes 3-4 ms to finish)
        /// @return 
        ThroughputTestRtn ThroughputTest();
        /// @brief Move single xbot in 6 degrees of freedom (fixed velocity)
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0)
        /// @param PosX X position in meters
        /// @param PosY Y position in meters
        /// @param PosZ Z position in meters
        /// @param PosRx rotation about the X axis in radians
        /// @param PosRy rotation about the Y axis in radians
        /// @param PosRz rotation about the Z axis in radians
        /// @return 
        MotionRtn SixDMotion(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL PosZ, PMC_REAL PosRx, PMC_REAL PosRy, PMC_REAL PosRz);
        /// @brief Move single xbot in 6 degrees of freedom (user set velocity)
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0)
        /// @param PosX x position in meters
        /// @param PosY y position in meters
        /// @param PosZ z position in meters
        /// @param PosRx rx position in radians
        /// @param PosRy ry position in radians
        /// @param PosRz rz position in radians
        /// @param LongAxisAcc The long axis acc in m/s^2
        /// @param LongAxisVel The long axis vel in m/s
        /// @param ZVel The z vel in m/s
        /// @param RxVel The rx vel in radian/s
        /// @param RyVel The ry vel in radian/s
        /// @param RzVel The rz vel in radian/s
        /// @return 
        MotionRtn SixDMotionVelocity(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL PosZ, PMC_REAL PosRx, PMC_REAL PosRy, PMC_REAL PosRz, PMC_REAL LongAxisAcc, PMC_REAL LongAxisVel, PMC_REAL ZVel, PMC_REAL RxVel, PMC_REAL RyVel, PMC_REAL RzVel);
        /// @brief Move single xbot in 6 degrees of freedom (user set velocity)(based on previously uploaded compensation data)
        /// @param cmdLB label to be associated with this command in the PMC(0-65535)
        /// @param XbotID ID# of the xbot to move (1-255)
        /// @param PosX x position in meters
        /// @param PosY y position in meters
        /// @param PosZ z position in meters
        /// @param PosRx rx position in radians
        /// @param PosRy ry position in radians
        /// @param PosRz rz position in radians
        /// @param LongAxisAcc The long axis acc in m/s^2
        /// @param LongAxisVel The long axis vel in m/s
        /// @param ZVel The z vel in m/s
        /// @param RxVel The rx vel in radian/s
        /// @param RyVel The ry vel in radian/s
        /// @param RzVel The rz vel in radian/s
        /// @return 
        MotionRtn SixDMotionVelocity_Comp(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL PosZ, PMC_REAL PosRx, PMC_REAL PosRy, PMC_REAL PosRz, PMC_REAL LongAxisAcc, PMC_REAL LongAxisVel, PMC_REAL ZVel, PMC_REAL RxVel, PMC_REAL RyVel, PMC_REAL RzVel);
        /// @brief Command 1 - 12 xbots to follow trajectories
        /// @param cmdLB The command label (0-65535)
        /// @param nXbots number of xbots commanded to follow trajectories (up to 12)
        /// @param XbotID pointer to array of ID#s of xbots to follow trajectories
        /// @param TrajID pointer to array of ID#s of the trajectories that the xbots are to follow
        /// @return 
        MotionRtn ActivateTrajectory(PMC_UINT cmdLB, PMC_USINT nXbots, PMC_USINT* XbotID, PMC_USINT* TrajID);
        /// @brief Command single xbot to follow a circular arc defined by arc center and arc angle
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (1-255)
        /// @param Mode 0:absolute;1: relative
        /// @param Dir 0:clockwise;1:counter-clockwise
        /// @param EndVel Velocity at the end of the motion in meters/second
        /// @param MaxVel Maximum velocity for this motion in meters/second
        /// @param MaxAcc Maximum acceleration for this motion in meters/second^2
        /// @param CenterX X location of the arc center in meters
        /// @param CenterY Y location of the arc center in meters
        /// @param Angle Arc angle in radians
        /// @return 
        MotionRtn ArcMotionCenter(PMC_UINT cmdLB, PMC_USINT XbotID, POSITIONMODE Mode, ARCDIRECTION Dir, PMC_REAL EndVel, PMC_REAL MaxVel, PMC_REAL MaxAcc, PMC_REAL CenterX, PMC_REAL CenterY, PMC_REAL Angle);	
        /// @brief Command single xbots to follow a circular arc defined by target position and arc radius
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (1-255)
        /// @param Mode 0:absolute;1: relative
        /// @param AType 0: Minor Arc;1: Major Arc
        /// @param Dir 0:clockwise;1:counter-clockwise
        /// @param EndVel Velocity at the end of the motion in meters/second
        /// @param MaxVel Maximum velocity for this motion in meters/second
        /// @param MaxAcc Maximum acceleration for this motion in meters/second^2
        /// @param PosX X target position in meters
        /// @param PosY Y target position in meters
        /// @param Radius Arc radius in meters
        /// @return 
        MotionRtn ArcMotionTarget(PMC_UINT cmdLB, PMC_USINT XbotID, POSITIONMODE Mode, ARCTYPE AType, ARCDIRECTION Dir, PMC_REAL EndVel, PMC_REAL MaxVel, PMC_REAL MaxAcc, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL Radius);
        /// @brief Activate all Xbots
        /// @param IDMode 0: full auto, 1: activate to Landed state, 2: activate to Discover mode, 3: exit Discover mode
        /// @return 
        PMCRTN ActivateXbots(PMC_USINT IDMode);
        /// @brief Command multiple xbots (1-127) to nearest rail (user set velocity and acceleration). Pathing is determined by PMC
        /// @param nXbots number of xbots to move (up to 127)	
        /// @param XbotID ID#s of xbots to move
        /// @param MaxVel Maximum velocity of the xbots during the command (m/s)
        /// @param MaxAcc Maximum acceleration of the xbots during the command (m/s^2)
        /// @return 
        PMCRTN App_AutoDriveToRail(PMC_USINT nXbots,PMC_USINT* XbotID,PMC_REAL MaxVel,PMC_REAL MaxAcc);
        /// @brief Gets all the xbots in all the stations
        /// @param StateFilterCount number xbot states to filter for
        /// @param XbotStateFilters xbot states to filter for
        /// @return 
        App_GetAllStationXbotsRtn App_GetAllStationXbots(PMC_USINT StateFilterCount,PMC_USINT* XbotStateFilters);
        /// @brief Gets all the xbots in any state in all the stations
        /// @return 
        App_GetAllStationXbotsRtn App_GetAnyStationXbots();
        /// @brief gets the ID of a xbot in any state in a station's bay
        /// @param StationID Station ID (>0)
        /// @param BayID Bay ID (>0)
        /// @return 
        App_GetBayXbotIDRtn App_GetBayAnyXbot(PMC_UINT StationID,PMC_USINT BayID);
        /// @brief gets the ID of an idle xbot in a station's bay
        /// @param StationID Station ID (>0)
        /// @param BayID Bay ID (>0)
        /// @return 
        App_GetBayXbotIDRtn App_GetBayIdleXbot(PMC_UINT StationID,PMC_USINT BayID);
        /// @brief gets the ID of the xbot in a station's bay
        /// @param StationID Station ID (>0)
        /// @param BayID Bay ID (>0)
        /// @param StateFilterCount number xbot states to filter for
        /// @param XbotStateFilters xbot states to filter for
        /// @return 
        App_GetBayXbotIDRtn App_GetBayXbotID(PMC_UINT StationID,PMC_USINT BayID,PMC_USINT StateFilterCount,PMC_USINT* XbotStateFilters);
        /// @brief reads an application designer file (as a raw binary) from the PMC
        /// @param DesignID design ID to read
        /// @return 
        App_GetDesignRtn App_GetDesign(PMC_USINT DesignID);
        /// @brief Get the IDs of all xbots in any state in a station
        /// @param StationID Station ID (>0)
        /// @return 
        App_GetStationXbotIDsRtn App_GetStationAnyXbot(PMC_UINT StationID);
        /// @brief Get the IDs of all idle xbots in a station
        /// @param StationID Station ID (>0)
        /// @return 
        App_GetStationXbotIDsRtn App_GetStationIdleXbot(PMC_UINT StationID);
        /// @brief Get the IDs of all xbots in a station
        /// @param StationID Station ID (>0)
        /// @param StateFilterCount number xbot states to filter for
        /// @param XbotStateFilters xbot states to filter for
        /// @return 
        App_GetStationXbotIDsRtn App_GetStationXbotIDs(PMC_UINT StationID,PMC_USINT StateFilterCount,PMC_USINT* XbotStateFilters);
        /// @brief Get an xbot's target station
        /// @param XbotID ID of the xbot
        /// @return 
        App_GetXbotTargetRtn App_GetXbotTarget(PMC_USINT XbotID);
        /// @brief Sends an application designer file (as a raw binary) to the PMC
        /// @param nBytes number of bytes in the application designer file (up to 500,000 bytes) 
        /// @param DesignID design ID to save the file under 
        /// @param Bytes the application designer file as a raw binary
        /// @return 
        PMCRTN App_SaveDesign(PMC_DINT nBytes,PMC_USINT DesignID,PMC_BYTE* Bytes);
        /// @brief send an xbot to an application designer station
        /// @param XbotID the xbot to send
        /// @param StationID the station to send the xbot to
        /// @param BayID the station bay to send the xbot to
        /// @param WaitForFreeBay 0: xbot moves to station bay immediately, 1: xbot waits for the station bay to be free before moving
        /// @return 
        PMCRTN App_SendXbotToStation(PMC_USINT XbotID,PMC_UINT StationID,PMC_USINT BayID,PMC_USINT WaitForFreeBay);
        /// @brief send an xbot to an application designer station overriding rail velocity and acceleration
        /// @param XbotID the xbot to send
        /// @param StationID the station to send the xbot to
        /// @param BayID the station bay to send the xbot to
        /// @param WaitForFreeBay 0: xbot moves to station bay immediately, 1: xbot waits for the station bay to be free before moving
        /// @param EndVel override ending velocity in meters/second
        /// @param MaxVel override maximum velocity in meters/second
        /// @param MaxAcc override maximum acceleration in meters/second^2
        /// @return 
        PMCRTN App_SendXbotToStationSpeed(PMC_USINT XbotID,PMC_UINT StationID,PMC_USINT BayID,PMC_USINT WaitForFreeBay,PMC_REAL EndVel,PMC_REAL MaxVel,PMC_REAL MaxAcc);
        /// @brief auto driving motion command, automatically route xbots to their target positions
        /// @param nXbots number of xbots specified in this command, up to 127
        /// @param RoutingType labelled (0) or unlabelled (1) routing
        /// @param OverhangAllowed false: xbots aren't allowed to overhang flyways, true: xbots are allowed to overhang flyways
        /// @param ZoneID 0: system routing; >0: zone based routing (zone must be fenced)
        /// @param XbotID pointer to an array containing the xbot IDs of the xbots specified in this command (ID#s from 1-255)
        /// @param PosX pointer to an array containing the target x positions. (m)
        /// @param PosY pointer to an array containing the target y positions. (m)
        /// @return 
        PMCRTN AutoDrivingMotion(PMC_USINT nXbots, PMC_USINT RoutingType,PMC_BOOL OverhangAllowed, PMC_USINT ZoneID, PMC_USINT* XbotID, PMC_REAL* PosX, PMC_REAL* PosY);
        /// @brief Command multiple xbots (1-78) to target positions (user set velocity and acceleration). Pathing is determined by PMC
        /// @param nXbots number of xbots specified in this command, up to 127
        /// @param RoutingType labelled (0) or unlabelled (1) routing
        /// @param OverhangAllowed false: xbots aren't allowed to overhang flyways, true: xbots are allowed to overhang flyways
        /// @param ZoneID 0: system routing; >0: zone based routing (zone must be fenced)
        /// @param XbotID pointer to an array containing the xbot IDs of the xbots specified in this command (ID#s from 1-255)
        /// @param PosX pointer to an array containing the target x positions. (m)
        /// @param PosY pointer to an array containing the target y positions. (m)
        /// @param MaxVel Maximum velocity of the xbots during the command (m/s)
        /// @param MaxAcc Maximum acceleration of the xbots during the command (m/s^2)
        /// @return 
        PMCRTN AutoDrivingMotionVelocity(PMC_USINT nXbots, PMC_USINT RoutingType,PMC_BOOL OverhangAllowed, PMC_USINT ZoneID, PMC_USINT* XbotID, PMC_REAL* PosX, PMC_REAL* PosY, PMC_REAL MaxVel, PMC_REAL MaxAcc);
        /// @brief activates an autoloading zone
        /// @param ZoneID zone ID: >0 for creation/activation/deactivation; >=0 with delete zone(s) (ID# from 0-255)
        /// @param NextXbotID Xbot ID to be assigned to next received xbot: 0-PMC assigned, >=1-user assigned 
        /// @param NextXbotOrientation Orientation assigned to next received xbot (only user assigned ID)(0-0 deg;1-90 deg;2-180 deg;3-270 deg) 
        /// @return 
        PMCRTN AutoLoadingZone_Activate(PMC_USINT ZoneID,PMC_USINT NextXbotID,PMC_USINT NextXbotOrientation);
        /// @brief Creates a new autoloading zone
        /// @param ZoneID zone ID: (1-255)
        /// @param ZoneMode 0: unloading zone, 1: loading zone
        /// @param UnloadingMode 0: soft-landing mode, 1: hard-landing mode
        /// @param LoadingDirection 0: auto, 1: loading from +X, 2: loading from -X, 3: loading from +Y, 4: loading from -Y 
        /// @param LoadFailResetMode 0: auto reset loading zone, 1: manual reset loading zone
        /// @param ZoneCenterX X coordinate of zone center at flyway boundary (m)
        /// @param ZoneCenterY Y coordinate of zone center at flyway boundary (m)
        /// @param ZoneLength zone length in loading/unloading direction (m)
        /// @param ZoneWidth zone width (m)
        /// @param MaxXbotSizeX max mover size in X (m)
        /// @param MaxXbotSizeY max mover size in Y (m)
        /// @param MaxVel max travelling speed inside the zone (m/s)
        /// @param MaxAcc max travelling acceleration inside the zone (m/s^s)
        /// @param MaxHeight max detection height (m) (0 = no limit)
        /// @return 
        PMCRTN AutoLoadingZone_Create(PMC_USINT ZoneID, ALZONETYPE ZoneMode, ALZONEUNLOADMODE UnloadingMode,PMC_USINT LoadingDirection,PMC_USINT LoadFailResetMode, PMC_REAL ZoneCenterX, PMC_REAL ZoneCenterY, PMC_REAL ZoneLength, PMC_REAL ZoneWidth, PMC_REAL MaxXbotSizeX, PMC_REAL MaxXbotSizeY, PMC_REAL MaxVel, PMC_REAL MaxAcc, PMC_REAL MaxHeight);
        /// @brief Deactivate an autoloading zone
        /// @param ZoneID zone ID: 1-255
        /// @return 
        PMCRTN AutoLoadingZone_Deactivate(PMC_USINT ZoneID);
        /// @brief deletes one or all autoloading zone(s)
        /// @param ZoneID zone ID: 0 - delete all zone, >0 - delete single zone (0-255)
        /// @return 
        PMCRTN AutoLoadingZone_Delete(PMC_USINT ZoneID);
        /// @brief Gets abbreviated status of all autoloading zones
        /// @return 
        AutoLoadZoneAllStatusReturn AutoLoadingZone_GetAllStatus();
        /// @brief Get status of an autoloading zone
        /// @param ZoneID ID of zone that will be released (1-255)
        /// @return 
        AutoLoadZoneStatusReturn AutoLoadingZone_GetZoneStatus(PMC_USINT ZoneID);
        /// @brief Release an autoloading zone exit
        /// @param ZoneID ID of zone that will be released (1-255)
        /// @param NextXbotID Xbot ID to be assigned to next received xbot: 0-PMC assigned, >=1-user assigned
        /// @param NextXbotOrientation Orientation assigned to next received xbot (only user assigned ID)(0-0 deg;1-90 deg;2-180 deg;3-270 deg)
        /// @return 
        PMCRTN AutoLoadingZone_LoadingZoneClear(PMC_USINT ZoneID,PMC_USINT NextXbotID,PMC_USINT NextXbotOrientation);
        /// @brief Sends an xbot to an auto loading zone
        /// @param ZoneID ID of zone that xbot will be sent to (1-255)
        /// @param XbotID ID of xbot to send to zone (1-255)
        /// @return 
        PMCRTN AutoLoadingZone_UnloadXbot(PMC_USINT ZoneID, PMC_USINT XbotID);
        /// @brief Block the motion buffers of the xbots in a group
        /// @param GroupID 0: block all groups; >0: block specific group
        /// @param IsBlock False: unblock the group(s); True: block the group(s)
        /// @return 
        PMCRTN BlockXbotGroup(PMC_USINT GroupID, PMC_BOOL IsBlock);
        /// @brief Bond xbots in a group
        /// @param GroupID 0: bond all groups; >0: bond specific group
        /// @param IsBond False: unbond group(s); True: bond group(s)
        /// @param Mode 0: decouple mode;1: couple mode
        /// @return 
        PMCRTN BondXbotGroup(PMC_USINT GroupID, PMC_BOOL IsBond, PMC_USINT Mode);
        /// @brief Slave the axes of a slave xbot to the axes of one or more master xbots via cams
        /// @param cmdLB label to be associated with this command in the PMC (0-65535)
        /// @param Level 0:Exit from cam mode;1: Enter cam mode
        /// @param SlaveXID ID# of the slave xbot (ID#s 1-255)
        /// @param nAxis number of axes to cam together (up to 7)
        /// @param SlaveAID slave axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param camID ID#s of the cams to use (ID#s 1-255)
        /// @param MasterXID master xbot ID#s (ID#s 1-255)
        /// @param MasterAID master axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @return 
        PMCRTN CamModeCtrl(PMC_UINT cmdLB, PMC_USINT Level, PMC_USINT SlaveXID, PMC_USINT nAxis, PMC_USINT* SlaveAID, PMC_USINT* camID, PMC_USINT* MasterXID, PMC_USINT* MasterAID);
        /// @brief Slave the axes of a slave xbot to the axes of one or more master xbots via cams with more advanced options
        /// @param cmdLB label to be associated with this command in the PMC (1-65535)
        /// @param Level 0:Exit from cam mode;1: Enter cam mode
        /// @param SlaveXID ID# of the slave xbot (1-255)
        /// @param nAxis number of axes to cam together (up to 4)
        /// @param SlaveAID slave axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param camID ID#s of the cams to use (ID#s 1-255)
        /// @param MasterXID master xbot ID#s (ID#s 1-255)
        /// @param MasterAID master axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param MasterAOffset master axis offsets (m)
        /// @param SlaveAOffset slave axis offsets (m)
        /// @param MasterAScaling master axis scaling, positive only
        /// @param SlaveAScaling slave axis scaling, positive only
        /// @param CamMode cam mode; 0: auto start, 1: cyclic, 2: start once
        /// @param MasterOffsetMode 0: absolute, 1: relative
        /// @return 
        PMCRTN CamModeCtrlAdvanced(PMC_UINT cmdLB, PMC_USINT Level, PMC_USINT SlaveXID, PMC_USINT nAxis, PMC_USINT* SlaveAID, PMC_USINT* camID, PMC_USINT* MasterXID, PMC_USINT* MasterAID, PMC_REAL* MasterAOffset, PMC_REAL* SlaveAOffset, PMC_REAL* MasterAScaling, PMC_REAL* SlaveAScaling, PMC_USINT* CamMode, PMC_USINT* MasterOffsetMode);
        /// @brief Slave the axes of a slave xbot to the axes of one or more master xbots via cams
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param Level 0: Begin IN End OUT, 1: End IN Begin OUT, 2: Begin IN Begin OUT, 3: End IN End OUT
        /// @param SlaveXID ID# of the slave xbot
        /// @param nAxis number of axes to cam together (up to 4)
        /// @param SlaveAID slave axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param camID ID#s of the cams to use
        /// @param MasterXID master xbot ID#s
        /// @param MasterAID master axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param MasterAScaling master axis scaling, positive only
        /// @param SlaveAScaling slave axis scaling, positive only
        /// @return 
        PMCRTN CamModeCtrlBufferable(PMC_UINT cmdLB, PMC_USINT Level, PMC_USINT SlaveXID, PMC_USINT nAxis, PMC_USINT* SlaveAID, PMC_USINT* camID, PMC_USINT* MasterXID, PMC_USINT* MasterAID, PMC_REAL* MasterAScaling, PMC_REAL* SlaveAScaling);
        /// @brief clear commands stored in a macro
        /// @param MacroID ID# of the macro to be cleared. Macro IDs are 128 - 191
        /// @return 
        PMCRTN ClearMacro(PMC_USINT MacroID);	
        /// @brief Configure a PMC digital input to start advanced cam motion (rising edge starts cam; falling edge stops cam)
        /// @param DiID digital input ID(1-128)
        /// @param SlaveXID ID# of the slave xbot
        /// @param nAxis number of axes to cam together (up to 4)
        /// @param SlaveAID slave axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param camID ID#s of the cams to use
        /// @param MasterXID master xbot ID#s
        /// @param MasterAID master axes 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param MasterAOffset master axis offsets (m)
        /// @param SlaveAOffset slave axis offsets (m)
        /// @param MasterAScaling master axis scaling, positive only
        /// @param SlaveAScaling slave axis scaling, positive only
        /// @param CamMode cam mode; 0: auto start, 1: cyclic, 2: start once
        /// @param MasterOffsetMode 0: absolute, 1: relative
        /// @return 
        PMCRTN ConfigDI2Cam(PMC_USINT DiID, PMC_USINT SlaveXID, PMC_USINT nAxis, PMC_USINT* SlaveAID, PMC_USINT* camID, PMC_USINT* MasterXID, PMC_USINT* MasterAID, PMC_REAL* MasterAOffset, PMC_REAL* SlaveAOffset, PMC_REAL* MasterAScaling, PMC_REAL* SlaveAScaling, PMC_USINT* CamMode, PMC_USINT* MasterOffsetMode);
        /// @brief Configure PMC digital inputs to quickstop the PMC or a sector
        /// @param nDI number of digital inputs to configure (up to 22)
        /// @param DiID Array of digital input ID to configure
        /// @param SectorID Array of sector ID#s quick stop (0 = entire PMC)
        /// @return 
        PMCRTN ConfigDI2QuickStop(PMC_USINT nDI, PMC_USINT* DiID, PMC_USINT* SectorID);
        /// @brief Configure PMC digital inputs to reset PMC digital outputs
        /// @param nDI number of digital inputs to configure (up to 22)
        /// @param DiID Array of digital input ID to configure
        /// @param RstDoID Array of digital output ID#s to reset
        /// @return 
        PMCRTN ConfigDI2Reset(PMC_USINT nDI, PMC_USINT* DiID, PMC_USINT* RstDoID);
        /// @brief Configure PMC digital inputs to trigger xbots to run macros
        /// @param nDI number of digital inputs to configure (up to 22)
        /// @param DiID Array of digital input ID to configure
        /// @param MacroID Array of macro ID#s to run. Macro IDs are 128 - 191
        /// @param XbotID Array of ID#s to run the macros
        /// @return 
        PMCRTN ConfigDI2RunMacro(PMC_USINT nDI, PMC_USINT* DiID, PMC_USINT* MacroID, PMC_USINT* XbotID);
        /// @brief Configure PMC digital inputs to act as macro triggers
        /// @param nDI Number of digital inputs to configure (up to 22)
        /// @param DiID Array of digital input ID to configure
        /// @return 
        PMCRTN ConfigDI2Trigger(PMC_USINT nDI, PMC_USINT* DiID);
        /// @brief Configure digital outputs to set on command labels
        /// @param nDO number of digital outputs to configure (up to 5)
        /// @param DoID array of digital output ID#s to configure
        /// @param XbotID array of xbot ID#s to monitor for the command labels
        /// @param CmdLb array of command labels to set on
        /// @param Type_ when to set the digital output 0: Cmd Label Start; 1: Cmd Label End; 2: Cmd Label state
        /// @return 
        PMCRTN ConfigDO2CmdLb(PMC_USINT nDO, PMC_USINT* DoID, PMC_USINT* XbotID, PMC_UINT* CmdLb, PMC_USINT* Type_);
        /// @brief Configure digital outputs to set on xbot displacements
        /// @param nDO number of digital outputs to configure (up to 5)
        /// @param DoID array of digital output ID#s to configure
        /// @param XbotID array of xbot ID#s to monitor for displacement
        /// @param Type_ 0: Positive Cross; 1: Negative Cross; 2: State
        /// @param Mode 0: X only; 1: Y only ; 2: XFactor*X + YFactor*Y
        /// @param Threshold Thresholds for output trigger in meters
        /// @param XFactor XFactor used for Mode #2
        /// @param YFactor YFactor used for Mode #2
        /// @return 
        PMCRTN ConfigDO2Disp(PMC_USINT nDO, PMC_USINT* DoID, PMC_USINT* XbotID, PMC_USINT* Type_, PMC_USINT* Mode, PMC_REAL* Threshold, PMC_REAL* XFactor, PMC_REAL* YFactor);
        /// @brief Configure digital outputs to set on xbot force
        /// @param nDO number of digital outputs to configure (up to 5)
        /// @param DoID array of digital output ID#s to configure
        /// @param XbotID array of xbot ID#s to monitor for force
        /// @param Type_ 0: Positive Cross; 1: Negative Cross; 2: State
        /// @param AxisID 1: X axis; 2: Y axis; 3: Z axis; 4: Rx; 5: Ry; 6: Rz;
        /// @param Threshold Thresholds for output trigger in Newtons/Newton*Meters
        /// @return 
        PMCRTN ConfigDO2Force(PMC_USINT nDO, PMC_USINT* DoID, PMC_USINT* XbotID, PMC_USINT* Type_, PMC_USINT* AxisID, PMC_REAL* Threshold);
        /// @brief Configure digital outputs to set on xbot motion
        /// @param nDO Configure digital outputs to set on xbot motion
        /// @param DoID array of digital output ID#s to configure
        /// @param XbotID array of xbot ID#s to monitor for motion
        /// @param Type_ 0: Motion Start; 1: Motion End; 2: Motion state
        /// @return 
        PMCRTN ConfigDO2Motion(PMC_USINT nDO, PMC_USINT* DoID, PMC_USINT* XbotID, PMC_USINT* Type_);
        /// @brief Configure digital outputs to set on number of xbots in a zone
        /// @param nDO number of digital outputs to configure (up to 5)
        /// @param DoID array of digital output ID#s to configure
        /// @param ZoneID array of Zone ID#s to monitor for number of movers in the zone
        /// @param Type_ 0: mover count rising about threshold; 1: mover count falling below threshold; 2: mover count higher than threshold
        /// @param Threshold Thresholds for output trigger in number of movers
        /// @return 
        PMCRTN ConfigDO2Zone(PMC_USINT nDO, PMC_USINT* DoID, PMC_USINT* ZoneID, PMC_USINT* Type_, PMC_USINT* Threshold);
        /// @brief Configure feedback streams for xbots position or force
        /// @param nStm number of feedback streams (up to 8)
        /// @param StmID feedback stream ID
        /// @param XbotID xbot ID# for the stream
        /// @param FBMode 0: position; 1: force; 2: reference position; 3: tracking error
        /// @return 
        PMCRTN ConfigFBStream(PMC_USINT nStm, PMC_USINT* StmID, PMC_USINT* XbotID, PMC_USINT* FBMode);
        /// @brief Configure extended feedback streams for xbots position or force
        /// @param nXbots number of feedback streams (up to 127)
        /// @param XbotID xbot ID# for the stream
        /// @param FBMode 0: position; 1: force; 2: reference position; 3: tracking error
        /// @return 
        PMCRTN ConfigFBStreamExtended(PMC_USINT nXbots, PMC_USINT* XbotID, PMC_USINT* FBMode);
        /// @brief Resets PMCControllerType internal state, DO NOT ACTIVATE WHEN PMC IS RUNNING
        /// @return 
        PMCRTN ControllerReset();
        /// @brief Read the configuration file (as raw binary) from the PMC
        /// @return 
        ConfigRtn GetConfiguration();
        /// @brief Sends a configuration file (as raw binary) to the PMC
        /// @param nBytes number of bytes in the configuration file (up to 500,000 bytes)
        /// @param bytes the configuration file as a raw binary
        /// @return 
        PMCRTN SetConfiguration(PMC_DINT nBytes, PMC_BYTE* bytes);
        /// @brief Create a xbot group
        /// @param GroupID must be greater than 0
        /// @param nXbots number of xbots to be in the group (up to 32)
        /// @param XbotID xbot ID#s to be in the group
        /// @return 
        PMCRTN CreateXbotGroup(PMC_USINT GroupID, PMC_USINT nXbots, PMC_USINT* XbotID);
        /// @brief Deactivate all Xbots
        /// @return 
        PMCRTN DeactivateXbots();
        /// @brief Delete trajectory file
        /// @param TrajID 0: delete all trajectory files; >0: delete specific trajectory file
        /// @return 
        PMCRTN DeleteTrajectory(PMC_USINT TrajID);
        /// @brief delete a xbot group
        /// @param GroupID 0: delete all groups; >0: delete specific group
        /// @return 
        PMCRTN DeleteXbotGroup(PMC_USINT GroupID);
        /// @brief Find all xbots whose centers are within a rectangular area
        /// @param BottomLeftX X coordinate of bottom left corner of area (m)
        /// @param BottomLeftY Y coordinate of bottom left corner of area (m)
        /// @param TopRightX X coordinate of top right corner of area (m)
        /// @param TopRightY Y coordinate of top right corner of area (m)
        /// @return 
        FindXbotsInAreaRtn FindXbotsInArea(PMC_REAL BottomLeftX, PMC_REAL BottomLeftY, PMC_REAL TopRightX, PMC_REAL TopRightY);
        /// @brief activate force mode control on a xbot
        /// @param Mode 0: absolte force mode; 1:relative force mode
        /// @param Level 0: Exit from force mode;1: Z force mode;2: X force mode;3: Y force mode;4: XY force mode;5: Z torque mode;8: X force + Z torque;9: Y force + Z torque
        /// @param Buffer 0: enter/exit force mode immediately; 1:add mode change to motion buffer
        /// @param XbotID xbot ID# of the xbot to activate force mode control
        /// @param ForceX force in X in Newtons
        /// @param ForceY force in Y in Newtons
        /// @param ForceZ force in Z in Newtons
        /// @param TorqueZ torque around the Z axis in Newton Meters
        /// @return 
        PMCRTN ForceModeCtrl(PMC_USINT Mode, PMC_USINT Level, PMC_USINT Buffer, PMC_USINT XbotID, PMC_REAL ForceX, PMC_REAL ForceY, PMC_REAL ForceZ,PMC_REAL TorqueZ);
        /// @brief activate force mode control on a xbot with extended options
        /// @param Mode 0: absolute force mode; 1:relative force mode
        /// @param Level Set which axises have force mode (0-position,1-force): bit0-Fx, bit1-Fy, bit2-Fz, bit3-Tx, bit4-Ty, bit5-Tz
        /// @param Buffer 0: enter/exit force mode immediately; 1:add mode change to motion buffer
        /// @param XbotID xbot ID# of the xbot to activate force mode control
        /// @param ForceX force in X in Newtons
        /// @param ForceY force in Y in Newtons
        /// @param ForceZ force in Z in Newtons
        /// @param TorqueX torque around the X axis in Newton Meters
        /// @param TorqueY torque around the Y axis in Newton Meters
        /// @param TorqueZ torque around the Z axis in Newton Meters
        /// @return 
        PMCRTN ForceModeCtrlEx(PMC_USINT Mode, PMC_USINT Level, PMC_USINT Buffer, PMC_USINT XbotID, PMC_REAL ForceX, PMC_REAL ForceY, PMC_REAL ForceZ, PMC_REAL TorqueX, PMC_REAL TorqueY, PMC_REAL TorqueZ);
        /// @brief Delete G-code file
        /// @param GCodeID 0: delete all G-code files; >0: delete specific G-code file
        /// @return 
        PMCRTN DeleteGCode(PMC_USINT GCodeID);
        /// @brief Get the IDs of all G-code files on the PMC
        /// @return 
        GCodeIDRtn GetGCodeIDs();
        /// @brief Reads a G-code file from the PMC
        /// @param GCodeID ID of GCode file to read
        /// @return PMC return value + G-code file length + pointer to the G-code file as a raw binary stream
        GCodeRtn ReadGCode(PMC_USINT GCodeID);
        /// @brief Run G-code file
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param GCodeID G-code ID# (1-64)
        /// @param XbotID xbot ID# (>0)
        /// @return 
        PMCRTN RunGCode(PMC_UINT cmdLB, PMC_USINT GCodeID, PMC_USINT XbotID);
        /// @brief Send a G-code file to the PMC
        /// @param GCodeID GCode ID# (1-64)
        /// @param nBytes number of bytes in the G-code file (up to 200,000 bytes)
        /// @param bytes the G-code file as a raw binary
        /// @return 
        PMCRTN SaveGCode(PMC_USINT GCodeID, PMC_DINT nBytes, PMC_BYTE* bytes);
        /// @brief Get the location of all accidents in the system
        /// @return 
        GetAllAccidentLocationsRtn GetAllAccidentLocations();
        /// @brief Get the number and IDs of all accident xbots
        /// @return 
        AccidentXbotRtn GetAllAccidentXbots();
        /// @brief Get the status of a border
        /// @param BorderID Border ID (>0)
        /// @return 
        BorderStatusRtn GetBorderStatus(PMC_USINT BorderID);
        /// @brief Get status of a Xbot's motion buffer
        /// @param XbotID Xbot ID# (>0)
        /// @return 
        MotionBufferStatusRtn GetBufferStatus(PMC_USINT XbotID);
        /// @brief Read the PMC's error log
        /// @return 
        LogRtn GetErrorLog();	
        /// @brief Get number of flyway connection errors for each flyway
        /// @return 
        GetFlywayConnectErrorCountsRtn GetFlywayConnectErrorCounts();
        /// @brief Get flyway error code
        /// @param FlywayID Flyway ID# (>0)
        /// @return 
        FlywayErrorRtn GetFlywayError(PMC_USINT FlywayID);
        /// @brief Get the position of a flyway
        /// @param FlywayID Flyway ID# (>0)
        /// @return 
        GetFlywayPositionRtn GetFlywayPosition(PMC_USINT FlywayID);
        /// @brief Reads the serial number of a flyway
        /// @param FlywayID Flyway logical ID (>0)
        /// @return 
        SerialNumRtn GetFlywaySerialNum(PMC_USINT FlywayID);
        /// @brief Get temperatures and power consumption of a flyway
        /// @param FlywayID Flyway ID
        /// @return 
        FlywayTempRtn GetFlywayStatus(PMC_USINT FlywayID);
        /// @brief DEPRECATED (renamed to GetFlywayStatus) Get temperatures and power consumption of a flyway
        /// @param FlwID Flyway ID
        /// @return 
        FlywayTempRtn GetFlywayTemp(PMC_USINT FlwID);
        /// @brief Get status of a xbot group
        /// @param GroupID Group ID >0
        /// @return 
        GroupStatusRtn GetGroupStatus(PMC_USINT GroupID);
        /// @brief Get the number of and IDs of any incoming xbots
        /// @return 
        IncomingXbotsRtn GetIncomingXbots();
        /// @brief Get the number of and IDs of any incoming xbots with extra info
        /// @return 
        IncomingXbotsExRtn GetIncomingXbotsEx();
        /// @brief get status of a macro
        /// @param MacroID Macro ID#
        /// @return 
        MotionMacroReturn GetMacroStatus(PMC_USINT MacroID);
        /// @brief Get payload of a xbot
        /// @param XbotID Xbot ID#
        /// @return 
        PayloadRtn GetPayload(PMC_USINT XbotID);
        /// @brief Get the IDs of planet xbots that are attached to a star xbot
        /// @param StarXbotID xbot ID# (>0)
        /// @return 
        GetPlanetsRtn GetPlanets(PMC_USINT StarXbotID);
        /// @brief Retreive the latest PMC error codes
        /// @return 
        ErrorCodeRtn GetPMCErrorCode();
        /// @brief Reads the serial number of the PMC
        /// @return 
        SerialNumRtn GetPMCSerialNum();
        /// @brief Get status of the Planar Motor Controller
        /// @return 
        PMCStatusRtn GetPmcStatus();
        /// @brief Gets the PMC software version number
        /// @return 
        VersionRtn GetPMCVersion();	
        /// @brief Get the last 100 warning codes from the PMC
        /// @return 
        WarningsReturn GetPMCWarnings();
        /// @brief Get the number of PMNet communication errors for each flyway 
        /// @return 
        GetPMNetErrorCountsRtn GetPMNetErrorCounts();
        /// @brief Get the ID of the sun xbot that a planet xbot is attached to
        /// @param PlanetXbotID planet xbot ID# (>0)
        /// @return 
        GetStarRtn GetStar(PMC_USINT PlanetXbotID);
        /// @brief Get spaced out xbot positions
        /// @return 
        GetSpacedXbotPositionsRtn GetSpacedXbotPositions();
        /// @brief Read the PMC's warning log
        /// @return 
        LogRtn GetWarningLog();
        /// @brief Gets the number of xbots in system and their ID#s (up to 99 xbots)(much slower than ReadXbotIDs)
        /// @return 
        GetXbotIDsRtn GetXbotIDs();
        /// @brief Get properties of a xbot
        /// @param XbotID xbot ID# (>0)
        /// @return 
        XbotPropertyReturn GetXbotProperty(PMC_USINT XbotID);	
        /// @brief Get status of a xbot
        /// @param XbotID xbot ID# (>0)
        /// @param FeedbackType 0: Feedback Position 1: Feedback Force
        /// @return 
        XBotStatusRtn GetXbotStatus(PMC_USINT XbotID, FEEDBACKOPTION FeedbackType);
        /// @brief send a single linear motion to a group of XBots (creates, bonds, and deletes group all in one step)
        /// @param nXbots number of xbots to group and move (up to 32)
        /// @param XbotID xbot ID#s
        /// @param LeaderXbotID xbot to be sent to target position
        /// @param Mode 0: Absolute position. 1: relative positioning
        /// @param Type 0: direct straight line; 1: move in X then Y; 2: move in Y then X
        /// @param PosX X position in meters
        /// @param PosY Y position in meters
        /// @param EndVel ending velocity in meters/second
        /// @param MaxVel maximum velocity in meters/second
        /// @param MaxAcc maximum acceleration in meters/second^2
        /// @param Radius turn radius of corner if Type = 1 or 2
        /// @return 
        MotionRtn GroupXYMotion(PMC_USINT nXbots,PMC_USINT* XbotID,PMC_USINT LeaderXbotID,POSITIONMODE Mode, LINEARPATHTYPE Type,PMC_REAL PosX,PMC_REAL PosY,PMC_REAL EndVel,PMC_REAL MaxVel,PMC_REAL MaxAcc,PMC_REAL Radius);
        /// @brief inject sinusoidal force/torque signals to one or multiple axes of xbot 
        /// @param Mode 0: turn off noise,1: turn on noise
        /// @param XbotID xbot to inject noise (>0)
        /// @param nAxis number of axises to inject noise into
        /// @param AxisIDs axis IDs to inject noise into (1-X; 2-Y; 3-Z; 4-Rx; 5-Ry; 6-Rz)
        /// @param Amplitudes frequencies of sinusoidal signals (Hz,maximum is 655 Hz,precision of 0.01 Hz)
        /// @param Frequencies phases of sinusoidal signals (degrees,precision of 0.01 degs)
        /// @param Phases frequencies of sinusoidal signals (Hz)
        /// @param Durations durations of sinusoidal signals (s)
        /// @return 
        PMCRTN InjectNoise(PMC_USINT Mode, PMC_USINT XbotID, PMC_USINT nAxis, PMC_USINT* AxisIDs, PMC_REAL* Amplitudes, PMC_REAL* Frequencies,PMC_REAL* Phases, PMC_REAL* Durations);
        /// @brief inject sinusoidal force/torque signals with delays to one or multiple axes of xbot 
        /// @param Mode 0: turn off noise,1: turn on noise
        /// @param XbotID xbot to inject noise (>0)
        /// @param nAxis number of axises to inject noise into
        /// @param AxisIDs axis IDs to inject noise into (1-X; 2-Y; 3-Z; 4-Rx; 5-Ry; 6-Rz)
        /// @param Amplitudes amplitudes of sinusoidal signals (N or Nm)
        /// @param Frequencies frequencies of sinusoidal signals (Hz,maximum is 655 Hz,precision of 0.01 Hz)
        /// @param Phases phases of sinusoidal signals (degrees,precision of 0.01 degs)
        /// @param Durations durations of sinusoidal signals (s)
        /// @param Delays delays of sinusoidal signals (s,maximum is 655 sec,precision of 0.01 sec)
        /// @return 
        PMCRTN InjectNoiseDelay(PMC_USINT Mode, PMC_USINT XbotID, PMC_USINT nAxis, PMC_USINT* AxisIDs, PMC_REAL* Amplitudes, PMC_REAL* Frequencies, PMC_REAL* Phases, PMC_REAL* Durations, PMC_REAL* Delays);
        /// @brief jog a xbot in short axises (Z, Rx, Ry, or Rz)
        /// @param XbotID xbot ID# (>0)
        /// @param Enable 0: stop jogging xbot; 1: start jogging xbot
        /// @param AxisID Axis to jog; 0-Z, 1-Rx, 2-Ry, 3-Rz
        /// @param Velocity jogging speed in meters/second or radians/second
        /// @return 
        PMCRTN JogShortAxis(PMC_USINT XbotID, PMC_BOOL Enable, PMC_USINT AxisID, PMC_REAL Velocity);
        /// @brief jog a xbot in x/y plane
        /// @param XbotID xbot ID# (>0)
        /// @param Enable 0: stop jogging xbot; 1: start jogging xbot
        /// @param Direction direction to jog in radians
        /// @param Velocity jogging speed in meters/second
        /// @param Acceleration jogging acceleration in meters/second^2
        /// @return 
        PMCRTN JogVelocity(PMC_USINT XbotID, PMC_BOOL Enable, PMC_REAL Direction, PMC_REAL Velocity,PMC_REAL Acceleration);	
        /// @brief Levitate/Land a xbot
        /// @param XbotID 0: leviate/land all xbots; &gt;0: leviate/land specific xbot
        /// @param Level 0 = landed, 1 = levitate
        /// @param Speed 0 = 1.6s, 1= 0.8s, 2 = 0.4s, 3 = 0.2s, 4 = 0.1s, 5 = 0.05s (all times approximate)
        /// @param LandedZForce Z axis force when the xbot is landed (Newtons)
        /// @return 
        PMCRTN LevitationCtrl(PMC_USINT XbotID, LEVITATEOPTIONS Level, PMC_USINT Speed, PMC_REAL LandedZForce);
        /// @brief Levitate/Land a xbot with control over the speed of the landing/levitation
        /// @param XbotID 0: leviate/land all xbots; >0: leviate/land specific xbot
        /// @param Level 0 = landed, 1 = levitate
        /// @param Speed 0 = 1.6s, 1= 0.8s, 2 = 0.4s, 3 = 0.2s, 4 = 0.1s, 5 = 0.05s (all times approximate)
        /// @return 
        PMCRTN LevitationCtrlSpeed(PMC_USINT XbotID, LEVITATEOPTIONS Level, PMC_USINT Speed);	
        /// @brief Assigns the linkage defined to xbots, and starts up the CAM and sun-planet relationship if possible
        /// @param LinkID ID of the linkage [1, 64]
        /// @param XbotID Xbot IDs of the slaves
        /// @return 
        LinkedMover_AssignRtn LinkedMover_Assign(PMC_USINT LinkID, PMC_USINT* XbotID);
        /// @brief Define masked axis of mover linkage, where multiple movers' motion is combined via a CAM (linked cams only respond to single axis motion) to actuate an mechanical axis
        /// @param LinkID ID of the linkage [1, 64]
        /// @param MasterAxis master axis: 1-X,2-Y,3-Z,4-Rx,5-Ry,6-Rz
        /// @param MasterAxisOffset master axis offset to linkage center(m)
        /// @param NumSlaveAxes number of slave axis (1-8)
        /// @param SlaveID which of the 4 slave xbots to be cammed
        /// @param SlaveAxis slave axes: 1-X,2-Y,3-Z,4-Rx,5-Ry,6-Rz
        /// @param SlaveCamID cams to use
        /// @param SlaveAxisOffset slave axis offsets to link center(m)
        /// @return 
        PMCRTN LinkedMover_CamSlaves(PMC_USINT LinkID, PMC_USINT MasterAxis, PMC_REAL MasterAxisOffset, PMC_USINT NumSlaveAxes, PMC_USINT* SlaveID, PMC_USINT* SlaveAxis, PMC_USINT* SlaveCamID, PMC_REAL* SlaveAxisOffset);
        /// @brief Defines a new mover linkage
        /// @param LinkID ID of the linkage [1, 64]
        /// @param nSlaves number of slave xbots in the linkage
        /// @param SlaveX Default X positions of slaves relative to linkage center(m)
        /// @param SlaveY Default Y positions of slaves relative to linkage center(m)
        /// @return 
        PMCRTN LinkedMover_Define(PMC_USINT LinkID, PMC_USINT nSlaves, PMC_REAL* SlaveX, PMC_REAL* SlaveY);
        /// @brief Control a xbots motion buffer
        /// @param Level 0: Block buffer;1: release buffer;2: clear buffer
        /// @param XbotID 0: control all xbot buffers; >0: control specific xbot buffer
        /// @return 
        PMCRTN MotionBufferCtrl(MOTIONBUFFEROPTIONS Level, PMC_USINT XbotID);
        /// @brief Start absolute ID auto scanning for the entire PMC
        /// @param ZoneID 0-Scan using all available area in system,>0-scan using area defined by zone ID
        /// @return 
        PMCRTN MoverID_AutoScan(PMC_USINT ZoneID);
        /// @brief Change absolute IDs
        /// @param nXbots number of xbots to change absolute IDs (<=127)
        /// @param CurrentIDs current absolute IDs to change
        /// @param NewIDs new absolute IDs to change to
        /// @return 
        PMCRTN MoverID_ChangeAbsoluteIDs(PMC_USINT nXbots, PMC_USINT* CurrentIDs, PMC_USINT* NewIDs);
        /// @brief get the closest scanning location of a xbot
        /// @param XbotID Xbot ID# (>0)
        /// @param Orientation 0-East;1-North;2-West;3-South
        /// @return 
        MoverID_GetScanLocationRtn MoverID_GetScanLocation(PMC_USINT XbotID,PMC_USINT Orientation);
        /// @brief manually scan a single xbot for its absolute ID
        /// @param XbotID Xbot ID# (>0)
        /// @param Orientation 0-East;1-North;2-West;3-South
        /// @return 
        PMCRTN MoverID_ManualScan(PMC_USINT XbotID,PMC_USINT Orientation);
        /// @brief read a xbot's scan status
        /// @param XbotID xbot ID#
        /// @return 
        MoverID_ReadScanStatusRtn MoverID_ReadScanStatus(PMC_USINT XbotID);
        /// @brief recover XID after flyway error
        /// @return 
        PMCRTN MoverID_RecoverID();
        /// @brief Use the known mover ID of xbots to register the configuration's absolute IDs
        /// @param nXbots number of xbots to set (up to 127)
        /// @param XbotIDs ID#s of xbots to set RFIDs
        /// @param MoverType XBot Type (0 = M3-06,2 = M3-08,4 = M3-09X,5 = M3-09Y,6 = M3-10,8 = M3-11X,9 = M3-11Y,12 = M3-12,14 = M3-13)
        /// @param RFID RFIDs
        /// @return 
        PMCRTN MoverID_RegisterIDs(PMC_USINT nXbots,PMC_USINT* XbotIDs,PMC_USINT* MoverType,PMC_ULINT* RFID);
        /// @brief Gets the mover ID of a xbot on a flyway
        /// @param FlywayID logical ID (>0) of the flyway to scan
        /// @return 
        MoverID_ScanMoverIDRtn MoverID_ScanMoverID(PMC_USINT FlywayID);
        /// @brief Use the known mover ID of xbots to set the absolute IDs
        /// @param nXbots number of xbots to set (up to 127)
        /// @param XbotID ID#s of xbots to set absolute IDs
        /// @param RFID RFIDs 
        /// @param Orientation 0-East;1-North;2-West;3-South
        /// @return 
        PMCRTN MoverID_Set(PMC_USINT nXbots,PMC_USINT* XbotID,PMC_ULINT* RFID,PMC_USINT* Orientation);
        /// @brief Get mover label of a xbot
        /// @param XbotID xbot ID# (>0)
        /// @return 
        MoverLabel_GetLabelRtn MoverLabel_GetLabel(PMC_USINT XbotID);
        /// @brief search for a xbot based on mover label
        /// @param MoverLabel mover label to return the ID for
        /// @return 
        MoverLabel_GetXbotIDRtn MoverLabel_GetXbotID(PMC_UINT MoverLabel);
        /// @brief Set a xbot's mover label
        /// @param XbotID Xbot ID to set the label for
        /// @param MoverLabel Number to set the label to
        /// @return 
        PMCRTN MoverLabel_SetLabel(PMC_USINT XbotID,PMC_UINT MoverLabel);
        /// @brief Assign a stereotype to a xbot
        /// @param StereotypeID ID of the mover stereotype. [1, 255]
        /// @param XbotID ID of the XBot to assign to. 0 = all XBots
        /// @param BufferAssign 0: assign stereotype immediately; 1:add stereotype change to motion buffer
        /// @return 
        PMCRTN MoverStereotype_Assign(PMC_USINT StereotypeID, PMC_USINT XbotID, PMC_USINT BufferAssign);
        /// @brief Define a mover stereotype
        /// @param MoverType XBot Type (0 = M3-06,2 = M3-08,4 = M3-09X,5 = M3-09Y,6 = M3-10,8 = M3-11X,9 = M3-11Y,12 = M3-12,14 = M3-13)
        /// @param StereotypeID ID of the mover stereotype. [1, 255]
        /// @param StereotypeDefinition The stereotype definition.
        /// @return 
        PMCRTN MoverStereotype_Define(MOVERTYPE MoverType, PMC_USINT StereotypeID, MoverStereotypeData StereotypeDefinition);	
        /// @brief Read a mover stereotype
        /// @param MoverType XBot Type (0 = M3-06,2 = M3-08,4 = M3-09X,5 = M3-09Y,6 = M3-10,8 = M3-11X,9 = M3-11Y,12 = M3-12,14 = M3-13)
        /// @param StereotypeID ID of the mover stereotype. [1, 255]
        /// @return 
        MoverStereotypeDefinitionReturn MoverStereotype_ReadDef(MOVERTYPE MoverType, PMC_USINT StereotypeID);	
        /// @brief pause xbot motion
        /// @param XbotID 0: all Xbots; >0: specific Xbot
        /// @return 
        PMCRTN PauseXbots(PMC_USINT XbotID);
        /// @brief begin star-planet motion
        /// @param Level 0:disconnect from star xbot;1: connect to star xbot;2: connect to star w/ coupled RZ
        /// @param StarXID xbot ID# of the star xbot
        /// @param nXbots number of planet xbots (up to 32)
        /// @param PlanetXID planet xbot ID#s
        /// @return 
        PMCRTN PlanetMotionCtrl(PLANETOPTIONS Level, PMC_USINT StarXID, PMC_USINT nXbots, PMC_USINT* PlanetXID);
        /// @brief Reads the digital signal from PMC
        /// @param DiID digital input (of the PLC fieldbus) number [1-128]
        /// @return 
        DigitalSignalRtn ReadDigitalSignalFromPMC(PMC_USINT DiID);
        /// @brief Reads the number of accident xbots.
        /// @return 
        ReadNumXbotsRtn ReadNumAccidentXbots();	
        /// @brief read the number of xbots coming from neighbor PMCs
        /// @return 
        ReadNumXbotsRtn ReadNumIncomingXbots();
        /// @brief Read Planar Motor Controller state
        /// @return 
        PMCStateRtn ReadPmcState();	
        /// @brief read xbot stream feedback
        /// @param StreamChannelID stream channel ID#
        /// @param XbotAxisID Axis ID. X=1, Y=2, Z=3, RX=4, RY=5, RZ=6
        /// @return 
        FeedbackRtn ReadStreamFeedback(PMC_USINT StreamChannelID, PMC_USINT XBotAxisID);
        /// @brief read extended xbot stream feedback
        /// @param XbotID stream channel ID#
        /// @param XBotAxisID Axis ID. X=1, Y=2, Z=3, RX=4, RY=5, RZ=6
        /// @return 
        FeedbackRtn ReadStreamFeedbackExtended(PMC_USINT XbotID, PMC_USINT XBotAxisID);	
        /// @brief Read the timestamp of the PMC communication frame
        /// @return struct with return code and time stamp 
        ReadTimeStampRtn ReadTimeStamp();
        /// @brief Reads the hash (MD5) and other parameters of the trajectory
        /// @param TrajID trajectory to read
        /// @return 
        TrajectoryHashRtn ReadTrajectoryHash(PMC_USINT TrajID);
        /// @brief read xbot force
        /// @param XbotID xbot ID# (1-127)
        /// @return 
        ReadXbotForceRtn ReadXbotForce(PMC_USINT XbotID);
        /// @brief Reads the number of xbots in system and their ID#s (up to 78 xbots)
        /// @return 
        ReadXbotIDsRtn ReadXbotIDs();	
        /// @brief read xbot position
        /// @param XbotID xbot ID# (1-127)
        /// @return 
        ReadXbotPosRtn ReadXbotPos(PMC_USINT XbotID);
        /// @brief Use feedback or extended feedback to calculate a xbot's speed (feedback or extended feedback must be configured before hand)
        /// @param ID stream/xbot ID (feedback position must update two times before the output is valid)
        /// @return 
        ReadXbotSpeedRtn ReadXbotSpeed(PMC_USINT ID);
        /// @brief read a xbot's state (ID <= 127)
        /// @param XbotID xbot ID# (1-127)
        /// @return 
        ReadXbotStateRtn ReadXbotState(PMC_USINT XbotID);	
        /// @brief read a xbot's state (any ID, but with increased latency)
        /// @param XbotID xbot ID#
        /// @return 
        ReadXbotStateRtn ReadXbotStateEx(PMC_USINT XbotID);
        /// @brief read a xbot's status
        /// @param XbotID xbot ID# (1-127)
        /// @return 
        ReadXbotStatusRtn ReadXbotStatus(PMC_USINT XbotID);
        /// @brief reboot Planar Motor System
        /// @return 
        PMCRTN Reboot();	
        /// @brief Recovers an accident xbot
        /// @param XbotID ID# of the xbot to be recovered (>0)
        /// @param RecoveryMode 0-resume motion after recovery, 1-pause motion(ResumeXbots to continue), 2-clear motion buffer
        /// @param ShortAxis 0:resume to default short axis position; 1:resume to previous short axis position
        /// @return 
        PMCRTN RecoverAccidentXbot(PMC_USINT XbotID, PMC_USINT RecoveryMode, PMC_USINT ShortAxis);	
        /// @brief unpause xbot motion
        /// @param XbotID 0: all Xbots; >0: specific Xbot
        /// @return 
        PMCRTN ResumeXbots(PMC_USINT XbotID);	
        /// @brief Get all scanned RFIDs and their corresponding xbot IDs
        /// @return 
        GetXbotRFIDsRtn RFID_GetXbotRFIDs();
        /// @brief Resets absolute xbot IDs for all xbots (PMC must be deactivated first)
        /// @return 
        PMCRTN RFID_ResetIDs();
        /// @brief rotates xbot around the Z axis to a target position
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0)
        /// @param BoundaryMode 0: high performance, 1: compact
        /// @param MotionMode 0: absolute motion, 1: relative motion
        /// @param WrapMode angle wrapping mode; 0:Absolute position (+/- 100 rotations) 1:positive rotation in the range of [0,2PI) -1: negative rotation in the range of [0,2PI]
        /// @param Angle target angle of rotation in radians
        /// @param MaxVel maximum velocity in rads/second
        /// @param MaxAcc maximum acceleration in rads/second^2
        /// @return 
        MotionRtn RotaryMotion(PMC_UINT cmdLB, PMC_USINT XbotID,PMC_SINT BoundaryMode,PMC_SINT MotionMode, PMC_SINT WrapMode, PMC_REAL Angle, PMC_REAL MaxVel, PMC_REAL MaxAcc);
        /// @brief spins xbot around the Z axis for a set time
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0)
        /// @param BoundaryMode >0: high performance, 1: compact
        /// @param Angle final angle of rotation after spin is complete in radians
        /// @param MaxVel maximum velocity in rads/second
        /// @param MaxAcc maximum acceleration in rads/second^2
        /// @param Duration minimum duration of spinning in seconds (0 to spin forever or until StopXbot command sent)
        /// @return 
        MotionRtn RotaryMotionSpin(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_SINT BoundaryMode, PMC_REAL Angle, PMC_REAL MaxVel, PMC_REAL MaxAcc, PMC_REAL Duration);
        /// @brief command xbot to run a macro
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param MacroID macro ID# (128 - 191)
        /// @param XbotID xbot ID# (>0)
        /// @return 
        PMCRTN RunMacro(PMC_UINT cmdLB, PMC_USINT MacroID, PMC_USINT XbotID);
        /// @brief save macro
        /// @param MacroID macro ID# (128 - 191)
        /// @return 
        PMCRTN SaveMacro(PMC_USINT MacroID);	
        /// @brief Send a trajectory file to the PMC, PMC must be in the deactivated state
        /// @param TrajID Traj ID# (1-64)
        /// @param nBytes number of bytes in the G-code file (up to 500,000 bytes)
        /// @param Axises what axises are in the trajectory file: bit0=X; bit1=Y; bit2=Z; bit3=Rx; bit4=Ry; bit5=Rz; bit6=DO (1 means axis selected; 0 means not selected)
        /// @param TimeInterval time interval between positions (seconds)
        /// @param Bytes the trajectory file as a raw binary
        /// @return 
        PMCRTN SaveTrajectory(PMC_USINT TrajID, PMC_DINT nBytes, PMC_USINT Axises, PMC_REAL TimeInterval, PMC_BYTE* Bytes);	
        /// @brief Gets the global ID of a xbot on a flyway
        /// @param FlywayID logical ID (>0) of the flyway to scan
        /// @return 
        ScanXIDRtn ScanXID(PMC_USINT FlywayID);
        /// @brief Activate a sector
        /// @param SectorID sector ID: >0
        /// @return 
        PMCRTN Sector_Activate(PMC_USINT SectorID);
        /// @brief Deactivate  a sector
        /// @param SectorID sector ID: >0
        /// @return 
        PMCRTN Sector_Deactivate(PMC_USINT SectorID);
        /// @brief Get the status of a sector
        /// @param SectorID sector ID: >0
        /// @return 
        Sector_GetStatusRtn Sector_GetStatus(PMC_USINT SectorID);
        /// @brief Recover a sector, removing the fence around it
        /// @param SectorID sector ID: >0
        /// @return 
        PMCRTN Sector_Recover(PMC_USINT SectorID);
        /// @brief Sends the digital signal to PMC
        /// @param DoID digital output (of the PLC fieldbus) ID# [1-128]
        /// @param Level desired digital signal level
        /// @return successfully set/reset the digital signal
        bool SendDigitalSignalToPMC(PMC_USINT DoID, PMC_BOOL Level);	
        /// @brief Enter and leave PMC service mode
        /// @param Level 0: enter service mode;1: exit service mode
        /// @return 
        PMCRTN ServiceModeCtrl(PMC_USINT Level);	
        /// @brief Sets the PMC date and time used for logging
        /// @param Year year (AD/CE)
        /// @param Month month (one indexed, January = 1)
        /// @param Day day (one indexed, first day of the month = 1)
        /// @param Hour hour (24 hour clock)
        /// @param Minute minute
        /// @param Second second
        /// @return 
        PMCRTN SetDateAndTime(PMC_UINT Year, PMC_UINT Month, PMC_UINT Day, PMC_UINT Hour, PMC_UINT Minute, PMC_UINT Second);
        /// @brief Sets the jerk (rate of acceleration change) limit for a xbot
        /// @param XbotID xbot ID# (>0)
        /// @param AxisID axis ID (1: X, 2: Y, 3: Z, 4: Rx, 5: Ry, 6:Rz)
        /// @param JerkLimit Jerk limit (m/s^3 or rad/s^3)
        /// @return 
        PMCRTN SetJerkLimit(PMC_USINT XbotID, PMC_USINT AxisID, PMC_REAL JerkLimit);
        /// @brief Initialize orientation of xbot before activation in absolute ID mode
        /// @param XbotID xbot ID# (0 = all xbots)
        /// @param Orientation 0-0deg;1-90deg;2-180deg;3-270deg
        /// @return 
        PMCRTN SetXbotOrientation(PMC_USINT XbotID, PMC_USINT Orientation);
        /// @brief set a xbot property
        /// @param nXbots number of xbots to set a property on (up to 14)
        /// @param XbotID array of xbot ID#
        /// @param PropertyID array of property IDs; 0: mover type (read only); 1: user configured payload; 2: user configured center of gravity in Z; 3: payload X dimension; 5: payload Y dimension; 7: acceleration limit (read only)
        /// @param Value array of property values; 1: user configured payload (kilograms); 2: user configured center of gravity in Z (meters); 3: payload X dimension (meters); 5: payload Y dimension (meters)
        /// @return 
        PMCRTN SetXbotProperty(PMC_USINT nXbots, PMC_USINT* XbotID, MOVERPROPERTY* PropertyID, PMC_REAL* Value);
        /// @brief move xbot in Z, Rx, Ry, and, Rz
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0)
        /// @param Mode 0:Absolute;1:Relative
        /// @param Type_ 0: Rotation only;1: Planar Rotation
        /// @param PosZ Z position in meters
        /// @param PosRx rotation about X axis in radians
        /// @param PosRy rotation about Y axis in radians
        /// @param PosRz rotation about Z axis in radians
        /// @param VelZ velocity in Z axis in meters/second
        /// @param VelRx velocity of X axis rotation in radians/second
        /// @param VelRy velocity of Y axis rotation in radians/second
        /// @param VelRz velocity of Z axis rotation in radians/second
        /// @param Cx Rotation center in X when type=1
        /// @param Cy Rotation center in Y when type=1
        /// @return 
        MotionRtn ShortAxisMotion(PMC_UINT cmdLB, PMC_USINT XbotID, POSITIONMODE Mode, SHORTAXESCENTERMODE Type_, PMC_REAL PosZ, PMC_REAL PosRx, PMC_REAL PosRy, PMC_REAL PosRz, PMC_REAL VelZ, PMC_REAL VelRx, PMC_REAL VelRy, PMC_REAL VelRz, PMC_REAL Cx, PMC_REAL Cy);
        /// @brief Move a xbot in only one axis
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to move (>0).
        /// @param Mode 0: Absolute position. 1: relative positioning
        /// @param Priority 0: no priority, 1: high priority; all other xbots that try to enter the path will be blocked until motion is done
        /// @param AxisID axis to move in 1-X, 2-Y, 3-Z, 4-Rx, 5-Ry, 6-Rz 
        /// @param Pos position in meters or radians
        /// @param EndVel ending velocity in meters/second or radians/second
        /// @param MaxVel maximum velocity in meters/second or radians/second
        /// @param MaxAcc maximum acceleration in meters/second^2 or radians/second^2
        /// @return 
        MotionRtn SingleAxisMotion(PMC_UINT cmdLB, PMC_USINT XbotID, POSITIONMODE Mode,PMC_USINT Priority, PMC_USINT AxisID, PMC_REAL Pos, PMC_REAL EndVel, PMC_REAL MaxVel, PMC_REAL MaxAcc);
        /// @brief Define a new star wheel module
        /// @param WheelID Wheel ID (>0)
        /// @param Direction Wheel rotation direction (0: clockwise/negative Rz, 1: counterclockwise/position Rz)
        /// @param MasterXID Master Xbot ID (must be virtual xbot 100-127)
        /// @param DiscRadius Wheel radius in meters
        /// @param MaxDiscSpeed Maximum disc rotation speed in rad/s
        /// @param MaxXbotAcc Maximum xbot acceleration in m/s^2
        /// @param DiscCenterX Disc center X coordinate in meters
        /// @param DiscCenterY Disc center Y coordinate in meters
        /// @param StartX Xbot starting location X coordinate in meters
        /// @param StartY Xbot starting location Y coordinate in meters
        /// @param EndX Xbot ending location X coordinate in meters
        /// @param EndY Xbot ending location Y coordinate in meters
        /// @param SyncStart Sync section starting angle in radians
        /// @param SyncEnd Sync section ending angle in radians
        /// @param NumVials Number of vials on the disc (1-100)
        /// @param VialLocations Location of the vials on the disc in radians (CCW is positive)
        /// @return 
        PMCRTN Star_CreateStar(PMC_USINT WheelID, PMC_USINT Direction, PMC_USINT MasterXID, PMC_REAL DiscRadius, PMC_REAL MaxDiscSpeed, PMC_REAL MaxXbotAcc, PMC_REAL DiscCenterX, PMC_REAL DiscCenterY, PMC_REAL StartX, PMC_REAL StartY, PMC_REAL EndX, PMC_REAL EndY, PMC_REAL SyncStart, PMC_REAL SyncEnd, PMC_USINT NumVials, PMC_REAL* VialLocations);
        /// @brief Delete a star wheel module
        /// @param WheelID wheel ID:  0 - delete all wheels, >0 - delete single wheel
        /// @return 
        PMCRTN Star_DeleteStar(PMC_USINT WheelID);
        /// @brief Get the status of a star wheel module
        /// @param WheelID wheel ID: >0
        /// @return 
        StarStatusReturn Star_GetStarStatus(PMC_USINT WheelID);	
        /// @brief send an xbot to a star wheel module
        /// @param WheelID wheel ID: >0
        /// @param XbotID xbot ID: >0
        /// @return 
        PMCRTN Star_SendXbotToStar(PMC_USINT WheelID, PMC_USINT XbotID);
        /// @brief Tell a star wheel module that the xbot is clear of the exit
        /// @param WheelID Wheel ID: >0
        /// @return 
        PMCRTN Star_StarExitClear(PMC_USINT WheelID);	
        /// @brief activate PMC, levitate all xbots, report number of xbots in system and their ID#s
        /// @return 
        StartUpPMSRtn StartUpPlanarMotorSystem();
        /// @brief stop motion of xbot and clear its buffer
        /// @param XbotID xbot ID#; 0: all xbots; 1: specific xbot
        /// @return 
        PMCRTN StopXbots(PMC_USINT XbotID);
        /// @brief configure xbot reference streaming
        /// @param Level 0:Exit from stream mode;1: Enter stream mode
        /// @param nXbots number of xbots to configure streaming for (up to 9)
        /// @param Buffer 0: enter/exit stream mode immediately; 1:add mode change to motion buffer
        /// @param XbotID array of xbot ID#s
        /// @param StmID stream ID#s
        /// @param StmAxis Bit0: X;Bit1:Y;Bit2:Z;Bit3: Rx; Bit4: Ry; Bit5: Rz
        /// @param offsetX offset in X for stream position (meters)
        /// @param offsetY offset in Y for stream position (meters)
        /// @return 
        StreamModeCtrlRtn StreamModeCtrl(PMC_USINT Level, PMC_USINT nXbots,PMC_USINT Buffer, PMC_USINT* XbotID, PMC_USINT* StmID, PMC_USINT* StmAxis,PMC_REAL* offsetX,PMC_REAL* offsetY);
        /// @brief send linear motion commands to multiple xbots at once
        /// @param nXbots number of xbots to send linear move to (up to 4)
        /// @param XbotID xbot ID#s
        /// @param PosX X positions in meters
        /// @param PosY Y positions in meters
        /// @param EndVel Ending velocities in meters/second
        /// @param MaxVel maximum velocities in meters/second
        /// @param MaxAcc maximum accelerations in meters/second^2
        /// @return 
        MotionRtn SyncMotion(PMC_USINT nXbots, PMC_USINT* XbotID, PMC_REAL* PosX, PMC_REAL* PosY, PMC_REAL* EndVel, PMC_REAL* MaxVel, PMC_REAL* MaxAcc);	
        /// @brief reset the xbot weight to zero
        /// @param XbotID xbot ID# (>0)
        /// @return 
        PMCRTN TareXbot(PMC_USINT XbotID);
        /// @brief Enable or disable ReadXbotPos for a virtual xbot
        /// @param XbotID xbot ID# (>=100)
        /// @param Mode 0-enable ReadXbotPos for this virtual xbot,1-disable ReadXbotPos for this virtual xbot
        /// @return 
        PMCRTN VirtualXbotReadPosCtrl(PMC_USINT XbotID, PMC_USINT Mode);
        /// @brief Teleport a virtual xbot to a given position (virtual xbot must be idle first)
        /// @param XbotID xbot ID# (>=100)
        /// @param PosX X position (meters)
        /// @param PosY Y position (meters)
        /// @param PosZ Z position (meters)
        /// @param PosRx Rx position (radians)
        /// @param PosRy Ry position (radians)
        /// @param PosRz Rz position (radians)
        /// @return 
        PMCRTN VirtualXbotTeleport(PMC_USINT XbotID, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL PosZ, PMC_REAL PosRx, PMC_REAL PosRy, PMC_REAL PosRz);
        /// @brief xbot waits until another xbot performs a command with a certain label
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID # of the xbot to wait (>0)
        /// @param TriggerXID Trigger Xbot ID
        /// @param TriggerType 0: Begin;1: End; 2: Execute
        /// @param TriggerCmdLb command label to wait for
        /// @param LabelType 0: Motion Cmd Label;1: Run Macro Cmd Label
        /// @return 
        PMCRTN WaitUntilCmdLb(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_USINT TriggerXID, TRIGGERCMDLABELTYPE TriggerType, PMC_UINT TriggerCmdLb, TRIGGERCMDTYPE LabelType);	
        /// @brief xbot waits until another xbots reaches a given displacement
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to wait (>0)
        /// @param TriggerXID Trigger Xbot ID
        /// @param dispMode 0: X only; 1: Y only
        /// @param dispType 0: Greater Than;1: Less Than; 2: Positive cross;3: Negative cross
        /// @param Threshold threshold to wait until in meters
        /// @param posXFactor deprecated
        /// @param posYFactor deprecated
        /// @return 
        PMCRTN WaitUntilDisp(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_USINT TriggerXID, TRIGGERDISPLACEMENTMODE dispMode, TRIGGERDISPLACEMENTTYPE dispType, PMC_REAL Threshold, PMC_REAL posXFactor, PMC_REAL posYFactor);
        /// @brief xbot waits for a PMC digital input
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to wait (>0)
        /// @param TriggerDI Trigger Digital ID
        /// @param TriggerType 0: Rising Edge;1: Falling Edge; 2: High Level;3: Low Level
        /// @return 
        PMCRTN WaitUntilFBDI(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_USINT TriggerDI, TRIGGEREDGETYPE TriggerType);
        /// @brief xbot waits for a amount of time
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to wait (>0)
        /// @param Delay time to wait for in seconds
        /// @return 
        PMCRTN WaitUntilTimeDelay(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_REAL Delay);	
        /// @brief xbot waits until the number of xbots in a zone reaches a threshold
        /// @param cmdLB label to be associated with this command in the PMC
        /// @param XbotID ID# of the xbot to wait (>0)
        /// @param TriggerZoneID Trigger Zone ID
        /// @param TriggerType 0: rising edge; 1: falling edge; 2: greater then; 3: less than
        /// @param Threshold number of xbots threshold to wait until
        /// @return 
        PMCRTN WaitUntilZone(PMC_UINT cmdLB, PMC_USINT XbotID, PMC_USINT TriggerZoneID, PMC_USINT TriggerType, PMC_USINT Threshold);
        /// @brief Measure the weight of an xbot, averaged over a period of time
        /// @param XbotID xbot ID# (>0)
        /// @param Duration weighting duration (s)
        /// @param ReturnType 0-wait until weighing is complete before returning,1-start weighing only,2-read weighing result only
        /// @return 
        PayloadRtn WeighXbot(PMC_USINT XbotID, PMC_REAL Duration,PMC_USINT ReturnType);
        /// @brief Write a reference position/force to the PMC
        /// @param StmID stream ID#s [1-9]
        /// @param AxisID 1: X; 2: Y; 3: Z; 4: Rx; 5: Ry; 6: Rz
        /// @param Pos reference value; meters for position X/Y/Z; radians for position Rx/Ry/Rz; Newtons for force X/Y/Z; Newton*Meters for force Rx,Ry,Rz
        /// @return successfully wrote reference stream
        bool WriteStream(PMC_USINT StmID, PMC_USINT AxisID, PMC_REAL Pos);
        /// @brief Changes state of the part that the xbot is carrying
        /// @param nXbots The number of xbots (1-127)
        /// @param XbotID pointer to array of xbot IDs
        /// @param PartState pointer to array of part states
        /// @return 
        PMCRTN XbotPartCtrl(PMC_USINT nXbots, PMC_USINT* XbotID, PMC_USINT* PartState);
        /// @brief linear motion command using SI units (meters, radians)
        /// @param cmdLB command label (0-65535)
        /// @param XbotID xbot ID (1-255)
        /// @param Mode 0 = absolute position mode; 1 = relative position mode
        /// @param Type 0 = direct; 1 = X then Y; 2 = Y then X
        /// @param PosX Target Position X, in meters
        /// @param PosY Target Position Y, in meters
        /// @param EndVel Final speed, in m/s
        /// @param MaxVel Max speed, in m/s
        /// @param MaxAcc Max acceleration, in m/s^2
        /// @param Radius turn radius of corner if Type = 1 or 2
        /// @return PMC return value + travel time in seconds
        MotionRtn XYMotion(PMC_UINT cmdLB, PMC_USINT XbotID, POSITIONMODE Mode, LINEARPATHTYPE Type, PMC_REAL PosX, PMC_REAL PosY, PMC_REAL EndVel, PMC_REAL MaxVel, PMC_REAL MaxAcc,PMC_REAL Radius);
        /// @brief Disable/enable Rz collision checks in a zone
        /// @param ZoneID zone ID: >0
        /// @param DisableRzCheck 0 = enable Rz collision check, 1 = disable Rz collision check
        /// @return 
        PMCRTN Zone_CollisionControl(PMC_USINT ZoneID, PMC_USINT DisableRzCheck);	
        /// @brief Define the area controlled by a zone
        /// @param ZoneID zone ID: >0
        /// @param Mode 0: regular zone, >0: intersection zone with # of xbots allowed to enter
        /// @param BottomLeftX X coordinate of bottom left corner of zone (m)
        /// @param BottomLeftY Y coordinate of bottom left corner of zone (m)
        /// @param TopRightX X coordinate of right top corner of zone (m)
        /// @param TopRightY Y coordinate of right top corner of zone (m)
        /// @param EnableZLimit 0: no Z limit on xbots that enter, 1: enable Z limit
        /// @param ZLimit xbots at height above this will be blocked by fence: ignored if z limit isn't enabled
        /// @return 
        PMCRTN Zone_DefineZone(PMC_USINT ZoneID,PMC_USINT Mode, PMC_REAL BottomLeftX, PMC_REAL BottomLeftY, PMC_REAL TopRightX, PMC_REAL TopRightY,PMC_USINT EnableZLimit,PMC_REAL ZLimit);
        /// @brief Activate or deactivate the fence around a zone
        /// @param ZoneID Zone ID (>0)
        /// @param Level Control level: 0 - fence off, 1 - fence on
        /// @return 
        PMCRTN Zone_Fencing(PMC_USINT ZoneID, FENCEOPERATION Level);
        /// @brief Get the status of a zone
        /// @param ZoneID Zone ID (>0)
        /// @return 
        ZoneStatusReturn Zone_GetStatus(PMC_USINT ZoneID);
        /// @brief Get the status of a zone with extended information
        /// @param ZoneID Zone ID (>0)
        /// @return 
        ZoneStatusExReturn Zone_GetStatusEx(PMC_USINT ZoneID);
        /// @brief Change the speed override settings for a zone
        /// @param ZoneID Zone ID (>0)
        /// @param OverrideType 0-override with ratio,1-override with absolute speed and acceleration limits
        /// @param SpeedOverrideFactor multiplicative factor for xbot speed in the zone (0-2)
        /// @param AccOverrideFactor multiplicative factor for xbot acceleration in the zone (0.001-2)
        /// @return 
        PMCRTN Zone_OverrideZone(PMC_USINT ZoneID,PMC_USINT OverrideType, PMC_REAL SpeedOverrideFactor, PMC_REAL AccOverrideFactor);
        /// @brief Place xbots into a deactivated zone in emulation mode
        /// @param ZoneID zone ID: >0
        /// @param NumXbots number of xbots to place (up to 9)
        /// @param MoverType XBot type to place (0 = M3-06,2 = M3-08,4 = M3-09X,5 = M3-09Y,6 = M3-10,8 = M3-11X,9 = M3-11Y,12 = M3-12,14 = M3-13)
        /// @param PosX X position to place the xbot
        /// @param PosY Y position to place the xbot
        /// @return 
        PMCRTN Zone_PlaceXbotsEmulation(PMC_USINT ZoneID, PMC_USINT NumXbots, PMC_USINT* MoverType, PMC_REAL* PosX, PMC_REAL* PosY);
        /// @brief Remove all xbots from a deactivated zone in emulation mode
        /// @param ZoneID zone ID: >0
        /// @return 
        PMCRTN Zone_RemoveXbotsEmulation(PMC_USINT ZoneID);
        /// @brief activate or deactivate a zone
        /// @param ZoneID Zone ID (>0)
        /// @param Level Control level: 0 - deactivate zone, 1 - activate zone
        /// @return 
        PMCRTN Zone_ZoneCtrl(PMC_USINT ZoneID, ZONEOPERATION Level);
        /// @brief (PMI INTERNAL TESTING, DELETE FROM CUSTOMER LIBRARY) Starts recording a function
        /// @param numXbots The number xbots in the function (>0)
        /// @return 
        FunctionRtn StartFunction(PMC_USINT numXbots);
        /// @brief (PMI INTERNAL TESTING, DELETE FROM CUSTOMER LIBRARY) Stop function recording
        /// @return 
        PMCRTN EndFunction();
        /// @brief (PMI INTERNAL TESTING, DELETE FROM CUSTOMER LIBRARY) Deletes a recorded function
        /// @param FunctionID The function id number (0 - delete all functions, >0 - delete specific function)
        /// @return 
        PMCRTN DeleteFunction(PMC_USINT FunctionID);
        /// @brief (PMI INTERNAL TESTING, DELETE FROM CUSTOMER LIBRARY) Runs a recorded function
        /// @param FunctionID The function id number (>0)
        /// @param SyncMode 0-synced, 1-non synced
        /// @param numXbots The number of xbots in the function (>0)
        /// @param XbotID Pointer to array of xbot IDs
        /// @return 
        PMCRTN RunFunction(PMC_USINT FunctionID,PMC_USINT SyncMode, PMC_USINT numXbots, PMC_USINT* XbotID);	
        /// @brief (PMI INTERNAL TESTING, DELETE FROM CUSTOMER LIBRARY) Gets info about a function
        /// @param FunctionID The function id number (>0)
        /// @return 
        FunctionInfoRtn GetFunctionInfo(PMC_USINT FunctionID);
        /// @brief (PMI INTERNAL USE, DELETE FROM CUSTOMER LIBRARY) Command function template
        /// @param Input example input
        /// @param NumInputs The number inputs
        /// @return 
        PMCRTN CommandFunctionTemplate(PMC_USINT Input, PMC_UDINT NumInputs);
        /// @brief (PMI INTERNAL USE, DELETE FROM CUSTOMER LIBRARY) activate an application design
        /// @param DesignID the design ID to activate
        /// @return 
        PMCRTN AppDesign_SelectDesign(PMC_USINT DesignID);
    };
}
