
#ifndef __WORKCTRL_H__
#define	__WORKCTRL_H__

#include "config.h"

#include "datafile.h"
#include "operator.h"
#include "motos.h"
#include "nvpara.h"
#include "controlbus.h"

#include "ocom.h"

#if (CUR_MACHINE == MACH_EMB)
#include "embroidery.h"
#endif

#if (CUR_MACHINE == MACH_WIRE)
#include "wire.h"
#endif

#if (CUR_MACHINE == MACH_BEDSKIRT)
#include "bedSkirt.h"
#endif

#if (CUR_MACHINE == MACH_PES)
#include "pes.h"
#endif
//-------------------------------------------------------------------------------

// 机器状态

typedef struct
{
	// 0
	u32 workStatus;			// 工作状态位图
							// .0 允许时限。=0，使用时限已到，不允许下位机工作；=1，允许下位机工作；
							// .1 允许状态。=0，界面钳制，不允许下位机工作；=1，允许下位机工作；
							// .2 机器状态。=0，手动工作状态; =1，自动工作状态
							// .3 钥匙状态。=0，关闭状态; =1，打开状态
							// .4 文件接收标志。= 0，初始状态。= 1，收到了文件
							// .5 参数接收标志。= 0，初始状态。= 1，收到了参数
							// .6 正在忙标志。= 0，空闲（可以接收文件和参数）。= 1，工作中（不会接收文件和参数）
							// .7 上料状态。=0，手动上料状态; =1，自动上料状态
							// .8 参数更新标志。 =1，下位机更新了参数
							// .9 模拟工作标志。=1, 处于模拟工作状态
							// .10 允许扫描条码状态。=1, 允许
							// .11 允许拍照状态。=1, 允许
							// .12 正在工作标志
							// .13 传感信号扫描中标志
							// .14 相机校准模式中标志
							// .15 调试输出中标志. = 0，初始状态。= 1，上位机正在测试输出信号,不响应程序内输出控制
							// .16 等待标志. = 0，初始状态。= 1，等待外设就绪
							// .17 换梭标志，0，初始状态，1，换梭中
							// .18 软件遍历功能标志. =1,不允许遍历
							// .19 取模板框状态
							// .20 放模板框状态
							// .21 匹绣, 0:退出匹绣,主轴归零 1:进入匹绣,扎针,允许移框
							// .22 断线检测， 0：退出断线检测状态， 1：进入断线检测状态
							// .23 喷墨主板文件有效标志,  0:无效,   1:有效
							// .25 删除文件标志,  0:无效,   1:有效
							// .26 请求重发文件,  0:无效,   1:有效

	// 1
	u32 errorCode;			// 错误代码
	s32 fileIdx;			// 文件序号
	u32 dataIdx;			// 数据索引
	u32 runSpeed;			// 运动速度
	u32 runAction;			// 执行动作代码 *
	u32 runSteps;			// 当前执行步骤 *
	u32 outCounter;			// 产量计数

    // 8
    u32 tempdat[12];        // 自定义状态

    // 20
    s32 btrdPics;			// 底线片数计数
    s32 btrdLength;			// 底线长度计数

    // 22
    u32 colorIdx;			// 色序编码
	s32 curEncPos;			// 当前位置

    // 24
    u32 msAnlge;
    u32 potVal;
    s32 needleIdx;			// 针位号

    // 27
	s32 workableTimer;		// 可工作时间计数器（分钟）

	// 28
	u32 embNeedleNum;		// 刺绣针数

	// 29
	u32 workTimeRecord;		// 单片工作时间
	u32 clipLv;
	u32 tempdat3;

//	// 20230517扩展
//	// 32
//	u32 tempdat4[8];
//
//	// 40
//	u32 tempdat5[8];
//
//	// 48
//	u32 tempdat6[8];
//
//	// 56
//	u32 tempdat7[64-56];

} __attribute__ ((packed)) MCStatus;

//-------------------------------------------------------------------------------

