//
//  motion_controller.h - motion controller class header file
//
//  $Id: motion_controller.h 54 2014-04-11 01:06:56Z brian $ 
//
//  Copyright (c) 1999-2014 by Precision Micro Control Corp. All rights reserved.
//
#ifndef MOTION_CONTROLLER_H
#define MOTION_CONTROLLER_H

// Run Status bit masks
#define READY			0x1
#define RUNNING			0x2
#define FINISHED		0x4
#define PAUSED			0x8
#define FEEDHOLD		0x10
#define DRYRUN			0x20
#define BLOCK_SKIP		0x40

#define DIM_INPUT_ABS	0x100
#define DIM_INPUT_INC	0x200

#define CNC_ERROR		0x10000
#define PROGRAM_ERROR	0x20000
#define E_STOP			0x40000
#define EE_STOP			0x80000
#define DRIVE_FAULT		0x100000
#define MOTOR_ERROR		0x200000

/// <summary>
/// MotionController - Motion Controller Class
/// </summary>
class MotionController : CObject
{
public:
	/// <summary>Constructor.</summary>
	/// <param name="id">Controller ID.</param>
	MotionController(int id = 0);
	/// <summary>Destructor.</summary>
	~MotionController(void) {}
	
	/// <summary>Open a binary and an ASCII handle to the controller.</summary>
	void						Open();
	/// <summary>Close the controller handles.</summary>
	void						Close(void);

	/// <summary>Get controller type.</summary>
	/// <returns>Controller type constant (MCAPI constant).</returns>
	int							GetControllerType() { return m_ctlr_type; }
	
	/// <summary>Decode status word for axis (test for bit set/unset).</summary>
	/// <param name="status">Status word to test.</param>
	/// <param name="bit">Status word to test.</param>
	/// <returns>True if set, false if not set.</returns>
	int							DecodeStatus(DWORD status, int bit) { return MCDecodeStatus(m_hctlr_bin, status, bit); }
	/// <summary>Set axis direction.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="direction">New direction.</param>
	void						Direction(WORD axis, WORD direction) { MCDirection(m_hctlr_bin, axis, direction); }
	/// <summary>Enable or disable an axis.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="state">True to enable, false to disable.</param>
	void						EnableAxis(WORD axis, int state) { MCEnableAxis(m_hctlr_bin, axis, state); }
	/// <summary>Enable or disable a digital I/O channel.</summary>
	/// <param name="channel">Channel number to control.</param>
	/// <param name="state">True to enable, false to disable.</param>
	void						EnableDigitalIO(WORD channel, bool state) { MCEnableDigitalIO(m_hctlr_bin, channel, state); }
	/// <summary>Generate a background task.</summary>
	/// <param name="macro">Macro number to run as a background task.</param>
	void						GenerateTask(int macro) { MCBlockBegin(m_hctlr_bin, MC_BLOCK_TASK, macro); MCBlockEnd(m_hctlr_bin, NULL); }
	/// <summary>Get state of all digital I/O channels.</summary>
	/// <returns>Unsigned integer value with one bit per channel for each of 32 channels.</returns>
	unsigned int				GetAllDigitalIO(void) { unsigned int state; MCGetDigitalIOEx(m_hctlr_bin, 0, &state); return state; }
	/// <summary>Get axis optimal position.</summary>
	/// <param name="axis">Axis number to query.</param>
	/// <returns>Optimal position.</returns>
	double						GetOptimal(WORD axis) { double temp; MCGetOptimalEx(m_hctlr_bin, axis, &temp); return temp; }
	/// <summary>Get axis actual position.</summary>
	/// <param name="axis">Axis number to query.</param>
	/// <returns>Actual position.</returns>
	double						GetPosition(WORD axis) { double temp; MCGetPositionEx(m_hctlr_bin, axis, &temp); return temp; }
	/// <summary>Get status word for axis.</summary>
	/// <param name="axis">Axis number to query.</param>
	/// <returns>Status word.</returns>
	unsigned int				GetStatus(WORD axis) { return MCGetStatus(m_hctlr_bin, axis); }
	/// <summary>Get axis target position.</summary>
	/// <param name="axis">Axis number to query.</param>
	/// <returns>Target position.</returns>
	double						GetTarget(WORD axis) { double temp; MCGetTargetEx(m_hctlr_bin, axis, &temp); return temp; }
	/// <summary>Start axis moving.</summary>
	/// <param name="axis">Axis number to control.</param>
	void						Go(WORD axis) { MCGo(m_hctlr_bin,axis); }
	/// <summary>Run a macro.</summary>
	/// <param name="macro">Number of macro to run.</param>
	void						MacroCall(int macro) { MCMacroCall(m_hctlr_bin, macro); }
	/// <summary>Move an axis to an absolute position.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="position">Target position.</param>
	void						MoveAbsolute(WORD axis, double position) { MCMoveAbsolute(m_hctlr_bin, axis, position); }
	/// <summary>Move an axis to a relative amount.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="distance">Amount to move.</param>
	void						MoveRelative(WORD axis, double distance) { MCMoveRelative(m_hctlr_bin, axis, distance); }
	/// <summary>Set axis acceleration.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="acceleration">New acceleration.</param>
	void						SetAcceleration(WORD axis, double acceleration) { MCSetAcceleration(m_hctlr_bin, axis, acceleration); }
	/// <summary>Set axis deceleration.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="deceleration">New deceleration.</param>
	void						SetDeceleration(WORD axis, double deceleration) { MCSetDeceleration(m_hctlr_bin, axis, deceleration); }
	/// <summary>Set axis operating mode.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="master">Master axis number if mode is MC_MODE_CONTOUR, otherwise should be zero.</param>
	/// <param name="mode">New operating mode, one of MC_MODE_CONTOUR, MC_MODE_GAIN, MC_MODE_POSITION, 
	/// MC_MODE_TORQUE, or MC_MODE_VELOCITY.</param>
	void						SetOperatingMode(WORD axis, WORD master, WORD mode) { MCSetOperatingMode(m_hctlr_bin, axis, master, mode); }
	/// <summary>Set axis velocity.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="override">New velocity.</param>
	void						SetVelocity(WORD axis, double velocity) { MCSetVelocity(m_hctlr_bin, axis, velocity); }
	/// <summary>Set velocity override.</summary>
	/// <param name="axis">Axis number to control.</param>
	/// <param name="over_ride">Override value.</param>
	void						SetVelocityOverride(WORD axis, double over_ride) { MCSetVelocityOverride(m_hctlr_bin, axis, over_ride); }
	/// <summary>Stop a moving axis.</summary>
	/// <param name="axis">Axis number to control.</param>
	void						Stop(WORD axis) { MCStop(m_hctlr_bin, axis); }

