
#ifndef USBMCLIB_H
# define USBMCLIB_H

/*
#ifdef USBMC_STATIC_LIB
#pragma comment(lib, "setupapi.lib")
#ifdef _DEBUG
# pragma comment(lib, "usbmclibd.lib") //Static lib debug version
#else
# pragma comment(lib, "usbmclib.lib") //Static lib release version
#endif
#else
# pragma comment(lib, "usbmc.lib")	//DLL version
#endif
*/
//#pragma comment(lib, "setupapi.lib")


#pragma pack(push, 1)

typedef struct {
	//Motor tuning
	int spu;	//steps per unit
	int vel;	//velocity steps/s
	int acc;	//acceleration steps/s2

	BYTE slave;	//slave axis (for A,B or C)

	//soft limits
	int smin, smax;
	//int slow_zone;

	//homing
	int home_speed;
	int home_offset;
	BYTE  home_flags;

}USBMC_AxisCfg;



typedef struct{
	//BYTE spindle_relay;
	BYTE spindle_motor;
	int spindle_pwmfreq;
	int spindle_pwmmin;
	int spindle_pwmmax;
} USBMC_SpindleConfig;

typedef struct {
	USBMC_AxisCfg ax_cfg[7];
	USBMC_SpindleConfig sp_cfg;

	WORD state_flags;

	int home_retract_speed;
	BYTE home_deref_speed;

	//BYTE laser_gate_port;
	//WORD index_prescaler;
	BYTE enc_for_mpg;	//Encoder to use for MPG (0 or 1)
	//BYTE enc_x4;

} USBMC_Config;


// One motion buffer segment, 1ms update rate

typedef struct {
	double pos[6];	 //axis position in steps
	DWORD line;		//this segment ID number (optional)
	BYTE ecmd:4, epin:4;		//fast ext out command and pin number (optional)
	BYTE pwm_duty;	   //8-bit pwm duty for compensation (optional)
} USBMC_BufSeg;


//#define MAX_STEP_RATE	250000


typedef struct {
	BYTE pin;	//pin number >=1 (0=undefined)
	BYTE enable:1, inv:1;	//signal enable and invert (make active low)
} USBMC_Signal;


typedef struct{

	//Output signals
	USBMC_Signal stepx, stepy, stepz, stepa, stepb, stepc, steps;	//Step outputs
	USBMC_Signal dirx, diry, dirz, dira, dirb, dirc, dirs;	//Dir outputs
	USBMC_Signal charge1, charge2;	//Charge pump signal outputs
	USBMC_Signal ext1, ext2, ext3, ext4, ext5, ext6;	//External out 1-6

	//Input signals
	USBMC_Signal homex, homey, homez, homea, homeb, homec;	//home switches
	USBMC_Signal limitxp, limitxn, limityp, limityn, limitzp, limitzn;	 //limit switches positive and negative
	USBMC_Signal limitap, limitan, limitbp, limitbn, limitcp, limitcn;
	USBMC_Signal index;	//Spindle index input
	USBMC_Signal estop;	//ESTOP input
	USBMC_Signal enc1a, enc1b;	//Encoder1 A,B inputs
	USBMC_Signal enc2a, enc2b;	//Encoder2 A,B inputs
	USBMC_Signal probe; 

	WORD debounce[16];	//debounce data for all input pins, debounce[0]=debounce value for pin1 etc.

}USBMC_IOCfg;



//Motion controller complete status
typedef struct {
	BYTE size;		//size of this struct
	BYTE state;		//current mode
	BYTE cur_seq;	//current sequence
	BYTE flags;			//various flags
	WORD inputs;	//input states
	WORD outputs;	//output states
	int axis_ticks[7];	//all axes positions in steps
	float spindle_rpm;	//rpm detected using Index input
	WORD inbuff;		//points currently in buffer
	DWORD time;		//timestamp when this status was created
	int encoder1_pos;	//encoder1 position
	int encoder2_pos;	//encoder2 position
	BYTE fault;			//fault code
	BYTE homed;		//signals referenced axis
	DWORD gline;	//id from cur buffer segment (like prog line currently executing)
	WORD analogv;	//analog input value
} USBMC_Status;


#ifndef USBMC_NAMESPACE
# define USBMC_NAMESPACE

namespace USBMC{

	//Current mode
	enum Mode{
		M_IDLE=0,
		M_JOG,
		M_SEGM,
		M_HOLD,
		M_ESTOP,
		M_SAFE,
		M_RDOWN
	};