#define	WORK_STA_ENTIME		0x00000001		// 允许时限
#define	WORK_STA_ENSTATE	0x00000002		// 允许状态
#define	WORK_STA_WKAUTO		0x00000004		// 工作状态
#define	WORK_STA_KEYEN		0x00000008		// 钥匙状态
#define	WORK_STA_FILEOK		0x00000010		// 文件接收标志。= 0，初始状态。= 1，收到了文件
#define	WORK_STA_PARAOK		0x00000020		// 参数接收标志。= 0，初始状态。= 1，收到了参数
#define	WORK_STA_BUSY		0x00000040		// 正在忙标志。= 0，空闲（可以接收文件和参数）。= 1，工作中（不会接收文件和参数）

#define	WORK_STA_NEW_PARA	0x00000100		// 参数更新标志。 =1，下位机更新了参数。上位机需要读取下位机的参数文件并更新
#define	WORK_STA_SIMULATE	0x00000200		// 模拟工作标志。 =1，机器处于模拟工作
#define	WORK_STA_EN_SCAN	0x00000400		// 扫码允许。 =1，允许扫码状态
#define	WORK_STA_WORKING	0x00001000		// 工作标志。= 1，工作中
#define	WORK_STA_SENSOR		0x00002000		// 传感信号扫描中标志. = 0，初始状态。= 1，上位机正在检测传感信号,所有按钮不响应
#define	WORK_STA_OUTPUT		0x00008000		// 调试输出中标志. = 0，初始状态。= 1，上位机正在测试输出信号,不响应程序内输出控制
#define	WORK_STA_WAIT		0x00010000		// 等待标志. = 0，初始状态。= 1，等待外设就绪

#define WORK_STA_CHG_HOOK	0x00020000		// 换梭标志，0，初始状态，1，换梭中
#define WORK_STA_TRAVERSE	0x00040000		// 软件遍历功能标志. 0,初始状态允许遍历. 1,不允许遍历

#define WORK_STA_CLOTH		0x00200000		// 匹绣, 0:退出匹绣,主轴归零 1:进入匹绣,扎针,允许移框
#define WORK_STA_DETBK		0x00400000		// 断线检测 0：退出断线检测状态， 1：进入断线检测状态

#define WORK_STA_FRM_CHK	0x02000000		// 模板到位标志，0，未到位；1，到位
#define WORK_STA_RFID_SCAN	0x04000000		// RFID识别标志，0，不允许；1，允许

#define WORK_STA_ALL_STOP	(WORK_STA_SENSOR|WORK_STA_OUTPUT|WORK_STA_GET_FLM|WORK_STA_PUT_FLM)		// 禁止相应任何动作状态

//-------------------------------------------------------------------------------

typedef struct
{
	u16 id;
	u16 cfg;
	u16 mod;
}AxisItem;

//-------------------------------------------------------------------------------

typedef struct
{
	// 0
	s32 motospos[AXIS_NUM];	// 电机位置
	// 6
	u32 fileID;				// 文件标识符
	u32 dataIdx;			// 数据索引
	u32 runSteps;			// 当前执行步骤
	u32 outCounter;			// 产量计数
	u32 btrdPics;			// 底线片数计数	()
	u32 btrdLength;			// 底线长度计数 ()
	u32 fileCheck;			// 文件校验
	u32 mcType;				// 机器类型
	s32 fileIdx;			// 文件序号
	u32 fileIdxMap;			// 文件位图
	u32 hookPlateCount;		// 自动换梭梭盘计数
	s32 sendCount;			//

	u32 embNeedleNum;		// 刺绣针数

	// 18
	u8 rev[MAX_SAVE_SIZE-(AXIS_NUM+13)*sizeof(u32)];
	u16	enFlag;						// 保存数据有效标志
} __attribute__ ((packed)) SavedPara;

//----------------------------