	/// <summary>Disable block skip.</summary>
	/// <param name="Block">Block number.</param>
	void						DisableBlockSkip(int block) { pmccmdex(m_hctlr_bin, 0, DBS, &block, MC_TYPE_LONG); }
	/// <summary>Disable dry run.</summary>
	void						DisableDryRun(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, DDR, &dummy, MC_TYPE_LONG); }
	/// <summary>Disable optional stop.</summary>
	void						DisableOptionalStop(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, DOS, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable/disable block text display.</summary>
	/// <param name="enable">True to enable display, false to disable display.</param>
	void						DisplayBlockText(bool enable) { int dummy; dummy = enable ? 1 : -1; pmccmdex(m_hctlr_bin, 0, DBT, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable/disable file number display.</summary>
	/// <param name="enable">True to enable display, false to disable display.</param>
	void						DisplayFileNumber(bool enable) { int dummy; dummy = enable ? 1 : -1; pmccmdex(m_hctlr_bin, 0, DFN, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable/disable file position display.</summary>
	/// <param name="enable">True to enable display, false to disable display.</param>
	void						DisplayFilePosition(bool enable) { int dummy; dummy = enable ? 1 : -1; pmccmdex(m_hctlr_bin, 0, DFP, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable/disable user output display.</summary>
	/// <param name="enable">True to enable display, false to disable display.</param>
	void						DisplayUserOutput(bool enable) { int dummy; dummy = enable ? 1 : -1; pmccmdex(m_hctlr_bin, 0, DUO, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable block skip.</summary>
	/// <param name="Block">Block number.</param>
	void						EnableBlockSkip(int block) { pmccmdex(m_hctlr_bin, 0, EBS, &block, MC_TYPE_LONG); }
	/// <summary>Enable dry run.</summary>
	void						EnableDryRun(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, EDR, &dummy, MC_TYPE_LONG); }
	/// <summary>Enable optional stop.</summary>
	void						EnableOptionalStop(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, EOS, &dummy, MC_TYPE_LONG); }
	/// <summary>Get file position.</summary>
	/// <returns>File position.</returns>
	int							GetFilePosition(void);
	/// <summary>Get program number.</summary>
	/// <returns>Program number.</returns>
	int							GetProgramNumber(void);
	/// <summary>Get repeat count.</summary>
	/// <returns>Repeat count.</returns>
	int							GetRepeatCount(void);
	/// <summary>Get run status.</summary>
	/// <returns>Status.</returns>
	int							GetRunStatus(void);
	/// <summary>Get sequence number.</summary>
	/// <returns>Sequence number.</returns>
	int							GetSequenceNumber(void);
	/// <summary>Get spindle speed.</summary>
	/// <returns>Spindle speed.</returns>
	double						GetSpindleSpeed(void);
	/// <summary>Get tool number.</summary>
	/// <returns>Tool number.</returns>
	int							GetToolNumber(void);
	/// <summary>Initiate block by block command.</summary>
	void						InitBlockByBlock(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, IBB, &dummy, MC_TYPE_LONG); }
	/// <summary>Initiate feed hold command.</summary>
	void						InitFeedHold(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, IFH, &dummy, MC_TYPE_LONG); }
	/// <summary>Initiate start command.</summary>
	void						InitStart(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, IST, &dummy, MC_TYPE_LONG); }
	/// <summary>Run a file on the controller.</summary>
	/// <param name="file_no">File number to run.</param>
	void						RunFile(int file_no) { pmccmdex(m_hctlr_bin, 0, RUF, &file_no, MC_TYPE_LONG); }
	/// <summary>Terminate a running file on the controller.</summary>
	void						RunTerminate(void) { int dummy = 0; pmccmdex(m_hctlr_bin, 0, RUT, &dummy, MC_TYPE_LONG); }
	/// <summary>Set the feedrate override.</summary>
	/// <param name="over_ride">Feedrate overwrite value.</param>
	void						SetFeedrateOverride(double over_ride) { pmccmdex(m_hctlr_bin, 0, SFO, &over_ride, MC_TYPE_DOUBLE); }
	/// <summary>Set the rapid rate override.</summary>
	/// <param name="over_ride">Rapid rate overwrite value.</param>
	void						SetRapidOverride(double over_ride) { pmccmdex(m_hctlr_bin, 0, SRO, &over_ride, MC_TYPE_DOUBLE); }
	/// <summary>Set the spindle rate override.</summary>
	/// <param name="over_ride">Spindle rate overwrite value.</param>
	void						SetSpindleOverride(double over_ride) { pmccmdex(m_hctlr_bin, 0, SSO, &over_ride, MC_TYPE_DOUBLE); }

	/// <summary>Get a character from the ASCII interface.</summary>
	/// <returns>Character value or 0 if no character was waiting.</returns>
	short int					GetC(void) { return pmcgetc(m_hctlr_asc); }
	/// <summary>Get a string from the ASCII interface.</summary>
	/// <param name="buffer">Buffer to hold string.</param>
	/// <param name="size">Size of buffer.</param>
	/// <returns>Number of characters read.</returns>
	short int					GetS(char* buffer, short int size) { return pmcgets(m_hctlr_asc, buffer, size ); }
	/// <summary>Put a character to the ASCII interface.</summary>
	/// <param name="ch">Character to send.</param>
	/// <returns>Number of characters sent.</returns>
	short int					PutC(short int ch) { return pmcputc(m_hctlr_asc, ch); }
	/// <summary>Put a string to the ASCII interface.</summary>
	/// <param name="ch">String to send.</param>
	/// <returns>Number of characters sent.</returns>
	short int					PutS(char* buffer) { return pmcputs(m_hctlr_asc, buffer); }
	/// <summary>Check if binary interface is ready to accept commands.</summary>
	/// <returns>True if ready. false if not ready.</returns>
	bool						Rdy(void) { return pmcrdy(m_hctlr_bin) != 0; }
	/// <summary>Check if ASCII interface is ready to accept commands.</summary>
	/// <returns>True if ready. false if not ready.</returns>
	bool						RdyA(void) { return pmcrdy(m_hctlr_asc) != 0; }
	/// <summary>Check if ASCII interface is ready to accept a file download.</summary>
	/// <returns>True if ready. false if not ready.</returns>
	bool						RdyFile(void);


	/// <summary>Download a file to the controller.</summary>
	/// <param name="filename">Name of file.</param>
	/// <param name="file_no">File number to use on controller.</param>
	void						LoadFile(char* filename, int file_no);

private:
	int							m_id;						///< controller ID
	int							m_ctlr_type;				///< controller type (MCAPI constant)
	HCTRLR						m_hctlr_asc;				///< Ascii interface controller handle
	HCTRLR						m_hctlr_bin;				///< binary interface controller handle
};

#endif			// MOTION_CONTROLLER_H