	//Sequences
	enum Sequence{
		SQ_NONE=0,
		SQ_HOME0,
		SQ_HOME1,
		SQ_HOME2,
		SQ_HOME3,
		SQ_HOME4,
		SQ_PROBE1,
		SQ_PROBE2,
		SQ_MPG
	};

	//Stop reasons
	enum Fault{
		F_NONE=0,
		F_UNK,
		F_HOMESW,
		F_LIMITSW,
		F_SOFTLIMIT,
		F_ESTOP,
		F_PROBE
	};

	enum HomeFlags{
		// Home flags
		HOME_NEG = 1,
		HOME_AUTOZERO =	2,
	};
	enum SpindleTypes{
		//Spindle types
		SPINDLE_NOMOTOR	= 0,
		SPINDLE_PWM,
		SPINDLE_STEPDIR
	};

	enum EngineCmd{
		//Engine commands
		C_EXT_OUT_ON	=	1,
		C_EXT_OUT_OFF	=	2
	};

	enum StopModes{
		STOP_ESTOP = 1,
		STOP_DISCONNECT	= 2
	};

	//cfg state FLAGS
	enum CfgFlags{
		//CHARGE flags
		CHARGE_5K =	1,
		CHARGE_ALWAYSON	=	2,

		//Misc
		LIMIT_OVERRIDE =	4,
		//THC_MODE	=	8,
		LASER_COMP =	16,
		LASER_GRAY =	32,
		//SOFTLIMITS_SLOWZONE =		64,		//unused
		HOME_UNLINK_SLAVE =	128,	//=!HOME_SLAVEWMASTER

		LOW_SPEED = 256,	//125kHz mode
	};

	//Runtime state flags 
	enum RuntimeFlags{
		SOFT_LIMITS	= 1,
		SHUTTLE_MODE = 2,
		//#define  OFFLINE_MODE	4
		//#define THC_MODE		8
		//#define THC_DISABLEUPDN		32
		//PROBE_LIMIT	=	64
	};

	//Status flags
	enum StatusFlags{
		S_FLG_SWRESYNC	=	1,
		S_FLG_THCON	=	2,
		S_FLG_SPINDLEON	=	 4,
		S_FLG_THCARCOK	=	8,
		S_FLG_THCUP	=	16,
		S_FLG_THCDOWN	=	32,
		S_FLG_THCLOCK	=	64,

		S_FLG_AXISHOMED = 128,
	};

	enum ProbeState{
		PROBE_IDLE=0,
		PROBE_ACTIVE,
		PROBE_NOHIT,
		PROBE_HIT
	};

	const int MAX_STEP_RATE	= 250000;			//maximum step frequency, Hz
	const int PIC_CORE_TIMER = 50000000;		//frequency of controller internal timer, Hz
};

#endif		//USBMC_NAMESPACE

#pragma pack(pop)




///////// USB-MC API functions

////// Hardware communication functions
BOOL usbmc_Open();
void usbmc_Close();
BOOL usbmc_Init(USBMC_Config *ucfg, USBMC_IOCfg *pcfg);
BOOL usbmc_GetStatus(USBMC_Status *stat);
void usbmc_Disconnect();
BOOL usbmc_CmdStop(BYTE flags=0);
BOOL usbmc_CmdSetOutputs(WORD out_bits, WORD flags=0, WORD zmask=0);
BOOL usbmc_CmdJogOn(int axis, BOOL dir, DWORD speed);
BOOL usbmc_CmdJogOff(int axis);
BOOL usbmc_CmdSpindle(BOOL on, WORD pwm_duty=0, DWORD speed=0);
BOOL usbmc_CmdHomeAxis(BYTE axis);
BOOL usbmc_CmdPurge(BOOL clear=FALSE);	//execute all data left in the buffer if any (or clear)
BOOL usbmc_SetupMPG(BYTE axis, 	double step,  DWORD maxvel, BOOL enable);	//hw mpg setup
BOOL usbmc_CmdProbe(double start[6], double end[6], double feedrate);
BOOL usbmc_GetProbePos(double hit_pos[6]);
int usbmc_GetProbeResult();
BOOL usbmc_IsProbing();
BOOL usbmc_IsHoming();

const char *usbmc_GetFirmwareVersion();
void usbmc_PosResync();

/////// Motion buffer management
BOOL usbmc_BufAdd(USBMC_BufSeg *p);	//add segment to the buffer
int usbmc_BufFreeCnt();	//get free space in the buffer
void usbmc_BufClear();	//clear all data in the buff
BOOL usbmc_BufEmpty();	//check if any data present in the buff

int usbmc_BufUpdate(int max_cnt=75);	//send data if present in the buffer

void usbmc_SetBuffSize(int moves);




#endif	//USBMCLIB_H