typedef struct
{
	MCStatus cursta;
	MCStatus oldsta;

	SavedPara savedpara;		// 保存数据

	//-----------------------
	u32 paraEnFlag;				// 参数有效标志
	//-----------------------
	u32 boardId;	   			// 板卡ID

	//-----------------------

	// 零位传感器坐标
	u32 posEnFlag;				// 坐标有效标志
	int zeroEnFlag;				// 零位坐标有效标志
	s32 zeroPosList[AXIS_NUM*10];	// 零位坐标值

	// 工作坐标
	int workAvaible;			// 工作坐标（数据坐标）有效标志
	s32 workPos[AXIS_NUM*10];	// 工作坐标,*10是为了预留

	//-----------------------

	int curmsrpm;				// 当前主轴转速
	int chrpmflag;				// 转速改变标志
	u32 expectedOutput;			// 预计产出（产量）

	//-----------------------
	int stopFlag;				// 运行停止标志
	int sendStaWhenRun;			// 运行时发送状态标志

	//-----------------------
	int chBobbinPics;			// 换梭片数
	int chBobbinLength;			// 换梭总长度（单位0.01mm）
	//-----------------------
	// 三色灯蜂鸣器
	int almflashRed;			// 红灯闪烁标志
	int almredSta;				// 闪红灯状态
	int almflashGreen;			// 绿灯闪烁标志
	int almgreenSta;			// 闪绿灯状态
	int almflashYello;			// 黄灯闪烁标志
	int almyelloSta;			// 闪黄灯状态
	int almflashBee;			// 蜂鸣器闪烁标志
	int almbeeSta;				// 蜂鸣器开关状态
	int almSta;					// 蜂鸣器状态

	//-----------------

	int cansetelapsed;

	//-----------------
	int stopShiftFlag;
	//-----------------

	int embMendTrdFlag;			// 补绣标志
	int embMendEndIdx;			// 补绣完成索引
	int mendEndPatternIdx;		// 20230601 补绣完成花样索引,用于花样循环或反复时补绣可跨花版

	//-----------------

	int requestFlag;			// 动态传输标志, =0,允许请求		=1,禁止请求

	//-----------------
	int workStopFlag;
	int olderr;
	int fileScanFlag;
	int fileScanSaveId;
	int fileScanOldId;
	int fileScanId;
	//-----------------
	u32 stopShiftEn;
	int stopShiftDx;
	int stopShiftDy;

	int stopBtnFlag;

	void (*WorkRunTask)(void);
	void (*AsynchronousTask)(void);

}WorkCtrl;

//----------------------------

#ifdef _IN_WORKCTRL_C
WorkCtrl g_workCtrl;
#else
extern WorkCtrl g_workCtrl;
#endif

//----------------------------

void InitWorkCtrl(void);
void InitAppCallback(void);
void WorkCtrlTask(void);
void TasksWhenDelay(void);
void DelayRef(u32 ms);
void DelayAndAsyncExe(u32 ms);
void DelayRefFt(u32 ms);

//----------------------------
void RefreshWorkTimeEn(void);

void SaveWorkNvPara(void);

void RefreshStatus(void);
void RefreshParas(int flag);
void SetNewParasFlag(int flag);

//-------------------------------------------------------------------------------

void RequestBoardVer(void);							// 请求外围板程序版本
int CreateBoardVer(OperPacket * pPkt, u8 protocol, u8 nodeId, u8 nodeType, BoardRegVal * pRegVal);
int CreateHeadBoardPara(OperPacket * pPkt, u8 nodeId, u8 nodeType, u8* pData);
int CreateColorBoardPara(OperPacket * pPkt, u8 nodeId, u8* pData);

int RequestHeadNvParas(int nodetype, int nodeid, int paraid, u32 * pBuf);
void SetHeadNvPara(int nodetype, int nodeid, int paraid, u32 * pBuf);
int CreateHeadNvParas(OperPacket * pPkt, u8 nodetype, u8 nodeId, u8 paraid, u8* pData);

int CreateMcInfo(OperPacket * pPkt, int toggle);
int CreateMcStatus(OperPacket * pPkt, int toggle);

int CreateFileList(OperPacket * pPkt, int toggle);

void SensorsStatus(int mode, u8 * buf);
int CreateSensorsStatus(OperPacket * pPkt);
int CreateSensorsBmp(OperPacket * pPkt);

//-------------------------------------------------------------------------------

void TraverseTask(u8 protocol, u8 nodeId, u8 nodeType, int traNum);		// 遍历任务

void SetMcStatus(u32 sta, u32 para);

int ControlByHand(OperPacket * pPkt);

void MotoToZero(u16 obj);
void MoveMotoByHand(u16 obj, u16 dir, u16 spd);
void OutputByHand(u16 obj, u16 act, u16 para);
void MotosServoCtrl(u16 obj, u16 onoff);
void ManualActionCtrl(u16 obj, u16 para2, u16 para3);
void TestThreadBreak(int type, int needle, int head);
void ShakeFrameTest(u16 ofstx, u16 ofsty, u16 runspd);


