#include "PMC_Acontis_Examples.h"
#include "EcOs.h"

void PollForXbotState(PMC_Acontis_API* PMC,int XbotID, XBOTSTATE state)
{
	ReadXbotStateRtn rtn;

	do
	{
		rtn = PMC->ReadXbotState(XbotID);
	} while (rtn.State != state && rtn.valid == true);
}

void PollForAllXbotsState(PMC_Acontis_API* PMC,XBOTSTATE state)
{
	ReadXbotIDsRtn rtn = PMC->ReadXbotIDs();

	if (rtn.valid == false)
	{
		return;
	}

	for (int i = 0; i < rtn.NumXbots; i++)
	{
		PollForXbotState(PMC,rtn.Xbot_IDs[i], state);
	}
}

void PollForPMCState(PMC_Acontis_API* PMC,PMCSTATUS state)
{
	PMCStateRtn rtn;

	do
	{
		rtn = PMC->ReadPmcState();
	} while (rtn.state != state && rtn.valid == true);
}

//2x1 flyways w/ 1 xbots - linear, arc target, block buffer, release buffer, clear macro, save macro, run macro
void Example01_longaxismotion(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 120,180
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.18, 0, 1, 10, 0);

	//arc motion counter clockwise to 120,60
	PMC->ArcMotionTarget(2, 1, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 0, 1, 10, 0.12, 0.06, 0.06);

	//linear motion to 360,60
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, 0.06, 0, 1, 10, 0);

	//arc motion to 360,180
	PMC->ArcMotionTarget(4, 1, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 0, 1, 10, 0.36, 0.18, 0.06);

	//linear motion to 120,180
	PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.18, 0, 1, 10, 0);

	//block xbot 1 motion buffer
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::BLOCKBUFFER, 1);

	//arc motion to 120,60 non-zero ending speed
	PMC->ArcMotionTarget(7, 1, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 10, 0.12, 0.06, 0.06);

	//linear motion to 360,60 non-zero ending speed
	PMC->XYMotion(8, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, 0.06, 1, 1, 10, 0);

	//arc motion to 360,180 non-zero ending speed
	PMC->ArcMotionTarget(9, 1, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 10, 0.36, 0.18, 0.06);

	//linear move to 120,180 zero ending speed
	PMC->XYMotion(10, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.18, 0, 1, 10, 0);

	//unblock xbot 1 buffer
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::RELEASEBUFFER, 1);

	//clear macro 128
	PMC->ClearMacro(128);

	//arc motion to 120,60 non-zero ending speed (macro 128)
	PMC->ArcMotionTarget(13, 128, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 10, 0.12, 0.06, 0.06);

	//linear motion to 360,60 non-zero ending speed (macro 128)
	PMC->XYMotion(14, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, 0.06, 1, 1, 10, 0);

	//arc motion to 360,180 non-zero ending speed (macro 128)
	PMC->ArcMotionTarget(15, 128, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 10, 0.36, 0.18, 0.06);

	//linear move to 120,180 zero ending speed
	PMC->XYMotion(16, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.18, 0, 1, 10, 0);

	//save macro 128
	PMC->SaveMacro(128);

	//run macro 128 using xbot 1
	PMC->RunMacro(18, 128, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways w/ 1 xbots - short axis, 6 dof, 6 dof w speed
void Example02_shortaxismotion(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 120,120
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::XTHENY, 0.12, 0.12, 0, 1, 10, 0);

	//short axis motion to z = 2 mm
	PMC->ShortAxisMotion(2, 1, POSITIONMODE::ABSOLUTE_MOTION, SHORTAXESCENTERMODE::XBOT_CENTER, 0.002, 0, 0, 0, 0.1, 0.1, 0.1, 0.1, 0, 0);

	//short axis motion to z = 2 mm, rx = 10mrad, Ry = 10mrad, rz = 80mrad
	PMC->ShortAxisMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, SHORTAXESCENTERMODE::XBOT_CENTER, 0.002, 0.01, 0.01, 0.08, 0.1, 0.1, 0.1, 0.1, 0, 0);

	//short axis motion to z = 1 mm, rx = 0mrad, Ry = 0mrad, rz = 0mrad
	PMC->ShortAxisMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, SHORTAXESCENTERMODE::XBOT_CENTER, 0.001, 0, 0, 0, 0.1, 0.1, 0.1, 0.1, 0, 0);

	//six dof to x=80mm,y=100mm,z=2mm,rx=10mrad,ry=10mrad,rz=80mrad)
	PMC->SixDMotion(5, 1, 0.08, 0.1, 0.002, 0.01, 0.01, 0.08);

	//six dof to (120,120,1,0,0,0) w/ user speeds
	PMC->SixDMotionVelocity(6, 1, 0.12, 0.12, 0.001, 0, 0, 0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways w/ 2 xbots - async,async velocity, create group,block&release group buffer, bond&unbond group
void Example03_groups(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//async move to 60,60 and 60,180
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC_REAL PosX_array[2] = { 0.06,0.06 };
	PMC_REAL PosY_array[2] = { 0.06,0.18 };
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, PosX_array, PosY_array);
	PollForAllXbotsState(PMC);

	// create group 1 w/ xbots 1 and 2
	PMC->CreateXbotGroup(1, 2, xbotID_array);

	//block buffer for group 1
	PMC->BlockXbotGroup(1, true);

	// load command to move xbot 1 to 420,60
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.06, 0, 1, 10, 0);

	//load command to move xbot 2 to 420,180
	PMC->XYMotion(5, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.18, 0, 1, 10, 0);

	//release buffer for group 1
	PMC->BlockXbotGroup(1, false);

	//move xbot 1 to 60,60
	PMC->XYMotion(7, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	// async move to 180,60 and 180,180 at user set speed and acceleration
	PosX_array[0] = 0.180; PosX_array[1] = 0.060;
	PosY_array[0] = 0.180; PosY_array[1] = 0.180;
	PMC->AutoDrivingMotionVelocity(2,0,false,0, xbotID_array, PosX_array, PosY_array, 2, 20);
	PollForAllXbotsState(PMC);

	// bond xbots in group 1
	PMC->BondXbotGroup(1, true, 0);

	// move xbot 1 to 420,60
	PMC->XYMotion(10, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.06, 0, 1, 10, 0);

	//move xbot 2 to 300,180
	PMC->XYMotion(11, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.30, 0.18, 0, 1, 10, 0);

	//move xbot 1 to 180,60
	PMC->XYMotion(12, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, 0.06, 0, 1, 10, 0);
	PollForAllXbotsState(PMC);

	//unbond xbots in group 1
	PMC->BondXbotGroup(1, false, 0);

	//move xbot 1 to 180,180
	MotionRtn rtn = PMC->XYMotion(14, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, 0.18, 0, 1, 10, 0);

	//delete group 1
	PMC->DeleteXbotGroup(1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways w/ 2 xbots - waituntil cmdlb,waituntil displacement
void Example04_waituntil(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//async move to 60,60 and 60,180
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC_REAL PosX_array[2] = { 0.06,0.18 };
	PMC_REAL PosY_array[2] = { 0.06,0.06 };
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, PosX_array, PosY_array);
	PollForAllXbotsState(PMC);

	// xbot 2 linear move to 180,180
	PMC->XYMotion(2, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, 0.18, 0, 1, 10, 0);

	//xbot 1 wait until xbot 2 does command label 5
	PMC->WaitUntilCmdLb(3, 1, 2, TRIGGERCMDLABELTYPE::CMD_START, 5, TRIGGERCMDTYPE::MOTION_COMMAND);

	// load command to move xbot 1 to 180,60
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, 0.06, 0, 1, 10, 0);

	// delay for 1 second
	this_thread::sleep_for(1000ms);

	//xbot 2 move to 300,180 w/ cmd lb 5
	PMC->XYMotion(5, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.30, 0.18, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//xbot 1 waituntil xbot 2 is x > 299.9
	PMC->WaitUntilDisp(6, 1, 2, TRIGGERDISPLACEMENTMODE::X_ONLY, TRIGGERDISPLACEMENTTYPE::GREATER_THAN, 0.2999, 0, 0);

	// load command to move xbot 1 to 180,180
	PMC->XYMotion(7, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, 0.18, 0, 1, 10, 0);

	// xbot 2 to 300,60
	PMC->XYMotion(8, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.30, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	// xbot 1 waituntil xbot 2 is y < 60.1 mm
	PMC->WaitUntilDisp(9, 1, 2, TRIGGERDISPLACEMENTMODE::Y_ONLY, TRIGGERDISPLACEMENTTYPE::LESS_THAN, 0.0601, 0, 0);

	// load command to move xbot 1 to 420,180
	PMC->XYMotion(10, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.18, 0, 1, 10, 0);

	// move xbot 2 to 420,60
	PMC->XYMotion(11, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.06, 0, 1, 10, 0);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x2 flyways w/ 1 xbots sample trajectory set as trajectory 1 (time interval = 10 ms) - trajectory, pause, resume, stop, deactivate, activate, levitate, arc center
void Example05_pmccontrol(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 240,240
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.24, 0.24, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//xbot 1 does trajectory 1
	PMC_USINT xbotID = 1;
	PMC_USINT trajID = 1;
	PMC->ActivateTrajectory(2, 1, &xbotID, &trajID);
	this_thread::sleep_for(5000ms);

	//pause xbot 1
	PMC->PauseXbots(1);
	this_thread::sleep_for(5000ms);

	//resume xbot 1
	PMC->ResumeXbots(1);
	this_thread::sleep_for(4500ms);

	//stop xbot 1
	PMC->StopXbots(1);
	PollForXbotState(PMC,1);

	//360 around 240,240
	PMC->ArcMotionCenter(6, 1, POSITIONMODE::ABSOLUTE_MOTION, ARCDIRECTION::CLOCKWISE, 0, 1, 10, 0.24, 0.24, 6.283);
	PollForXbotState(PMC,1);

	//deactivate PMC
	PMC->DeactivateXbots();
	PollForPMCState(PMC,PMCSTATUS::PMC_INACTIVE);
	this_thread::sleep_for(2000ms);

	//activate PMC
	PMC->ActivateXbots(0);
	PollForPMCState(PMC, PMCSTATUS::PMC_FULLCTRL);
	this_thread::sleep_for(2000ms);

	//Land xbot 1
	PMC->LevitationCtrl(1, LEVITATEOPTIONS::LAND,0,0);
	PollForXbotState(PMC, 1,XBOTSTATE::XBOT_LANDED);
	this_thread::sleep_for(2000ms);

	//Levitate xbot 1
	PMC->LevitationCtrl(1, LEVITATEOPTIONS::LEVITATE,0,0);
	PollForXbotState(PMC, 1, XBOTSTATE::XBOT_IDLE);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways, 4 xbots - get xbot prop, set xbot prop, sync move
void Example06_sync(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//async move to 60,60 300,60 540,60 780,60
	PMC_USINT xbotID_array[4] = { 1,2,3,4 };
	PMC_REAL PosX_array[4] = { 0.06,0.30,0.54,0.78 };
	PMC_REAL PosY_array[4] = { 0.06,0.06,0.06,0.06 };
	PMC->AutoDrivingMotion(4,0,false,0, xbotID_array, PosX_array, PosY_array);
	PollForAllXbotsState(PMC);

	//sync move all xbots to top of flyways
	PosY_array[0] = 0.66; PosY_array[1] = 0.66; PosY_array[2] = 0.66; PosY_array[3] = 0.66;
	PMC_REAL endvel[4] = { 0,0,0,0 };
	PMC_REAL maxacc[4] = { 20,20,20,20 };
	PMC_REAL maxvel[4] = { 2,2,2,2 };
	PMC->SyncMotion(4, xbotID_array, PosX_array, PosY_array, endvel, maxvel, maxacc);
	PollForAllXbotsState(PMC);

	//sync move all xbots to bottom of flyways
	PosY_array[0] = 0.06; PosY_array[1] = 0.06; PosY_array[2] = 0.06; PosY_array[3] = 0.06;
	PMC->SyncMotion(4, xbotID_array, PosX_array, PosY_array, endvel, maxvel, maxacc);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 2 xbots - sun planet
void Example07_sun(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//async move to 60,60 and 60,180
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC_REAL PosX_array[2] = { 0.06,0.06 };
	PMC_REAL PosY_array[2] = { 0.06,0.18 };
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, PosX_array, PosY_array);
	PollForAllXbotsState(PMC);

	//set xbot 2 as a planet to xbot 1
	PMC->PlanetMotionCtrl(PLANETOPTIONS::ADDPLANETS, 1, 1, &xbotID_array[1]);

	//move xbot 1 to 900,60
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//move xbot 1 to 60,60
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForAllXbotsState(PMC);

	//disconnect xbot 2 from xbot 1
	PMC->PlanetMotionCtrl(PLANETOPTIONS::REMOVEPLANETS, 1, 1, &xbotID_array[1]);

	//move xbot 1 to 900,60
	PMC->XYMotion(6, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//move xbot 1 to 60,60
	PMC->XYMotion(7, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 2 xbots - get pmc state, get buffer status
void Example08_bufferstatus(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//get pmc state
	PMCStatusRtn pmc_status = PMC->GetPmcStatus();

	//get buffer status of xbot 1
	MotionBufferStatusRtn BufferStatus1 = PMC->GetBufferStatus(1);

	//block buffer of xbot 1
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::BLOCKBUFFER, 1);

	//get buffer status of xbot 1
	MotionBufferStatusRtn BufferStatus2 = PMC->GetBufferStatus(1);

	//add move command to xbot 1 buffer
	PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//add move command to xbot 1 buffer
	PMC->XYMotion(6, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//get buffer status of xbot 1
	MotionBufferStatusRtn BufferStatus3 = PMC->GetBufferStatus(1);

	//release buffer of xbot 1
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::RELEASEBUFFER, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways 2 xbots - delete group, get group status, get macro status
void Example09_groupstatus(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//create group 1 from xbot 1 and 2
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC->CreateXbotGroup(1, 2, xbotID_array);

	//get status of group 1
	GroupStatusRtn GroupStatus1 = PMC->GetGroupStatus(1);

	//bond group 1
	PMC->BondXbotGroup(1, true, 0);

	//get status of group 1
	GroupStatusRtn GroupStatus2 = PMC->GetGroupStatus(1);

	//delete group 1
	PMC->DeleteXbotGroup(1);

	//get status of group 1
	GroupStatusRtn GroupStatus3 = PMC->GetGroupStatus(1);

	//clear macro 128
	PMC->ClearMacro(128);

	//get status of macro 128
	MotionMacroReturn MacroStatus1 = PMC->GetMacroStatus(128);

	//add command to macro 128
	PMC->XYMotion(9, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//add command to macro 128
	PMC->XYMotion(10, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//save macro 128
	PMC->SaveMacro(128);

	//get status of macro 128
	MotionMacroReturn MacroStatus2 = PMC->GetMacroStatus(128);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbots - get xbot status, wait until delay
void Example10_waituntiltime(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//get xbot 1 status
	XBotStatusRtn XbotStatus1 = PMC->GetXbotStatus(1, FEEDBACKOPTION::POSITION);

	//block xbot 1 buffer
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::BLOCKBUFFER, 1);

	//load move to 900,60
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//load wait for 5 seconds
	PMC->WaitUntilTimeDelay(4, 1, 5);

	//load move to 60,60
	PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//load wait for 5 seconds
	PMC->WaitUntilTimeDelay(6, 1, 5);

	//release xbot 1 buffer
	PMC->MotionBufferCtrl(MOTIONBUFFEROPTIONS::RELEASEBUFFER, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//>= 1 xbot
void Example11_readxbotposition(PMC_Acontis_API* PMC)
{
	int count = 0;
	while (count < 100)
	{
		//Read xbot 1 position every 100 ms while user moves the xbot using the PMT
		ReadXbotPosRtn PosRtn = PMC->ReadXbotPos(1);
		printf("Xbot X = %d mm, Y = %d mm\n", (int)(PosRtn.PosX * 1000), (int)(PosRtn.PosY * 1000));
		count++;
		this_thread::sleep_for(100ms);
	}
}

//4x3 flyways 1 xbot - send digital signal to PMC, macro trigger from DI
void Example12_DImacro(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//clear macro 128
	PMC->ClearMacro(128);

	//write move to 900,60 to macro 128
	PMC->XYMotion(3, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//write move to 900,660 to macro 128
	PMC->XYMotion(4, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.66, 0, 1, 10, 0);

	//save macro 128
	PMC->SaveMacro(128);

	//set digital input 1 to trigger macro 128 on xbot 1
	PMC_USINT DiID_array[1] = { 1 };
	PMC_USINT macroID_array[1] = { 128 };
	PMC_USINT xbotID_array[1] = { 1 };
	PMC->ConfigDI2RunMacro(1, DiID_array, macroID_array, xbotID_array);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);
	this_thread::sleep_for(1ms);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - waituntil DI, config DI as trigger
void Example13_waituntilDI(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//set DI 1 as trigger source
	PMC_USINT DiID_array[1] = { 1 };
	PMC->ConfigDI2Trigger(1, DiID_array);

	//xbot 1 wait until DI1 rising edge
	PMC->WaitUntilFBDI(3, 1, 1, TRIGGEREDGETYPE::RISING_EDGE);

	//load xbot 1 move to 900,60
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//load xbot 1 move to 900,660
	PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.66, 0, 1, 10, 0);
	this_thread::sleep_for(2000ms);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - DO set on cmdlb, DI as reset, read DO from PMC
void Example14_DOcmdlb(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//config DO1 to set on a cmdlb (3)
	PMC_USINT DoID_array[1] = { 1 };
	PMC_USINT xbotID_array[1] = { 1 };
	PMC_UINT cmdLB_array[1] = { 3 };
	PMC_USINT type_array[1] = { 0 };
	PMCRTN rtn = PMC->ConfigDO2CmdLb(1, DoID_array, xbotID_array, cmdLB_array, type_array);

	//cmd label 3
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//wait until DO1 from PMC is high
	DigitalSignalRtn Signal1;
	do
	{
		Signal1 = PMC->ReadDigitalSignalFromPMC(1);
	} while (Signal1.level == false);

	//setup DI 1 as reset for DO 1
	PMC_USINT diID_array[1] = { 1 };
	PMC_USINT rst_DoID_array[1] = { 1 };
	PMCRTN rtn2 = PMC->ConfigDI2Reset(1, diID_array, rst_DoID_array);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);
	this_thread::sleep_for(5ms);

	//read DO1
	DigitalSignalRtn Signal2 = PMC->ReadDigitalSignalFromPMC(1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - DO set on displacement
void Example15_DOdisplacement(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//config DO1 to set on a x > 500 
	PMC_USINT DoID_array[1] = { 1 };
	PMC_USINT xbotID_array[1] = { 1 };
	PMC_USINT type_array[1] = { 0 };
	PMC_USINT mode_array[1] = { 0 };
	PMC_REAL threshold_array[1] = { 0.5 };
	PMC_REAL xfactor_array[1] = { 0 };
	PMC_REAL yfactor_array[1] = { 0 };
	PMC->ConfigDO2Disp(1, DoID_array, xbotID_array, type_array, mode_array, threshold_array, xfactor_array, yfactor_array);

	//move xbot 1 to 900,60
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 0.1, 10, 0);

	//wait until DO1 is high
	DigitalSignalRtn Signal1;
	do
	{
		Signal1 = PMC->ReadDigitalSignalFromPMC(1);
	} while (Signal1.level == false);
	printf("Xbot passed 500mm\n");

	//setup DI 1 as reset for DO 1
	PMC_USINT diID_array[1] = { 1 };
	PMC_USINT rst_DoID_array[1] = { 1 };
	PMCRTN rtn2 = PMC->ConfigDI2Reset(1, diID_array, rst_DoID_array);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);
	this_thread::sleep_for(5ms);

	//read DO1
	DigitalSignalRtn Signal2 = PMC->ReadDigitalSignalFromPMC(1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - DO set on motion
void Example16_DOmotion(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//config DO1 to set on xbot 1 motion 
	PMC_USINT DoID_array[1] = { 1 };
	PMC_USINT xbotID_array[1] = { 1 };
	PMC_USINT type_array[1] = { 0 };
	PMC->ConfigDO2Motion(1, DoID_array, xbotID_array, type_array);

	//move xbot 1 to 900,60
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.06, 0, 1, 10, 0);

	//wait until DO1 is high
	DigitalSignalRtn signal1;
	do
	{
		signal1 = PMC->ReadDigitalSignalFromPMC(1);
	} while (signal1.level == false);

	//setup DI 1 as reset for DO 1
	PMC_USINT diID_array[1] = { 1 };
	PMC_USINT rst_DoID_array[1] = { 1 };
	PMCRTN rtn2 = PMC->ConfigDI2Reset(1, diID_array, rst_DoID_array);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);
	this_thread::sleep_for(5ms);

	//read DO1
	DigitalSignalRtn Signal2 = PMC->ReadDigitalSignalFromPMC(1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 2 xbot sample cam set as cam 128 (position interval = 1 mm) - cam mode, cam mode advanced
void Example17_cam(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move async move to 60,60 and 60,180
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC_REAL posx_array[2] = { 0.06,0.06 };
	PMC_REAL posy_array[2] = { 0.06,0.18 };
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, posx_array, posy_array);
	PollForAllXbotsState(PMC);

	//setup cam with xbot 2 y as slave to xbot 1 x
	PMC_USINT slaveaxis_array[2] = { 2,0 };
	PMC_USINT camID_array[2] = { 128,0 };
	PMC_USINT masterID_array[2] = { 1,0 };
	PMC_USINT masteraxis_array[2] = { 1,0 };
	PMC->CamModeCtrl(2, 1, 2, 1, slaveaxis_array, camID_array, masterID_array, masteraxis_array);

	//move xbot 1 to (400,60)
	PMC->XYMotion(3, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.4, 0.06, 0, 0.25, 10, 0);

	//move xbot 1 to (60,60)
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 0.25, 10, 0);
	PollForXbotState(PMC,1);

	//disable cam on xbot 2 
	PMC->CamModeCtrl(5, 0, 2, 1, slaveaxis_array, camID_array, masterID_array, masteraxis_array);

	//move to new start position (60,60) and (480,420)
	posx_array[1] = 0.48;
	posy_array[1] = 0.42;
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, posx_array, posy_array);
	PollForAllXbotsState(PMC);

	//setup advanced cam
	slaveaxis_array[0] = 1; slaveaxis_array[1] = 2;
	camID_array[0] = 128; camID_array[1] = 128;
	masterID_array[0] = 1; masterID_array[1] = 1;
	masteraxis_array[0] = 1; masteraxis_array[1] = 1;
	PMC_REAL masteroffset_array[2] = { 0,0 };
	PMC_REAL slaveoffset_array[2] = { 0,0 };
	PMC_REAL masterscaling_array[2] = { 1,2 };
	PMC_REAL slavescaling_array[2] = { 2,1 };
	PMC_USINT cammode_array[2] = { 1,1 };
	PMC_USINT masteroffsetmode_array[2] = { 1,1 };
	PMC->CamModeCtrlAdvanced(6, 1, 2, 2, slaveaxis_array, camID_array, masterID_array, masteraxis_array, masteroffset_array, slaveoffset_array, masterscaling_array, slavescaling_array, cammode_array, masteroffsetmode_array);

	//move xbot 1 to (400,60)
	PMC->XYMotion(7, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.4, 0.06, 0, 0.25, 10, 0);

	//move xbot 1 to (60,60)
	PMC->XYMotion(8, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 0.25, 10, 0);
	PollForXbotState(PMC,1);

	//disable advanced cam
	PMC->CamModeCtrlAdvanced(9, 0, 2, 2, slaveaxis_array, camID_array, masterID_array, masteraxis_array, masteroffset_array, slaveoffset_array, masterscaling_array, slavescaling_array, cammode_array, masteroffsetmode_array);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - jogging, jogging short axis
void Example18_jogging(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 120,120
	PMC->XYMotion(4, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.12, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//jog xbot 1 up and right
	PMC->JogVelocity(1, true, 0.7854, 0.05,10.0);
	this_thread::sleep_for(10000ms);

	//stop xbot 1 jogging
	PMC->JogVelocity(1, false, 0.7854, 0.05, 10.0);
	this_thread::sleep_for(500ms);

	//jog xbot 1 down and left
	PMC->JogVelocity(1, true, 3.927, 0.05, 10.0);
	this_thread::sleep_for(10000ms);

	//stop xbot 1 jogging
	PMC->JogVelocity(1, false, 0.7854, 0.05, 10.0);
	this_thread::sleep_for(500ms);

	//jog xbot 1 counterclockwise (positive Rz)
	PMC->JogShortAxis(1, true, 3, 0.001);
	this_thread::sleep_for(7500ms);

	//stop xbot 1 jogging
	PMC->JogShortAxis(1, false, 3, 0.001);
	this_thread::sleep_for(500ms);

	//jog xbot 1 clockwise (negative Rz)
	PMC->JogShortAxis(1, true, 3, -0.001);
	this_thread::sleep_for(7500ms);

	//stop xbot 1 jogging
	PMC->JogShortAxis(1, false, 3, -0.001);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

// 1 flyway (actual physical) w/ 1 xbots - force mode ctrl,read payload,read flyway temps
void Example19_force(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//activate force mode control for xbot 1 in x axis 0 Newtons
	PMC->ForceModeCtrl(0,2,0, 1, 0, 0, 0, 0);
	PollForXbotState(PMC,1);

	//get payload of xbot 1
	PayloadRtn payload = PMC->WeighXbot(1,1.0,0);

	//lread power usage,CPU temp,amplifier temp, and motor temp of flyway 1
	FlywayTempRtn flywaytemp = PMC->GetFlywayStatus(1);

	this_thread::sleep_for(10000ms);

	//exit force mode
	PMC->ForceModeCtrl(0,0,0, 1, 0, 0, 0, 0);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

// 1 flyway (actual physical) w/ 1 xbots - DO set on force
void Example20_DOforce(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to 120,120
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.12, 0, 1, 10, 0);

	//config DO1 to set on xbot 1 force X > 3 N
	PMC_USINT DoID_array[1] = { 1 };
	PMC_USINT xbotID_array[1] = { 1 };
	PMC_USINT type_array[1] = { 0 };
	PMC_USINT axis_array[1] = { 1 };
	PMC_REAL threshold_array[1] = { 3 };
	PMC->ConfigDO2Force(1, DoID_array, xbotID_array, type_array, axis_array, threshold_array);

	//wait until  DO 1 is high
	DigitalSignalRtn Signal1;
	do
	{
		Signal1 = PMC->ReadDigitalSignalFromPMC(1);
	} while (Signal1.level == false);
	printf("X force is > 3 N\n");

	//setup DI 1 as reset for DO 1
	PMC_USINT diID_array[1] = { 1 };
	PMC_USINT rst_DoID_array[1] = { 1 };
	PMCRTN rtn2 = PMC->ConfigDI2Reset(1, diID_array, rst_DoID_array);

	//set DI 1 to 0
	PMC->SendDigitalSignalToPMC(1, false);
	this_thread::sleep_for(1ms);

	//set DI 1 to 1
	PMC->SendDigitalSignalToPMC(1, true);
	this_thread::sleep_for(5ms);

	//read DO1
	DigitalSignalRtn Signal2 = PMC->ReadDigitalSignalFromPMC(1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//any amount of xbots 
void Example21_startupPMS(PMC_Acontis_API* PMC)
{
	StartUpPMSRtn Return = PMC->StartUpPlanarMotorSystem();
}

PMC_REAL Example22_y_stream_pos = 0;
struct PMCPointerPlusEventPointer
{
	PMC_Acontis_API* PMCPointer;
	void* EcEventPointer;
};
//5x2 flyways 9 xbots (y axis feedback must be enabled) - StreamModeCtrl,WriteStream,ConfigFBStream,read feedback
void Example22_streaming(PMC_Acontis_API* PMC,void* EcEventPointer)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//reset streaming positions
	Example22_y_stream_pos = 0;
	for (int xbotid = 1; xbotid < 10; xbotid++)
	{
		PMC->WriteStream(xbotid, 1, 0);
		PMC->WriteStream(xbotid, 2, 0);
		PMC->WriteStream(xbotid, 3, 0);
		PMC->WriteStream(xbotid, 4, 0);
		PMC->WriteStream(xbotid, 5, 0);
		PMC->WriteStream(xbotid, 6, 0);
	}

	//move all xbots to bottom of flyways
	PMC_USINT xbotID_array[9] = { 1,2,3,4,5,6,7,8,9 };
	PMC_REAL posx_array[9] = { 0.06,0.18,0.30,0.42,0.54,0.66,0.78,0.9,1.02 };
	PMC_REAL posy_array[9] = { 0.06,0.06,0.06,0.06,0.06,0.06,0.06,0.06,0.06};
	PMC->AutoDrivingMotion(9,0,false,0, xbotID_array, posx_array, posy_array);
	PollForAllXbotsState(PMC);

	//config feedback stream of xbot 1
	PMC_USINT StmID = 1;
	PMC_USINT XbotID = 5;
	PMC_USINT FBmode = 0;
	PMC->ConfigFBStream(1, &StmID, &XbotID, &FBmode);

	//start streaming for all 9 xbot's y axis
	PMC_USINT stmID_array[9] = { 1,2,3,4,5,6,7,8,9 };
	PMC_USINT stmAxis_array[9] = { 2,2,2,2,2,2,2,2,2 };
	PMC_REAL offsetX_array[9] = {0,0,0,0,0,0,0,0,0};
	PMC_REAL offsetY_array[9] = {0,0,0,0,0,0,0,0,0};
	PMC->StreamModeCtrl(1, 9,0, xbotID_array, stmID_array, stmAxis_array,offsetX_array,offsetY_array);

	//start the 1ms streaming timer task 
	PMCPointerPlusEventPointer PMCPlusEvent;
	PMCPlusEvent.PMCPointer = PMC;
	PMCPlusEvent.EcEventPointer = EcEventPointer;
	void* TimerTaskHandle = OsCreateThread((EC_T_CHAR*)"PMCStreamTask", Example22_streamingtimerhandler, 0,
            98, 0x8000, (void*) &PMCPlusEvent);

	//wait until the xbots have reached the top of the flyways
	do
	{
		PMC_REAL read_y_pos = PMC->ReadStreamFeedback(1, 2).FeedbackValue;
		this_thread::sleep_for(1ms);
	} while (Example22_y_stream_pos < 0.36);

	//turn off streaming
	PMC->StreamModeCtrl(0, 9,0, xbotID_array, stmID_array, stmAxis_array,offsetX_array,offsetY_array);

	//turn off timer thread
	OsDeleteThreadHandle(TimerTaskHandle);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//streaming timer task
void Example22_streamingtimerhandler(void* context)
{
	do
	{
		OsWaitForEvent(static_cast<PMCPointerPlusEventPointer*>(context)->EcEventPointer, 1000);
		Example22_y_stream_pos = Example22_y_stream_pos + 0.00001;
		for (int xbotid = 1; xbotid < 10; xbotid++)
		{
			static_cast<PMCPointerPlusEventPointer*>(context)->PMCPointer->WriteStream(xbotid, 2, Example22_y_stream_pos);
		}
	} while (Example22_y_stream_pos < 0.36);
}

//4x3 flyways 4 xbots - HoldForPMCState, HoldForXbot(s)Idle, HoldForXbot(s)State
void Example23_autodrivingvelocity(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move all xbots to bottom of flyways (quickly)
	PMC_USINT xbotID_array[4] = { 1,2,3,4 };
	PMC_REAL posx_array[4] = { 0.06,0.3,0.54,0.78 };
	PMC_REAL posy_array[4] = { 0.06,0.06,0.06,0.06 };
	PMCRTN rtn1 = PMC->AutoDrivingMotionVelocity(4,0,false,0, xbotID_array, posx_array, posy_array, 2, 20);
	PollForAllXbotsState(PMC);

	//move all xbots to top of flyways (slowly)
	posy_array[0] = 0.66; posy_array[1] = 0.66; posy_array[2] = 0.66; posy_array[3] = 0.66;
	PMCRTN rtn2 = PMC->AutoDrivingMotionVelocity(4,0,false,0, xbotID_array, posx_array, posy_array, 0.1, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//1 flyway 1 xbot (actual physical) - autoloading delete,create,activate,holdforzoneready,unload
void Example24a_autoloading_sending(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//delete any existing zone
	PMC->AutoLoadingZone_Delete(0);

	//move xbot to starting position
	PMC->XYMotion(2, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//create an autoloading unloading zone on the top left edge (75,240) of the flyway 
	PMCRTN rtn = PMC->AutoLoadingZone_Create(1, ALZONETYPE::UNLOAD_ZONE, ALZONEUNLOADMODE::STOP_BEFORE_UNLOAD,0,0, 0.075, 0.24, 0.12, 0.15, 0.12, 0.12, 1, 10,0);

	//activate the unloading zone
	PMCRTN rtn1 = PMC->AutoLoadingZone_Activate(1,0,0);

	//hold until the unloading zone is ready to receive a new xbot
	AutoLoadZoneStatusReturn ZoneStatusRtn;
	do
	{
		ZoneStatusRtn = PMC->AutoLoadingZone_GetZoneStatus(1);
	} while (ZoneStatusRtn.ReadyForNextXBot == false);

	//move the xbot into the unloading zone
	PMC->XYMotion(6, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, ZoneStatusRtn.UnloadingEntryXposm, ZoneStatusRtn.UnloadingEntryYposm, 0, 1, 10, 0);

	//unload the xbot
	PMC->AutoLoadingZone_UnloadXbot(1, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//1 flyway 1 xbot (actual physical, xbot not on flyway at beginning of example) - autoloading delete,create,activate,holdforzoneready,loadingzoneclear 
void Example24b_autoloading_receiving(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//delete any existing zones
	PMC->AutoLoadingZone_Delete(0);

	//create an autoloading loading zone on the top left edge (75,240) of the flyway
	PMC->AutoLoadingZone_Create(1, ALZONETYPE::LOAD_ZONE, ALZONEUNLOADMODE::STOP_BEFORE_UNLOAD,0,0, 0.075, 0.24, 0.12, 0.15, 0.12, 0.12, 1, 10,0);

	//activate the loading zone
	PMC->AutoLoadingZone_Activate(1,0,0);

	//user should place xbot in loading zone now
	printf("Loading zone ready, please place xbot in loading zone\n");

	//wait until the loading zone has received a new xbot
	AutoLoadZoneStatusReturn ZoneStatusRtn;
	do
	{
		ZoneStatusRtn = PMC->AutoLoadingZone_GetZoneStatus(1);
	} while (ZoneStatusRtn.ReadyForNextXBot == false);

	//move xbot out of the zone
	PMC->XYMotion(5, ZoneStatusRtn.LoadedXBotID, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::XTHENY, 0.18, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//tell the loading zone that the xbot has moved clear 
	PMC->AutoLoadingZone_LoadingZoneClear(1,0,0);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//4x3 flyways 1 xbot - MoverStereotype Define, Assign, ReadDef
void Example25_stereotypes(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//linear motion to 60,60
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);

	//define an unladen, fast stereotype as movertype 0 stereotype 1
	MoverStereotypeData stereotypedata1;
	stereotypedata1.payloadCGXm = 0; stereotypedata1.payloadCGYm = 0; stereotypedata1.payloadCGZm = 0;
	stereotypedata1.performanceLevel = 3; stereotypedata1.payloadkg = 0;
	stereotypedata1.payloadPositiveXmFromXBOTCenter = 0;
	stereotypedata1.payloadNegativeXmFromXBOTCenter = 0;
	stereotypedata1.payloadPositiveYmFromXBOTCenter = 0;
	stereotypedata1.payloadNegativeYmFromXBOTCenter = 0;
	PMC->MoverStereotype_Define(MOVERTYPE::M3_06, 1, stereotypedata1);

	//read movertype 0 stereotype 1
	MoverStereotypeDefinitionReturn stereotypeRtn1 = PMC->MoverStereotype_ReadDef(MOVERTYPE::M3_06, 1);

	//assign movertype 0 stereotype 1 to xbot 1
	PMC->MoverStereotype_Assign(1, 1,0);

	//linear motion to 900,660
	MotionRtn motionrtn1 = PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.9, 0.66, 0, 2, 20, 0);
	PollForXbotState(PMC,1);

	//define a laden slow stereotype as movertype 0 stereotype 2
	MoverStereotypeData stereotypedata2;
	stereotypedata2.payloadCGXm = 0; stereotypedata2.payloadCGYm = 0; stereotypedata2.payloadCGZm = 0.03;
	stereotypedata2.performanceLevel = 0; stereotypedata2.payloadkg = 2;
	stereotypedata2.payloadPositiveXmFromXBOTCenter = 0.12;
	stereotypedata2.payloadNegativeXmFromXBOTCenter = -0.12;
	stereotypedata2.payloadPositiveYmFromXBOTCenter = 0.12;
	stereotypedata2.payloadNegativeYmFromXBOTCenter = -0.12;
	PMC->MoverStereotype_Define(MOVERTYPE::M3_06, 2, stereotypedata2);

	//read movertype 0 stereotype 2
	MoverStereotypeDefinitionReturn stereotypeRtn2 = PMC->MoverStereotype_ReadDef(MOVERTYPE::M3_06, 2);

	//assign movertype 0 stereotype 2 to xbot 1
	PMC->MoverStereotype_Assign(2, 1,0);

	//linear motion to 60,60
	MotionRtn motionrtn2 = PMC->XYMotion(9, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 2, 20, 0);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//at least 2 flyways (physical) - GetFlywaySerialNum, PMC_GetPMCSerialNum, PMC_GetPMCVersion
void Example26_serialnumbers(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//read software version number of the PMC
	VersionRtn PMCSoftwareVersion = PMC->GetPMCVersion();

	//read serial number of the PMC
	SerialNumRtn PMCSerial = PMC->GetPMCSerialNum();

	//read serial number of flyway 1
	SerialNumRtn FlywaySerial1 = PMC->GetFlywaySerialNum(1);

	//read serial number of flyway 2
	SerialNumRtn FlywaySerial2 = PMC->GetFlywaySerialNum(2);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways 1 xbot - LevitationLandw/Speed
void Example27_levitatelandspeed(PMC_Acontis_API* PMC)
{
	long long levland_times[10];

	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	auto start_time = system_clock::now();

	//Land in 1.6s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LAND, 0);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_LANDED);
	levland_times[0] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Levitate in 1.6s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LEVITATE, 0);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_IDLE);
	levland_times[1] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Land in 0.8s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LAND, 1);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_LANDED);
	levland_times[2] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Levitate in 0.8s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LEVITATE, 1);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_IDLE);
	levland_times[3] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Land in 0.4s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LAND, 2);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_LANDED);
	levland_times[4] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Levitate in 0.4s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LEVITATE, 2);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_IDLE);
	levland_times[5] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Land in 0.2s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LAND, 3);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_LANDED);
	levland_times[6] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Levitate in 0.2s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LEVITATE, 3);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_IDLE);
	levland_times[7] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Land in 0.1s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LAND, 4);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_LANDED);
	levland_times[8] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//Levitate in 0.1s
	PMC->LevitationCtrlSpeed(1, LEVITATEOPTIONS::LEVITATE, 4);
	PollForXbotState(PMC,1, XBOTSTATE::XBOT_IDLE);
	levland_times[9] = duration_cast<milliseconds>(system_clock::now() - start_time).count();

	//wait for all xbots to be idle
PollForAllXbotsState(PMC);
}

//2x1 flyways 2 xbots (actual physical) - ZoneCtrl, GetStatus
void Example28a_zoneunloading(PMC_Acontis_API* PMC)
{
	//move to starting position	
	PMC_USINT xbotID_array[2] = { 1,2 };
	PMC_REAL posx_array[2] = { 0.06,0.18 };
	PMC_REAL posy_array[2] = { 0.06,0.06 };
	PMC->AutoDrivingMotion(2,0,false,0, xbotID_array, posx_array, posy_array);
	PollForAllXbotsState(PMC);

	//move xbot 2 into zone 2 (flyway 2)
	PMC->XYMotion(2, 2, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, 0.12, 0, 1, 10, 0);
	PollForXbotState(PMC,2);

	//deactivate zone 2 (flyway 2)
	PMC->Zone_ZoneCtrl(2, ZONEOPERATION::DEACTIVATE_ZONE);

	//tell user that they can remove the xbot in the zone
	PollForXbotState(PMC,2, XBOTSTATE::XBOT_DISABLED);
	printf("User can now remove xbot 2 from flyway 2 \n");

	//wait for user to remove xbot
	ZoneStatusReturn Zone_Status;
	do
	{
		Zone_Status = PMC->Zone_GetStatus(2);
	} while (Zone_Status.NumXbots != 0);

	this_thread::sleep_for(100ms);

	//activate zone once user is done removing the xbot
	PMC->Zone_ZoneCtrl(2, ZONEOPERATION::ACTIVATE_ZONE);

	//poll until zone reactivates
	ZoneStatusReturn Zone_status;
	do
	{
		Zone_status = PMC->Zone_GetStatus(2);
	} while (Zone_status.State != ZONESTATE::ACTIVATED_FENCED);

	this_thread::sleep_for(1000ms);
}

//2x1 flyways 2 xbots (actual physical, shoud be run after 27a) - ZoneCtrl, FenceCtrl, GetStatus 
void Example28b_zoneloading(PMC_Acontis_API* PMC)
{
	//move xbot 1 to side
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.18, 0, 1, 10, 0);

	//deactivate zone 2 (flyway 2)
	PMCRTN rtn = PMC->Zone_ZoneCtrl(2, ZONEOPERATION::DEACTIVATE_ZONE);

	//tell user that they can now put the xbot into the zone
	printf("User can place xbot 2 back onto flyway 2\n");

	//read zone info
	ZoneStatusReturn Zone_status;
	do
	{
		Zone_status = PMC->Zone_GetStatus(2);
	} while (Zone_status.NumXbots == 0);

	this_thread::sleep_for(100ms);

	//activate zone once user is done adding the xbot
	PMC->Zone_ZoneCtrl(2, ZONEOPERATION::ACTIVATE_ZONE);
	PollForXbotState(PMC,Zone_status.XbotIDs[0]);

	this_thread::sleep_for(100ms);

	//turn off fence on zone 2
	PMC->Zone_Fencing(2, FENCEOPERATION::REMOVE_FENCE);

	//move xbot in zone 2 to side
	PMC->XYMotion(8, Zone_status.XbotIDs[0], POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::YTHENX, 0.06, 0.06, 0, 1, 10, 0).PmcRtn;
}

//any number of flyways and xbots (real physical, with at least 1 xbot having suffered a tracking error) - GetAllAccidentXbots, RecoverAccidentXbot
//a tracking error can be triggered by holding a xbot down for about 3 seconds
void Example29_recoveryaccident(PMC_Acontis_API* PMC)
{
	//wait until a xbot has suffered a tracking error
	ReadNumXbotsRtn num_accident_xbots;
	do
	{
		num_accident_xbots = PMC->ReadNumAccidentXbots();
	} while (num_accident_xbots.nXbots == 0);

	//get IDs of all xbots that have suffered tracking errors
	AccidentXbotRtn accident_xbots = PMC->GetAllAccidentXbots();

	//recover the accident xbots
	for (int i = 0; i < num_accident_xbots.nXbots; i++)
	{
		PMC->RecoverAccidentXbot(accident_xbots.XbotIDs[i], 0, 0);
		PollForXbotState(PMC, accident_xbots.XbotIDs[i]);
	}

	PollForAllXbotsState(PMC);
}

//2x1 flyways 1 xbot (actual physical) with border 1 on the bottom edge of the 2 flyways - GetBorderStatus, ReadNumIncomingXbots, GetIncomingXbots
//additional user controlled PMC with 2x1 flyways with border 1 on the top edge, xbot starts on the user controlled PMC
void Example30_incoming(PMC_Acontis_API* PMC)
{
	//verify status of the boundary 
	BorderStatusRtn border_status = PMC->GetBorderStatus(1);
	if (border_status.BorderStatus != BORDERSTATUS::READY)
	{
		printf("Border is not ready, test aborted \n");
		return;
	}

	//wait until an xbot shows up on the boundary (user needs to manually move xbot over boundary using the other PMC)
	ReadNumXbotsRtn num_incoming_xbots;
	do
	{
		num_incoming_xbots = PMC->ReadNumIncomingXbots();
	} while (num_incoming_xbots.nXbots == 0);

	//get ID of the incoming xbot
	IncomingXbotsRtn incoming_xbot = PMC->GetIncomingXbots();

	//move xbot around the PLC controlled flyways
	PMC->XYMotion(4, incoming_xbot.XbotIDs[0], POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.18, 0, 1, 10, 0);
	PMC->XYMotion(5, incoming_xbot.XbotIDs[0], POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.18, 0, 1, 10, 0);

	//move xbot back over the boundary
	PMC->XYMotion(6, incoming_xbot.XbotIDs[0], POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, -0.12, 0, 1, 10, 0);
}

//any flyway configuration 50 xbots - PMC_ConfigFBStreamExtended, PMC_ReadStreamFeedbackExtended, PMC_ReadXbotSpeed
void Example31_extendedfeedback(PMC_Acontis_API* PMC)
{
	PMC_USINT xbotid_array[50];
	PMC_USINT fbmode_array[50];
	for (int i = 0; i < 50; i++)
	{
		xbotid_array[i] = i + 1;
		fbmode_array[i] = 0;
	}

	PMCRTN rtn = PMC->ConfigFBStreamExtended(50, xbotid_array, fbmode_array);

	int count = 0;
	while (count < 300)
	{
		count++;
		//Read xbot 31,42,50 position every 100 ms while user moves the xbot using the PMT
		float x31;
		float y31;
		float Rz31Speed;
		x31 = PMC->ReadStreamFeedbackExtended(31, 1).FeedbackValue;
		y31 = PMC->ReadStreamFeedbackExtended(31, 2).FeedbackValue;
		Rz31Speed = PMC->ReadXbotSpeed(31).SpeedRz;

		float x42;
		float y42;
		float Rz42Speed;
		x42 = PMC->ReadStreamFeedbackExtended(42, 1).FeedbackValue;
		y42 = PMC->ReadStreamFeedbackExtended(42, 2).FeedbackValue;
		Rz42Speed = PMC->ReadXbotSpeed(42).SpeedRz;

		float x50;
		float y50;
		float Rz50Speed;
		x50 = PMC->ReadStreamFeedbackExtended(50, 1).FeedbackValue;
		y50 = PMC->ReadStreamFeedbackExtended(50, 2).FeedbackValue;
		Rz50Speed = PMC->ReadXbotSpeed(50).SpeedRz;

		printf("31 = %dmm,%dmm,%dmrad/s: 42 = %dmm,%dmm,%dmrad/s: 50 = %dmm,%dmm,%dmrad/s\n", (int)(x31 * 1000), (int)(y31 * 1000),(int)(Rz31Speed*1000), (int)(x42 * 1000), (int)(y42 * 1000), (int)(Rz42Speed * 1000), (int)(x50 * 1000), (int)(y50 * 1000), (int)(Rz50Speed * 1000));

		this_thread::sleep_for(100ms);
	}
};

//2x1 flyways 1 xbots - ZoneFencing,DefineZone,ZoneGetStatus
void Example32_zonefencing(PMC_Acontis_API* PMC)
{
	//move xbot 1 to starting position
	PMC->XYMotion(1, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.06, 0, 1, 10, 0);
	PollForXbotState(PMC,1);

	//define zone 6 as the boundary between the two flyways
	PMC->Zone_DefineZone(6,0, 0.18, 0, 0.30, 0.24,0,0);

	//turn on fence on zone 6
	PMC->Zone_Fencing(6, FENCEOPERATION::BUILD_FENCE);

	//get status of zone 6
	ZoneStatusReturn zone_status = PMC->Zone_GetStatus(6);

	//move xbot 1 to other side of flyways (will hit fence)
	PMC->XYMotion(5, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.42, 0.18, 0, 1, 10, 0);

	//wait for xbot to hit fence
	this_thread::sleep_for(3000ms);

	//turn off fence on zone 6 to let the xbot through
	PMC->Zone_Fencing(6, FENCEOPERATION::REMOVE_FENCE);

	//set speed override through zone 6 to 0.1 
	PMC->Zone_OverrideZone(6,0, 0.1, 1);

	PollForXbotState(PMC,1);

	//set speed override in zone 6 back to 1
	PMC->Zone_OverrideZone(6,0, 1, 1);
}

//Initial setup for Example33_StarWheel
void Example33_StarWheelSetup(PMC_Acontis_API* PMC)
{
	PMC_REAL Disc_Radius = 0.3;
	PMC_REAL Disc_X = 0.36;
	PMC_REAL Disc_Y = 0.36;
	PMC_REAL Clearance_Space = 0.15;

	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//delete all star wheels
	PMC->Star_DeleteStar(0);

	//setup star wheel module
	PMC_REAL vials[4] = { 0,PI / 2,PI,3 * PI / 2 };
	PMC->Star_CreateStar(1, 1, 100, Disc_Radius, 5, 10, Disc_X, Disc_Y, Disc_X + Disc_Radius, 0.06, Disc_X - Clearance_Space, Disc_Y + Disc_Radius, 0, PI / 2, 4, vials);

	//setup macro 128
	PMC->ClearMacro(128);
	PMC->XYMotion(0, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.18, Disc_Y + Disc_Radius, 1, 1, 20, 0);
	PMC->ArcMotionTarget(0, 128, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 20, 0.06, Disc_Y + Disc_Radius - 0.12, 0.12);
	PMC->XYMotion(0, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.06, 0.18, 1, 1, 20, 0);
	PMC->ArcMotionTarget(0, 128, POSITIONMODE::ABSOLUTE_MOTION, ARCTYPE::MINORARC, ARCDIRECTION::COUNTERCLOCKWISE, 1, 1, 20, 0.18, 0.06, 0.12);
	PMC->XYMotion(0, 128, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, Disc_X + Disc_Radius, 0.06, 0, 2, 20, 0);
	PMC->SaveMacro(128);

	//move xbots to starting positions
	PMC_USINT xbotids[6] = { 1,2,3,4,5,6 };
	PMC_REAL PosXs[6] = { 0.06,0.06,0.06,0.06,0.06,0.06 };
	PMC_REAL PosYs[6] = { 0.06,0.18,0.30,0.42,0.54,0.66 };
	PMCRTN rtn = PMC->AutoDrivingMotion(6,0,false,0, xbotids, PosXs, PosYs);
	PollForAllXbotsState(PMC);

	//setup xbot queueing
	for (int i = 0; i < 6; i++)
	{
		PMC->XYMotion(0, i + 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::YTHENX, Disc_X + Disc_Radius, 0.06, 0, 2, 20, 0);
	}

	//setup streaming to virtual xbot 100
	PMC_USINT xbotid = 100;
	PMC_USINT stmid = 1;
	PMC_USINT stmaxis = 32;
	PMC_REAL offsetX = 0;
	PMC_REAL offsetY = 0;
	PMC->StreamModeCtrl(1, 1,0, &xbotid, &stmid, &stmaxis,&offsetX,&offsetY);
}

//streaming timer task
PMC_REAL Example33_wheel_angle = 0;
PMC_REAL Example33_rotation_speed = 1.0;
PMC_REAL Example33_cycle_time = 0.001;
void Example33_streamingtimerhandler(void* context)
{
	while(1)
	{
		OsWaitForEvent(static_cast<PMCPointerPlusEventPointer*>(context)->EcEventPointer,3000);
		//write wheel angle
		static_cast<PMCPointerPlusEventPointer*>(context)->PMCPointer->WriteStream(1, 6, Example33_wheel_angle);

		//increment wheel angle
		Example33_wheel_angle = Example33_wheel_angle + Example33_rotation_speed * Example33_cycle_time;

		//2PI wrap around handling
		if (Example33_wheel_angle > 2 * PI)
		{
			Example33_wheel_angle = Example33_wheel_angle - 2 * PI;
		}
	}
}

//3x3 flyways 6 xbots - star wheel module demo CreateStar, DeleteStar, GetStarStatus, SendXbotToStar, StarExitClear
void Example33_StarWheel(PMC_Acontis_API* PMC,void* EcEventPointer)
{
	//reset wheel angle
	Example33_wheel_angle = 0;
	PMC->WriteStream(1, 6, Example33_wheel_angle);
	int next_xbot = 1;

	//initial setup
	Example33_StarWheelSetup(PMC);

	//start the 1ms streaming timer task 
	PMCPointerPlusEventPointer PMCPlusEvent;
	PMCPlusEvent.PMCPointer = PMC;
	PMCPlusEvent.EcEventPointer = EcEventPointer;
	void* TimerTaskHandle = OsCreateThread((EC_T_CHAR*)"PMCStreamTask", Example33_streamingtimerhandler, 0,
            98, 0x8000, (void*) &PMCPlusEvent);

	while (1)
	{
		//check if xbot is in exit, if it is return it to queue and clear the star wheel's exit
		StarStatusReturn check_status = PMC->Star_GetStarStatus(1);
		if (check_status.ExitState == 1)
		{
			PMC->RunMacro(0, 128, check_status.ExitXID);
			PMC->Star_StarExitClear(1);
		}

		//check if next xbot in queue is ready to go, if it is send it to the star wheel
		XBOTSTATE xbot_state = PMC->ReadXbotState(next_xbot).State;
		if (xbot_state == XBOTSTATE::XBOT_IDLE)
		{
			PMC->Star_SendXbotToStar(1, next_xbot);
			next_xbot++;
			if (next_xbot > 6)
			{
				next_xbot = 1;
			}
		}
	}
}

//1x1 flyways 1 xbots - SingleAxisMotion,RotaryMotion,RotaryMotionSpin
void Example34_RotaryMotion(PMC_Acontis_API* PMC)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//move xbot 1 to x = 120mm
	PMC->SingleAxisMotion(0, 1, POSITIONMODE::ABSOLUTE_MOTION,0, 1, 0.12, 0, 1, 10);

	//move xbot 1 to y = 180mm
	PMC->SingleAxisMotion(0, 1, POSITIONMODE::ABSOLUTE_MOTION,0, 2, 0.18, 0, 1, 10);

	//move xbot 1 to down 60 mm in the y axis
	PMC->SingleAxisMotion(0, 1, POSITIONMODE::RELATIVE_MOTION,0, 2, -0.06, 0, 1, 10);
	PollForXbotState(PMC, 1);

	//rotate xbot 1 five times in the positive(counter clockwise) direction
	PMC->RotaryMotion(0, 1, 0, 1, 0, 10 * PI, PI, 10);
	PollForXbotState(PMC, 1);

	//rotate xbot 1 for 10 seconds in the negative (clockwise) direction
	PMC->RotaryMotionSpin(0, 1,0, 0, -PI, 10, 10);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//2x1 flyways 1 xbot (actual physical, left flyway set as master, right flyway set as sector 1) - PMC_Sector_Activate, PMC_Sector_Deactivate, PMC_Sector_Recover, PMC_Sector_GetStatus
void Example35_Sectors(PMC_Acontis_API* PMC)
{
	//move xbot 1 to the non sector flyway
	PMC->XYMotion(0, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.12, 0, 1, 10, 0);
	PollForAllXbotsState(PMC);

	//deactivate sector 1
	PMC->Sector_Deactivate(1);
	//wait for sector 1 to deactivate
	Sector_GetStatusRtn SectorStatus;
	do
	{
		SectorStatus = PMC->Sector_GetStatus(1);
	} while (SectorStatus.State != 2);

	//tell user to disconnect sector 1
	printf("Disconnect Sector 1 flyway\n");

	//try to move xbot 1 to the disconnected flyway
	PMC->XYMotion(0, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.36, 0.12, 0, 1, 10, 0);

	//wait for sector 1 to be disconnected
	do
	{
		SectorStatus = PMC->Sector_GetStatus(1);
	} while (SectorStatus.State != 1);

	this_thread::sleep_for(500ms);

	//tell user to reconnect sector 1
	printf("Reconnect Sector 1 flyway\n");

	this_thread::sleep_for(500ms);

	//wait for sector 1 to be reconnected
	do
	{
		SectorStatus = PMC->Sector_GetStatus(1);
	} while (SectorStatus.State != 2);

	this_thread::sleep_for(500ms);

	//activate sector once user has reconnected the flyway
	PMC->Sector_Activate(1);

	//wait for sector 1 to activate
	do
	{
		SectorStatus = PMC->Sector_GetStatus(1);
	} while (SectorStatus.State != 6);

	this_thread::sleep_for(100ms);

	//recover sector once the sector is done activating
	PMC->Sector_Recover(1);

	//done once the xbot reaches the sector flyway
	PollForAllXbotsState(PMC);
}

//any combination of xbots and flyways - SetDateAndTime
void Example36_SetDateAndTime(PMC_Acontis_API* PMC)
{
	//get the PC local time
	time_t curr_time;
	curr_time = time(NULL);
	tm* tm_local = localtime(&curr_time);

	//send the PC local time to the PMC (note that localtime return month as 0 indexed while the PMC expects month as 1 indexed and localtime returns year as years since 1900)
	PMC->SetDateAndTime(tm_local->tm_year + 1900, tm_local->tm_mon + 1, tm_local->tm_mday, tm_local->tm_hour, tm_local->tm_min, tm_local->tm_sec);
}

//3x3 flyways 1 xbot - DeleteGCode,SaveGCode,ReadGCode,GetGCodeIDs,RunGCode. G-code file 'GCodeDemo.txt' must be on disc in the DemoFilesFolder.  
void FileExample01_Gcode(PMC_Acontis_API* PMC, std::string DemoFilesFolder)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//Read testing G-code file from disk 
	ifstream GCodeFile;
	unsigned char sent_Gcode_data[200000];
	GCodeFile.open(DemoFilesFolder + "/GCodeDemo.txt",ios::binary);
	GCodeFile.read((char*)sent_Gcode_data, 200000);
	int sent_data_size = GCodeFile.gcount();
	GCodeFile.close();

	//Delete G-code file ID 1
	PMC->DeleteGCode(1);

	//Send the testing G-code file to the PMC
	PMCRTN rtn = PMC->SaveGCode(1, sent_data_size, sent_Gcode_data);

	//Read back the G-code file from the PMC
	GCodeRtn GRtn = PMC->ReadGCode(1);

	//Get the IDs of the G-code files on the PMC
	GCodeIDRtn IDRtn = PMC->GetGCodeIDs();

	//Run the testing G-code file
	PMC->RunGCode(0, 1, 1);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//any combination of flyways and xbots - GetErrorLog, GetWarningLog. Any existing 'warning_log.txt' or 'error_log.txt' file in DemoFilesFolder will be overwritten
void FileExample02_ReadLogs(PMC_Acontis_API* PMC, string DemoFilesFolder)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//get the PMC warning log
	LogRtn warninglog = PMC->GetWarningLog();

	//write the warning log to disk
	ofstream warninglogfile;
	warninglogfile.open(DemoFilesFolder + "/warning_log.txt",ios::binary | ios::trunc);
	warninglogfile.write((char*)warninglog.Bytes, warninglog.nBytes);
	warninglogfile.close();

	this_thread::sleep_for(1000ms);

	//get the PMC error log
	LogRtn errorlog = PMC->GetErrorLog();

	//write the error log to disk
	ofstream errorlogfile;
	errorlogfile.open(DemoFilesFolder + "/error_log.txt", ios::binary | ios::trunc);
	errorlogfile.write((char*)errorlog.Bytes, errorlog.nBytes);
	errorlogfile.close();

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//1x1 1 xbot - DeleteTrajectory, SaveTrajectory, ReadTrajectoryHash. Trajectory file 'TrajectoryDemo.txt' must be on disc in the DemoFilesFolder.
void FileExample03_Trajectory(PMC_Acontis_API* PMC, string DemoFilesFolder)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//read trajectory file from disk
	ifstream TrajFile;
	unsigned char TrajData[500000];
	TrajFile.open(DemoFilesFolder + "/TrajectoryDemo.txt", ios::binary);
	TrajFile.read((char*)TrajData, 500000);
	int traj_data_size = TrajFile.gcount();
	TrajFile.close();

	//delete all trajectories from PMC
	PMCRTN deletertn = PMC->DeleteTrajectory(0);

	//deactivate PMC to allow uploading trajectory files
	PMC->DeactivateXbots();
	PollForPMCState(PMC, PMCSTATUS::PMC_INACTIVE);

	//transfer trajectory file to PMC as trajectory 1
	PMCRTN rtn = PMC->SaveTrajectory(1, traj_data_size, 63, 0.010, TrajData);

	//reactivate PMC after uploading the trajectory
	PMC->ActivateXbots(0);
	PollForPMCState(PMC);

	//read the MD5 hash of trajectory 1 (should be 0x900D5E503988125A0FB99E7CB3ADFB86)
	TrajectoryHashRtn Hash = PMC->ReadTrajectoryHash(1);

	//move xbot to starting position
	PMC->XYMotion(0, 1, POSITIONMODE::ABSOLUTE_MOTION, LINEARPATHTYPE::DIRECT, 0.12, 0.12, 0, 1.0, 10.0, 0);

	//xbot 1 runs trajectory 1
	PMC_USINT xbotID = 1;
	PMC_USINT trajID = 1;
	PMC->ActivateTrajectory(0, 1, &xbotID, &trajID);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);
}

//any configuration of xbots and flyways - SetConfiguration, GetConfiguration. Configuration XML file 'PMCConfig.xml' must be on disc in the DemoFilesFolder
void FileExample04_Configuration(PMC_Acontis_API* PMC, string DemoFilesFolder)
{
	//wait for PMC to be active
	PollForPMCState(PMC);

	//wait for all xbots to be idle
	PollForAllXbotsState(PMC);

	//read config file from disk
	ifstream ConfigFile;
	unsigned char ConfigData[500000];
	ConfigFile.open(DemoFilesFolder + "/PMCConfig.xml", ios::binary);
	ConfigFile.read((char*)ConfigData, 500000);
	int config_data_size = ConfigFile.gcount();
	ConfigFile.close();

	//deactivate the PMC
	PMC->DeactivateXbots();
	PollForPMCState(PMC, PMCSTATUS::PMC_INACTIVE);

	//send the configuration to the PMC
	PMCRTN rtn = PMC->SetConfiguration(config_data_size, ConfigData);

	//reboot PMC to switch to the new configuration (restart PMT to update display in the GUI)
	PMC->Reboot();
	PollForPMCState(PMC,PMCSTATUS::PMC_BOOTING);
	PollForPMCState(PMC, PMCSTATUS::PMC_INACTIVE);

	//read the configuration from the PMC
	ConfigRtn Config = PMC->GetConfiguration();
}

//5x5 flyways - up to 10 xbots with the example application design loaded on the PMC as design 1
void Example37_ApplicationDesigner(PMC_Acontis_API* PMC)
{
	srand(69420);

	//start the system
	PollForPMCState(PMC);
	
	//move xbots to starting positions
	ReadXbotIDsRtn XbotIDsRtn = PMC->ReadXbotIDs();
	PMC_REAL PosX[10];
	PMC_REAL PosY[10];
	for(int i = 0;i < 10;i++)
	{
		PosX[i] = 0.06 + 0.12*i;
		PosY[i] = 0.06;
	}
	PMC->AutoDrivingMotion(XbotIDsRtn.NumXbots,0,false,0,XbotIDsRtn.Xbot_IDs,PosX,PosY);
	PollForXbotState(PMC,1);
	for(int i = 0;i < XbotIDsRtn.NumXbots;i++)
	{
		PMC->App_SendXbotToStation(i+1,1,1,0);
	}

	PMC_USINT StateFilter = (PMC_USINT)XBOTSTATE::XBOT_IDLE;
	App_GetBayXbotIDRtn StationBayRtn;
	while(1)
	{
		//station 1 bay 1
		StationBayRtn = PMC->App_GetBayXbotID(1,1,1,&StateFilter);
		if(StationBayRtn.XbotID != 0 && StationBayRtn.XbotID != 255)
		{
			PMC->App_SendXbotToStation(StationBayRtn.XbotID,2,rand() % 2 + 1,0);
		}

		//station 1 bay 2
		StationBayRtn = PMC->App_GetBayXbotID(1,2,1,&StateFilter);
		if(StationBayRtn.XbotID != 0 && StationBayRtn.XbotID != 255)
		{
			PMC->App_SendXbotToStation(StationBayRtn.XbotID,2,rand() % 2 + 1,0);
		}

		//station 2 bay 1
		StationBayRtn = PMC->App_GetBayXbotID(2,1,1,&StateFilter);
		if(StationBayRtn.XbotID != 0 && StationBayRtn.XbotID != 255)
		{
			PMC->App_SendXbotToStation(StationBayRtn.XbotID,1,rand() % 2 + 1,0);
		}

		//station 2 bay 2
		StationBayRtn = PMC->App_GetBayXbotID(2,2,1,&StateFilter);
		if(StationBayRtn.XbotID != 0 && StationBayRtn.XbotID != 255)
		{
			PMC->App_SendXbotToStation(StationBayRtn.XbotID,1,rand() % 2 + 1,0);
		}
	}
}