int ControlWork(OperPacket * pPkt);
int ControlWorkWhenWorking(OperPacket * pPkt);

void ChangeRpm(int rpmchg);
void AllToReset(void);
void AllToZero(void);
int GotoStartPos(void);
int GotoAnchorPos(void);
int GotoOffsetPos(void);
void SetOffsetPos(void);
int GotoWorkPos(void);
int GotoFinishPos(void);
int GotoFeedPos(void);
void SetFeedPos(void);
int GotoFrameZeroPos(void);
int CheckFrame(void);
void SimulationFrame(void);
int FastJump(u32 idx);
void OilingInWorking(u32 para1);
int MoveFrameToPos(s32 posx, s32 posy);
int FixMoveFrame(s32 xmvmnt, s32 yxmvmnt);

void MoveFrameTo(OperPacket * pPkt);
void MoveFrameAsOfst(OperPacket * pPkt);

//-------------------------------------------------------------------------------

int ReportError(int errCode);
void CleanError(void);

void SetLightStaByCode(int errCode);

int IsStatusChanged(void);
void SendStatus(int force);

void CheckSensorAndPos(void);

//-------------------------------------------------------------------------------

void CheckAndRequestData(void);

void SetFileOkFlag(int flag);

void SaveFileIdxFromDatafile(void);

int GetDatIndex(void);
int DatIndexInc(void);
int DatIndexDec(void);

void ChangeWorkPos(DataItem * pDatItem, int dir);
int GetWorkPosFromIndex(void);

int SetExecProgress(OperPacket * pPkt);

void SetDatIdxToStart(void);

//-------------------------------------------------------------------------------

// 读取并刷新电机位置
void ReadMotosPos(void);
void ReadAndFreshMotosPos(void);
void NormalRefPosition(u32 para, s32 * posilist);

//-------------------------------------------------------------------------------

#define	SET_MOTO_ZERO(mt)		do\
{\
	if (g_workCtrl.zeroEnFlag == DATA_VALID && (g_workCtrl.posEnFlag & mt##_MOD) == (mt##_MOD))\
	{\
		printf("\r\nset %s zero = %d \r\n", #mt, list[mt##_IDX]);\
		printf("before set, zero is %d\r\n", g_workCtrl.zeroPosList[mt##_IDX]);\
		temp = list[mt##_IDX] - g_workCtrl.zeroPosList[mt##_IDX];		/* 当前零位和原零位的差 */\
		temp += g_motosPara.motosPos[mt##_IDX];	/* 设置当前坐标 */\
		printf("set new pos to %d\r\n", temp);\
		printf("old pos=%d, new pos=%d\r\n", g_motosPara.motosPos[mt##_IDX], temp);\
		SetMotoCounter(mt##_IDX, temp);			/* 计数器初值 */\
		ReadAndFreshMotosPos();\
	}\
}while(0);

#define	SET_EX_MOTO_ZERO(mt)		do\
{\
	if (g_workCtrl.zeroEnFlag == DATA_VALID && (g_workCtrl.posEnFlag & mt##_MOD) == (mt##_MOD))\
	{\
		printf("\r\nset %s zero = %d \r\n", #mt, list[EX##mt##_IDX]);\
		printf("before set, zero is %d\r\n", g_workCtrl.zeroPosList[EX##mt##_IDX]);\
		temp = list[EX##mt##_IDX] - g_workCtrl.zeroPosList[EX##mt##_IDX];		/* 当前零位和原零位的差 */\
		temp += g_motosPara.motosPos[mt##_IDX];	/* 设置当前坐标 */\
		printf("set new pos to %d\r\n", temp);\
		printf("old pos=%d, new pos=%d\r\n", g_motosPara.motosPos[mt##_IDX], temp);\
		SetMotoCounter(mt##_IDX, temp);			/* 计数器初值 */\
		ReadAndFreshMotosPos();\
	}\
}while(0);
//-------------------------------------------------------------------------------
#if (AUTO_ELEC_CLIP == 1)
typedef struct
{
	u32 index;
	u8 level;
}__attribute__ ((packed)) DataClip;

extern DataClip g_dataClipLvBuf[256];
#endif
#endif
