
#define _IN_WORKCTRL_C

#include "workctrl.h"

#include "movectrl.h"
#include "error.h"
#include "buttons.h"
#include "inout.h"
#include "shell.h"
#include "debug.h"
#include "trigger.h"
#include "delay.h"
#include "canctrl.h"
#include "extendboards.h"
#include "ethernet.h"
#include "filetrans.h"
#include "installment.h"

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

void OneMinTimerTask(void);

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


#if (AUTO_ELEC_CLIP == 1)
// 电子夹线器区间等级表.
	// 0~239 存放120个区间等级
	// 其中偶数index中存放的起始索引,奇数为终止索引.
	// 起始索引中的level存放夹线力度.终止索引中的level始终为零.

	// 240,241 存放结束符,默认为0

	// 254,255存放默认等级和夹线力度

DataClip g_dataClipLvBuf[256];
#endif

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

#define EXEC_WORK_FUNC(func)	\
do \
{ \
	if (func != NULL) \
	{ \
		func(); \
	} \
}while(0)


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

void InitWorkCtrl(void)
{
	memset(&g_workCtrl, 0, sizeof(WorkCtrl));

	g_workCtrl.embMendEndIdx = -1;			// 20220303增加此初始化

#if (1)			// 暂时允许工作......
	g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;
	g_workCtrl.cursta.workStatus |= WORK_STA_ENSTATE;
#endif

	// 装载保存数据
#if (1)
	printf("sizeof(SavedPara)=%d\r\n", sizeof(SavedPara));
	ReadNVPara((NVPara*)(&g_workCtrl.savedpara), 1);	// 装载保存数据

	if (g_workCtrl.savedpara.mcType != MC_TYPE)
	{
		g_workCtrl.savedpara.enFlag = 0;
	}

	if (g_workCtrl.savedpara.enFlag != NVPARA_EN)
	{
		memset(&g_workCtrl.savedpara, 0, sizeof(g_workCtrl.savedpara));

		g_workCtrl.savedpara.mcType = MC_TYPE;
		g_workCtrl.savedpara.enFlag = NVPARA_EN;
		SaveWorkNvPara();

		printf("2. load save data failed\r\n");
		g_workCtrl.posEnFlag = 0;	// 电机位置失效
	}
	else
	{
		u32 address;
		address = (u32)(&(g_workCtrl.savedpara.motospos[0]));
		SetMotosCounter((s32 *)(address));		// 设置电机位置
		ReadAndFreshMotosPos();
		g_workCtrl.posEnFlag = ALL_MOTO_MOD;				// 电机位置有效

		g_workCtrl.cursta.dataIdx = g_workCtrl.savedpara.dataIdx;			// 装载数据索引
		printf("load fileID=0x%x, dataIdx=%d\r\n", g_workCtrl.savedpara.fileID, g_workCtrl.cursta.dataIdx);

		g_workCtrl.cursta.runSteps = g_workCtrl.savedpara.runSteps;			// 装载运行步骤
		g_workCtrl.cursta.outCounter = g_workCtrl.savedpara.outCounter;		// 装载产量计数
		g_workCtrl.cursta.embNeedleNum = g_workCtrl.savedpara.embNeedleNum;	// 装载刺绣针数
		g_workCtrl.cursta.btrdPics = g_workCtrl.savedpara.btrdPics;			// 装载底线片数计数
		g_workCtrl.cursta.btrdLength = g_workCtrl.savedpara.btrdLength;		// 装载底线长度计数
		g_workCtrl.cursta.fileIdx = g_workCtrl.savedpara.fileIdx;			// 装载文件序号
		g_datFile.fileIdx = g_workCtrl.cursta.fileIdx;						// 装载文件序号
		g_datFile.fileIdxMap = g_workCtrl.savedpara.fileIdxMap;				// 装载文件位图

		printf("2. load save data success\r\n");
	}
#endif

	InitAppCallback();

	InitDebug();

	{
		int rslt;
		rslt = InitInstallment();		// 初始化加密
		if (rslt != 0)	// 已经减去了关机时间
		{
			g_workCtrl.cansetelapsed = 1; // 设置不再接收上位机关机时间命令
		}
		RefreshWorkTimeEn();

		AddTriggerToList(60000, NULL, OneMinTimerTask);			// 1分钟定时任务，工作时间计数
	}
}

__WEAK void InitAppCallback(void)
{
}

void WorkCtrlTask(void)
{
	EXEC_WORK_FUNC(g_workCtrl.WorkRunTask);
	EXEC_WORK_FUNC(g_workCtrl.AsynchronousTask);
}

void TasksWhenDelay(void)
{
	EXEC_WORK_FUNC(g_workCtrl.AsynchronousTask);
	TriggerTask();			// 定时触发任务执行
	ExtendBoardTask();		// 输入输出任务执行
}

void DelayRef(u32 ms)
{
	do
	{
		TasksWhenDelay();

		if (ms <= 0)
		{
			break;
		}
		DelayMs(1);
		ms--;
	}while(1);
}

void DelayRefFt(u32 ms)
{
	u32 us = 0;
	do
	{
		TasksWhenDelay();
		if (ms <= 0)
		{
			break;
		}
		DelayUs(100);
		us++;
		if(us >= 10)
		{
			us = 0;
			ms--;
		}
	}while(1);
}

// 延时同时执行异步任务
void DelayAndAsyncExe(u32 ms)
{
	u32 timb = GetMsSoftTimer();
	do
	{
		TasksWhenDelay();

		u32 tim = GetMsSoftTimer();
		if (tim - timb >= ms)
		{
			break;
		}

	}while(1);
}

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

// 1分钟定时任务
void OneMinTimerTask(void)
{
	RefWorkableTimer(-1);		// 每分钟，计时减少

	RefreshWorkTimeEn();		// 更新允许工作标志
}

void RefreshWorkTimeEn(void)
{
#if	(USE_PASSWORD == 1)	// 强制使用分期付款密码
	if (GetWorkableTime() <= 0)
	{
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_ENTIME);		// 禁止工作(时间)
	}
	else
	{
		g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;		// 允许工作(时间)
	}
#elif (USE_PASSWORD == 2)	// 如果设置过分期付款密码,则按密码执行,否则认为没有密码
	u8 paswd[24];
	int i;

	GetLastpswd(paswd);
	for (i=0;i<24;i++)
	{
		if (paswd[i] != 0)
		{
			break;
		}
	}

	if (i != 24)
	{// 设置过分期密码
		if (GetWorkableTime() <= 0)
		{
			g_workCtrl.cursta.workStatus &= ~(WORK_STA_ENTIME);		// 禁止工作(时间)
		}
		else
		{
			g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;		// 允许工作(时间)
		}
	}
	else
	{// 没有设置过密码
		g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;		// 允许工作(时间)
	}

#elif (USE_PASSWORD == 0)	// 不使用密码
	{
		g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;		// 允许工作(时间)
	}
#endif
}

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

void SaveWorkNvPara(void)
{
	SaveNVPara((NVPara*)(&g_workCtrl.savedpara), 1);
}

__WEAK void RefreshStatus(void)
{
}

__WEAK void RefreshParas(int flag)
{
}

// 设置参数有效标志
void SetNewParasFlag(int flag)
{
	g_workCtrl.paraEnFlag |= flag;

	// 参数接收标志
	printf("set para ok flag\r\n");
	g_workCtrl.cursta.workStatus |= WORK_STA_PARAOK;		// 参数接收标志
}

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

void RequestBoardVer(void)
{
#if (MAX_SUPPORT_COLOR > 0)
	RequestColorsVersion();
	DelayRef(0);
#endif

#if (MAX_SUPPORT_HEAD > 0)
	RequestHeadsVersion();
	DelayRef(0);
#endif

#if (MAX_SUPPORT_EXTIO > 0)
	RequestExtIOsVersion();
	DelayRef(0);
#endif

}

int CreateBoardVer(OperPacket * pPkt, u8 protocol, u8 nodeId, u8 nodeType, BoardRegVal * pRegVal)
{
	if (pPkt == NULL)
	{
		return -1;
	}

	int rslt;

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->sendBoardVer.cmdCode = DCMD_SEND_BOARDVER;
	pPkt->sendBoardVer.protocolType = protocol;
	pPkt->sendBoardVer.nodeType = nodeType;

	if (protocol == BN_PROTOCOL_HEAD)
	{
		pPkt->sendBoardVer.nodeId = nodeId - HEAD_NODEID_BASE + 1;			// 从1开始,上位机不需要知道具体节点ID
	}
	else if (protocol == BN_PROTOCOL_COLOR)
	{
		pPkt->sendBoardVer.nodeId = nodeId - COLOR_NODEID_BASE + 1;			// 从1开始,上位机不需要知道具体节点ID
	}

	memcpy(&pPkt->sendBoardVer.ver, &pRegVal->exbVer, BOARD_VER_LEN*sizeof(u32));

	printf("board version: protocol=%d, nodeid=%d, nodeType=%d\r\n", pPkt->sendBoardVer.protocolType, pPkt->sendBoardVer.nodeId, pPkt->sendBoardVer.nodeType);
	char ver[EX_VER_LEN+1];
	memset(&ver, 0, EX_VER_LEN+1);
	memcpy(&ver, &pPkt->sendBoardVer.ver, BOARD_VER_LEN*sizeof(u32));
	printf("version=%s\r\n", ver);		// 程序版本
	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(pPkt->sendBoardVer.ver)), BOARD_VER_LEN*sizeof(u32));
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateBoardVer\r\n");
	}

	return rslt;
}

int CreateHeadBoardPara(OperPacket * pPkt, u8 nodeId, u8 nodeType, u8* pData)
{
	if (pPkt == NULL || pData == NULL)
	{
		return -1;
	}

	int rslt;

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->boardPara.cmdCode = DCMD_SEND_HEADPARA;

	pPkt->boardPara.nodeId = nodeId;			// headList对应索引,上位机不需要知道具体节点ID,只负责存储在相应变量即可
	pPkt->boardPara.nodeType = nodeType;		// 对应节点类型(平绣,毛巾,缠绕)

	memcpy(&pPkt->boardPara.exData, pData, BOARD_PARA_SIZE);

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(pPkt->boardPara.exData)), BOARD_PARA_SIZE);
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateHeadBoardPara\r\n");
	}

	return rslt;
}

int CreateColorBoardPara(OperPacket * pPkt, u8 nodeId, u8* pData)
{
	if (pPkt == NULL || pData == NULL)
	{
		return -1;
	}

	int rslt;

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->boardPara.cmdCode = DCMD_SEND_COLORPARA;

	pPkt->boardPara.nodeId = nodeId;			// 对应索引,上位机不需要知道具体节点ID,只负责存储在相应变量即可

	memcpy(&pPkt->boardPara.exData, pData, BOARD_PARA_SIZE);

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(pPkt->boardPara.exData)), BOARD_PARA_SIZE);
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateHeadBoardPara\r\n");
	}

	return rslt;
}

int RequestHeadNvParas(int nodetype, int nodeid, int paraid, u32 * pBuf)
{
#if (CUR_MACHINE == MACH_EMB)
	return RequestEmbCoilParasProc(nodeid, pBuf);
#elif (CUR_MACHINE == MACH_WIRE)
	return RequestWireHeadAParaProc(nodeid, 1, paraid, pBuf);
#else
	return 0;
#endif
}

void SetHeadNvPara(int nodetype, int nodeid, int paraid, u32 * pBuf)
{
#if (CUR_MACHINE == MACH_EMB)
	SetEmbCoilParasProc(nodeid, pBuf);
#elif (CUR_MACHINE == MACH_WIRE)
	SetWireHeadAPara(nodeid, paraid, pBuf);
#endif
}

int CreateHeadNvParas(OperPacket * pPkt, u8 nodetype, u8 nodeId, u8 paraid, u8* pData)
{
	if (pPkt == NULL || pData == NULL)
	{
		return -1;
	}

	int rslt;

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->boardPara.cmdCode = DCMD_SEND_HEAD_NVPARAS;

	pPkt->boardPara.nodeId = nodeId;			// 上位机不需要知道具体节点ID,只负责存储在相应变量即可
	pPkt->boardPara.nodeType = nodetype;
	pPkt->boardPara.paraid = paraid;

	memcpy(&pPkt->boardPara.exData, pData, 128);

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(pPkt->boardPara.exData)), 128);
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateHeadNvParas\r\n");
	}

	return rslt;
}

int CreateMcInfo(OperPacket * pPkt, int toggle)
{
	int rslt;
	MCInfo info;
	u16 ver;

	if (pPkt == NULL)
	{
		return -1;
	}

	memset(pPkt, 0, LEN_NORMAL_PACKET);
	memset(&info, 0, sizeof(MCInfo));

	pPkt->sendMcInfo.cmdCode = DCMD_SEND_MC_INFO;
	pPkt->sendMcInfo.toggle = (u16)toggle;

	ver = GetFpgaHardVersion();		// 读取硬件版本信息
	sprintf(info.fpgaHardVerStr, "FPGA Hard: %x.%x", (ver&0xff00)>>8,(ver&0x00ff));

	ver = GetFpgaSoftVersion();		// 读取软件版本信息
	sprintf(info.fpgaSoftVerStr, "FPGA Soft: %x.%x", (ver&0xff00)>>8,(ver&0x00ff));

	GetVersionStr(info.softwareVerStr);		// 软件版本信息

	GetBuildStr(info.buildInfoStr);			// 编译时间信息

	GetBoardIdInfo(info.boardId);			// 板卡ID信息

	GetLastInstallment(info.installment);	// 加密字符串

	printf("create system info len=%d, as follow:\r\n", sizeof(MCInfo));

	printf("%s\r\n", info.fpgaHardVerStr);			// FPGA硬件版本
	printf("%s\r\n", info.fpgaSoftVerStr);       	// FPGA软件版本
	printf("%s\r\n", info.softwareVerStr);      	// 软件版本
	printf("%s\r\n", info.buildInfoStr);        	// 编译日期信息
	printf("%s\r\n", info.boardId);             	// 板卡ID
	printf("%s\r\n", info.installment);         	// 最后一次的分期密码字符串

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(info)), sizeof(MCInfo));
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateMcInfo\r\n");
	}

	return rslt;
}

// 运行状态
int CreateMcStatus(OperPacket * pPkt, int toggle)
{
	int rslt;
	if (pPkt == NULL)
	{
		return -1;
	}

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->sendMcStatus.cmdCode = DCMD_SEND_MC_STATUS;
	pPkt->sendMcStatus.toggle = (u16)toggle;

//	printf("create mc status len=%d\r\n", sizeof(MCStatus));

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(g_workCtrl.cursta)), sizeof(MCStatus));
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateMcStatus\r\n");
	}

	return rslt;
}

// 运行文件位图
int CreateFileList(OperPacket * pPkt, int toggle)
{
	int rslt;
	if (pPkt == NULL)
	{
		return -1;
	}

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->setFilesList.cmdCode= DCMD_SEND_FILE_LIST;
	pPkt->setFilesList.fileIdxMap = (u16)toggle;

//	printf("create mc status len=%d\r\n", sizeof(MCStatus));

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(g_workCtrl.cursta)), sizeof(MCStatus));
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateMcStatus\r\n");
	}

	return rslt;
}

__WEAK void SensorsStatus(int mode, u8 * buf)
{
}

// 传感信号
int CreateSensorsStatus(OperPacket * pPkt)
{
	int rslt;
	u8 insta[MAX_EXDP_LEN];
	if (pPkt == NULL)
	{
		return -1;
	}

	memset(pPkt, 0, LEN_NORMAL_PACKET);
	memset(&insta, 0, MAX_EXDP_LEN);

	pPkt->sendSensors.cmdCode = DCMD_SEND_SENSORS;

	SensorsStatus(0, &insta[0]);

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(insta)), MAX_EXDP_LEN);
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateMcStatus\r\n");
	}

	return rslt;
}


// 传感信号位图
int CreateSensorsBmp(OperPacket * pPkt)
{
	int rslt;
	u8  insta[MAX_EXDP_LEN];

	if (pPkt == NULL)
	{
		return -1;
	}

	memset(pPkt, 0, LEN_NORMAL_PACKET);

	pPkt->sendSensors.cmdCode = DCMD_SEND_SENSORS_BMP;

	SensorsStatus(1, &insta[0]);

	rslt = PacketAVLDP(&(pPkt->packet), (u8*)(&(insta)),MAX_EXDP_LEN);
	if (rslt != 0)
	{
		printf("error at call PacketAVLDP in CreateSensorsBmp\r\n");
	}

	return rslt;
}

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

// 遍历任务
void TraverseTask(u8 protocol, u8 nodeId, u8 nodeType, int traNum)
{
#if (CUR_MACHINE == MACH_EMB)	// 绣花机
	EmbTraverseTask(nodeId, nodeType, traNum);
#elif (CUR_MACHINE == MACH_WIRE)
	WireTraverseTask(nodeId, traNum);
#else
#endif
}

void ResetCHB(u32 hdsel)
{
	g_workCtrl.cursta.errorCode = ERR_NONE;
	g_workCtrl.almflashGreen = ALM_LIT_FLASH;
	g_workCtrl.almflashRed = ALM_LIT_OFF;
	g_workCtrl.almflashYello = ALM_LIT_OFF;
	g_workCtrl.almflashBee = ALM_LIT_OFF;

	g_workCtrl.cursta.btrdLength = g_workCtrl.chBobbinLength;
	g_workCtrl.savedpara.btrdLength = g_workCtrl.cursta.btrdLength;
	g_workCtrl.cursta.btrdPics = g_workCtrl.chBobbinPics;
	g_workCtrl.savedpara.btrdPics = g_workCtrl.cursta.btrdPics;

	SaveWorkNvPara();

	printf("get cmd MC_CLEAN_BOBBIN\r\n");

	ReportError(0);
}

// 设置工作状态
void SetMcStatus(u32 sta, u32 para)
{
	switch(sta)
	{
	case MC_STA_CLENA_ERR:		// 清除错误
		CleanError();
		break;
	case MC_STA_EN_WORK:		// 允许工作(状态)
		printf("set en work sta\r\n");
		g_workCtrl.cursta.workStatus |= WORK_STA_ENSTATE;
		break;
	case MC_STA_DIS_WORK:		// 禁止工作(状态)
		printf("set dis work sta\r\n");
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_ENSTATE);
		break;
	case MC_STA_EN_TIME:		// 允许工作(时间)
		g_workCtrl.cursta.workStatus |= WORK_STA_ENTIME;
		break;
	case MC_STA_DIS_TIME:		// 禁止工作(时间)
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_ENTIME);
		break;
	case MC_CLEAN_COUNT:		// 产量计数清零
	{
		if (para == 0)
		{
			g_workCtrl.cursta.outCounter = 0;
			g_workCtrl.cursta.embNeedleNum = 0;		// 20211027,增加清空产量的同时清空刺绣针数
		}
		else
		{
			int decinc = (s16)para;
			decinc += g_workCtrl.cursta.outCounter;
			if (decinc < 0)
			{
				decinc = 0;
			}
			g_workCtrl.cursta.outCounter = decinc;
		}
		g_workCtrl.savedpara.outCounter = g_workCtrl.cursta.outCounter;
		g_workCtrl.savedpara.embNeedleNum = g_workCtrl.cursta.embNeedleNum;

		SaveWorkNvPara();
		ReportError(0);
		break;
	}
	case MC_STA_MANUAL:			// 手动工作状态
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_WKAUTO);
		break;
	case MC_STA_AUTO:			// 自动工作状态
		g_workCtrl.cursta.workStatus |= WORK_STA_WKAUTO;
		break;
	case MC_FILE_SWITCH:		// 文件切换
		g_workCtrl.cursta.fileIdx = para;
		break;
	case MC_INVALID_FILE:		// 文件失效命令
		InvalidDatFile(para);
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_EN_SCAN);	// 禁止扫码
		printf("get InvalidDatFile cmd, Reset work sta en scan1\r\n");
		break;
	case MC_CLEAN_PARA_REF:		// 清除刷新参数标志
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_NEW_PARA);
		break;
	case MC_SET_TO_NORMAL:		// 设置为正常工作状态
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_SIMULATE);
		break;
	case MC_SET_TO_SIMULATE:	// 设置为模拟工作状态
		g_workCtrl.cursta.workStatus |= WORK_STA_SIMULATE;
		break;
	case MC_CLEAN_FIDX:
		SetDatIdxToStart();
		/*
		g_workCtrl.cursta.dataIdx = 0;	// 文件索引复位
		g_workCtrl.savedpara.dataIdx = g_workCtrl.cursta.dataIdx;
		SaveWorkNvPara();
		GetWorkPosFromIndex();*/
		break;
	case MC_CLEAN_BOBBIN:		// 底线计数复位
		ResetCHB(para);
		break;
	case MC_SET_ENTER_SCAN_SENSOR:		// 设置为 进入 扫描传感器状态
		g_workCtrl.cursta.workStatus |= WORK_STA_SENSOR;
		printf("get MC_SET_ENTER_SCAN_SENSOR cmd\r\n");
		break;
	case MC_SET_EXIT_SCAN_SENSOR:	// 设置为 退出 扫描传感器状态
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_SENSOR);
		CleanButtonTask();
		printf("get MC_SET_EXIT_SCAN_SENSOR cmd\r\n");
		break;
	case MC_SET_ENTER_TEST_OUTPUT:		// 设置为 进入 测试输出状态
		g_workCtrl.cursta.workStatus |= WORK_STA_OUTPUT;
		printf("get MC_SET_ENTER_TEST_OUTPUT cmd\r\n");
		break;
	case MC_SET_EXIT_TEST_OUTPUT:	// 设置为 退出 测试输出状态
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_OUTPUT);
		CleanButtonTask();
		printf("get MC_SET_EXIT_TEST_OUTPUT cmd\r\n");
		break;

	case MC_STA_EXIT_TRA:			// 退出遍历状态
	{
		g_workCtrl.cursta.workStatus |= WORK_STA_TRAVERSE;
		break;
	}

	case MC_STA_EXIT_THREADBK:	// 退出断线检测状态
	{
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_DETBK);
		break;
	}

	case MC_INVALID_FILEBLOCK:	// 文件数据块失效命令(网络服务器实时传输花样文件)
	{
		InvalidDatBlock();
		break;
	}
	default:
		break;
	}
}

// 手动控制
int ControlByHand(OperPacket * pPkt)
{
	int err;
	printf("receive ctrl by hand, actcode=0x%x, para1=0x%x, para2=0x%x, para3=0x%x\r\n",
			pPkt->actByhand.actCode, pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);

	err = ERR_NONE;

	if (err != ERR_NONE)
	{
		ReportError(err);
		return err;
	}

	switch (pPkt->actByhand.actCode)
	{
		case MOTO_TO_ZERO:		// 电机归零
			MotoToZero(pPkt->actByhand.para1);
			break;
		case MOVE_BY_HAND:		// 电机手动移动
//			printf("para1=%d, para2=%d, para3=%d\r\n", pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			MoveMotoByHand(pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			break;
		case OUTPUT_CTRL:		// 输出控制
			OutputByHand(pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			break;
		case MOTO_EN_CTRL:		// 伺服打开关闭
			MotosServoCtrl(pPkt->actByhand.para1, pPkt->actByhand.para2);
			break;
		case MANUAL_ACTION:		// 手动控制功能
			ManualActionCtrl(pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			break;
		case TEST_THREADBK:		// 测试断线检测
			TestThreadBreak(pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			break;
		case SHAKE_FRAME_TEST:	// 抖框测试
			ShakeFrameTest(pPkt->actByhand.para1, pPkt->actByhand.para2, pPkt->actByhand.para3);
			break;

		default:
			break;
	}

	return 0;
}

__WEAK void MotoToZero(u16 obj)
{
}

__WEAK void MoveMotoByHand(u16 obj, u16 dir, u16 spd)
{
}

__WEAK void OutputByHand(u16 obj, u16 act, u16 para)
{
}

__WEAK void MotosServoCtrl(u16 obj, u16 onoff)
{
}

__WEAK void ManualActionCtrl(u16 obj, u16 para2, u16 para3)
{
}

__WEAK void TestThreadBreak(int type, int needle, int head)
{
}

void ShakeFrameTest(u16 ofstx, u16 ofsty, u16 runspd)
{
#if (CUR_MACHINE == MACH_WIRE)
	WireShakeFrameTest(ofstx, ofsty, runspd);
#endif
}

int ControlWork(OperPacket * pPkt)
{
	printf("work cmd, code=0x%x\r\n", pPkt->mcWork.workCode);
	switch(pPkt->mcWork.workCode)
	{
		case WORK_START:		// 启动工作
		{
			break;
		}
		case WORK_PAUSE:		// 暂停工作
		{
			break;
		}
		case WORK_FINISH:		// 流程复位
		{
			AllToReset();
			break;
		}
		case WORK_FIND_ZERO:	// 自动找零
		{
			AllToZero();
			break;
		}
		case WORK_GOTO_START:	// 回起点
		{
			GotoStartPos();
			break;
		}
		case WORK_GOTO_ANCHOR:	// 回定位点
		{
			GotoAnchorPos();
			break;
		}
		case WORK_GOTO_OFFSET:	// 回偏移点
		{
			GotoOffsetPos();
			break;
		}
		case WORK_SET_OFFSET:	// 定偏移点
		{
			SetOffsetPos();
			break;
		}
		case WORK_CHECK_FRAME:	// 边框检查
		{
			CheckFrame();
			break;
		}

		case WORK_SIMULATION_FRAME:	// 空走边框
		{
			SimulationFrame();
			break;
		}

		case WORK_FAST_JUMP:	// 快速进退
		{
			FastJump(pPkt->mcWork.para1);
			break;
		}

		case WORK_GOTO_WKPOS:	// 回工作点
		{
			GotoWorkPos();
			break;
		}

		case WORK_GOTO_FINISH:	// 回结束点
		{
			GotoFinishPos();
			break;
		}
		case WORK_GOTO_ZERO:	// 回零点位
		{
			GotoFrameZeroPos();
			break;
		}

		case WORK_RPM_CHG:		// 速度改变
		{
			ChangeRpm((int)(pPkt->mcWork.para1));
			break;
		}

		case WORK_FILE_IDX_CHG:		// 文件序号改变
		{
			g_workCtrl.cursta.fileIdx = (pPkt->mcWork.para1);
			break;
		}

		case WORK_GOTO_FEED:		// 回上料点
		{
			GotoFeedPos();
			break;
		}
		case WORK_SET_FEED:			// 定上料点
		{
			SetFeedPos();
			break;
		}
		case WORK_ACT_OIL:			// 手动加油
		{
			OilingInWorking(pPkt->mcWork.para1);
			break;
		}

		default:
			break;
	}

	return 0;
}

int ControlWorkWhenWorking(OperPacket * pPkt)
{
	if (pPkt == NULL)
	{
		return -1;
	}
	printf("work cmd when work, code=0x%x\r\n", pPkt->mcWork.workCode);
	switch(pPkt->mcWork.workCode)
	{
		case WORK_PAUSE:		// 暂停工作
		{
			g_workCtrl.stopFlag = 1;
			break;
		}
		case WORK_RPM_CHG:    // 速度改变
		{
			ChangeRpm((int)(pPkt->mcWork.para1));
			break;
		}
		case WORK_ACT_OIL:		// 工作中手动加油
		{
			OilingInWorking(pPkt->mcWork.para1);
			break;
		}
		default:
			break;
	}

	return 0;
}

__WEAK void ChangeRpm(int rpmchg)
{
}

// 流程复位
__WEAK void AllToReset(void)
{
}

__WEAK void AllToZero(void)
{
}

__WEAK int GotoStartPos(void)
{
	return 0;
}

__WEAK int GotoAnchorPos(void)
{
	return 0;
}

__WEAK int GotoOffsetPos(void)
{
	return 0;
}

__WEAK void SetOffsetPos(void)
{
}

__WEAK int GotoWorkPos(void)
{
	return 0;
}

__WEAK int GotoFinishPos(void)
{
	return 0;
}

__WEAK int GotoFeedPos(void)
{
	return 0;
}

__WEAK void SetFeedPos(void)
{
}

__WEAK int GotoFrameZeroPos(void)
{
	return 0;
}

__WEAK int CheckFrame(void)
{
	return 0;
}

// 空走边框
void SimulationFrame(void)
{
#if (CUR_MACHINE == MACH_EMB)
	EmbSimulationFrame();
#endif
}

__WEAK int FastJump(u32 idx)
{
	return 0;
}

__WEAK void OilingInWorking(u32 para1)
{
}

__WEAK int MoveFrameToPos(s32 posx, s32 posy)
{
	return 0;
}

// 定量移框
__WEAK int FixMoveFrame(s32 xmvmnt, s32 yxmvmnt)
{
	return 0;
}

void MoveFrameTo(OperPacket * pPkt)
{
	s32 posx, posy;

	posx = pPkt->moveFrameTo.posx;
	posy = pPkt->moveFrameTo.posy;

	printf("move to cmd, posx=%d, posy=%d\r\n", posx, posy);

	MoveFrameToPos(posx, posy);

}

void MoveFrameAsOfst(OperPacket * pPkt)
{
	s32 ofstx, ofsty;

	ofstx = pPkt->moveFrameTo.posx;
	ofsty = pPkt->moveFrameTo.posy;

	printf("move as ofst cmd, ofstx=%d, ofsty=%d\r\n", ofstx, ofsty);

	FixMoveFrame(ofstx, ofsty);
}

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

int ReportError(int errCode)
{
	if (errCode != g_workCtrl.cursta.errorCode)
	{
		printf("Error: code=0x%x\r\n", errCode);
		//printf("cursta work status 0x%x\r\n",g_workCtrl.cursta.workStatus);
	}

	g_workCtrl.cursta.errorCode = errCode;

	SendStatus(1);
	return 0;
}

void CleanError(void)
{
	ReportError(ERR_NONE);
}

__WEAK void SetLightStaByCode(int errCode)
{
	if (errCode == 0 || (errCode >= 0x100 && errCode < 0x200))	// 状态
	{
		if (((g_workCtrl.cursta.workStatus & WORK_STA_WORKING) == WORK_STA_WORKING) ||
			((g_workCtrl.cursta.workStatus & WORK_STA_SIMULATE) == WORK_STA_SIMULATE) ||
			((g_workCtrl.cursta.workStatus & WORK_STA_BUSY) == WORK_STA_BUSY) ||
			0 )
		{
			g_workCtrl.almflashRed = ALM_LIT_OFF;		// 关红灯
			g_workCtrl.almflashGreen = ALM_LIT_FLASH;	// 开绿灯
			g_workCtrl.almflashYello = ALM_LIT_OFF;		// 关黄灯
			g_workCtrl.almflashBee = ALM_LIT_OFF;		// 闪蜂鸣器
		}
		else
		{
			g_workCtrl.almflashRed = ALM_LIT_OFF;		// 关红灯
			g_workCtrl.almflashGreen = ALM_LIT_OFF;		// 关绿灯
			g_workCtrl.almflashYello = ALM_LIT_ON;		// 开黄灯
			g_workCtrl.almflashBee = ALM_LIT_OFF;		// 关蜂鸣器
		}
	}
	else	// 错误
	{
		g_workCtrl.almflashRed = ALM_LIT_FLASH;		// 开红灯
		g_workCtrl.almflashGreen = ALM_LIT_OFF;		// 关绿灯
		g_workCtrl.almflashYello = ALM_LIT_OFF;		// 关黄灯
		g_workCtrl.almflashBee = ALM_LIT_FLASH;		// 闪蜂鸣器
	}
}

// 状态改变判断
int IsStatusChanged(void)
{
	int rslt;

	RefreshStatus();

	g_workCtrl.cursta.workableTimer = GetWorkableTime();		// 更新计数值

	// 比较，不同则发送
	rslt = memcmp(&(g_workCtrl.oldsta), &(g_workCtrl.cursta), sizeof(MCStatus));
	if (rslt != 0)
	{
		memcpy(&(g_workCtrl.oldsta), &(g_workCtrl.cursta), sizeof(MCStatus));
	}
	return rslt;
}

void SendStatus(int force)
{
	SendMcStatus(force);
}

__WEAK void CheckSensorAndPos(void)
{
}

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

// 查询当前数据执行进度，并从上位机请求数据
void CheckAndRequestData(void)
{
	static int olddatblockIdx = -1;	// 记录上一次请求的数据块ID
	static u32 requesttimer = 0;	// 请求时间记录
	if (IsDatFileAvailable() == TRUE &&	// 20231017
			g_datFile.storage == STORAGE_NETWORK &&		// 20240204
			g_workCtrl.requestFlag == 0 &&		// 20240606
			1)
	{
		u32 timer = GetMsSoftTimer();

		int datblockIdx = GetBlockIdxNeedtoLoad(GetDatIndex());
		if (datblockIdx >= 0)
		{
			if (olddatblockIdx != datblockIdx ||
					((timer - requesttimer) > REQUEST_GAP) ||
					0)
			{
				olddatblockIdx = datblockIdx;
				requesttimer = timer;
				RequestADataBlock(datblockIdx);
			}
		}
	}
}

void SetFileOkFlag(int flag)
{
	if (flag == 0)
	{
		printf("clean file ok flag\r\n");
		g_workCtrl.cursta.workStatus &= ~(WORK_STA_FILEOK);	// 文件接收标志
	}
	else
	{
		printf("set file ok flag\r\n");
		g_workCtrl.cursta.workStatus |= WORK_STA_FILEOK;		// 文件接收标志
	}

	SendStatus(0);
}

void SaveFileIdxFromDatafile(void)
{
	g_workCtrl.cursta.fileIdx = g_datFile.fileIdx;
	g_workCtrl.savedpara.fileIdxMap = g_datFile.fileIdxMap;
	g_workCtrl.savedpara.fileIdx = g_workCtrl.cursta.fileIdx;
	SaveWorkNvPara();
}

int GetDatIndex(void)
{
	return g_workCtrl.cursta.dataIdx;
}

int DatIndexInc(void)
{
	int rslt;
	rslt = g_workCtrl.cursta.dataIdx + 1;

	if (IsDatIndexAvailable(rslt) == TRUE)
	{
		g_workCtrl.cursta.dataIdx = rslt;
		g_workCtrl.savedpara.dataIdx = g_workCtrl.cursta.dataIdx;
		SaveWorkNvPara();
	}
	else
	{
		rslt = -1;
	}

	return rslt;
}

int DatIndexDec(void)
{
	if (g_workCtrl.cursta.dataIdx != 0)
	{
		g_workCtrl.cursta.dataIdx--;

		g_workCtrl.savedpara.dataIdx = g_workCtrl.cursta.dataIdx;
		SaveWorkNvPara();
		return g_workCtrl.cursta.dataIdx;
	}
	else
	{
		return -1;
	}
}

__WEAK int GetWorkPosFromIndex(void)
{
	return 0;
}

int SetExecProgress(OperPacket * pPkt)
{
	int rslt;
	FileExecPara execPara;

	if (pPkt == NULL)
	{
		return -1;
	}

	if (pPkt->setExecProgress.exLen != sizeof(execPara))
	{
		printf("receive len not equ, receivelen=%d, FileExecPara = %d", pPkt->setExecProgress.exLen, sizeof(execPara));
		rslt = -2;
	}
	else
	{
		memcpy((u8*)(&execPara), pPkt->setExecProgress.exData, sizeof(execPara));
		rslt = 0;
	}

	if (rslt == 0)
	{
#if (CUR_MACHINE == MACH_EMB)
		rslt = EmbSetProgress(&execPara);
#elif (CUR_MACHINE == MACH_PES)
		rslt = PESSetProgress(&execPara);
#endif
		if (rslt == 0)	// 20231017
		{
			g_workCtrl.savedpara.dataIdx = g_workCtrl.cursta.dataIdx;
			SaveWorkNvPara();
		}
	}

	return rslt;
}

// 数据从头开始
void SetDatIdxToStart(void)
{
	g_workCtrl.cursta.dataIdx = 0;			// 当前花样的针迹数据索引

	g_workCtrl.cursta.colorIdx = 0;			// 20220708 数据从头开始,色序也应该从头开始

	g_workCtrl.savedpara.dataIdx = g_workCtrl.cursta.dataIdx;
	SaveWorkNvPara();

	// 机头补绣
	g_workCtrl.embMendEndIdx = -1;
	g_workCtrl.embMendTrdFlag = 0;
	g_workCtrl.mendEndPatternIdx = 0;

	GetWorkPosFromIndex();

#if (CUR_MACHINE == MACH_EMB)
	EmbSetDatIdxToStart();
#endif

}

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

void SaveToNvArea(s32 * posilist)
{
	if (posilist != NULL)
	{
		memcpy((s32 *)(&(g_workCtrl.savedpara.motospos[0])), posilist, sizeof(s32)*AXIS_NUM);
		SaveWorkNvPara();
	}
}

void ReadAndFreshMotosPos(void)
{
	s32 pos[AXIS_NUM];

	if (GetMotosCounter(pos) == 0)
	{
		RefreshMotosPos(pos);
		SaveToNvArea(pos);		// 保存到掉电保护区域
	}
}

void ReadMotosPos(void)
{// 只刷新,不保存
	s32 pos[AXIS_NUM];

	if (GetMotosCounter(pos) == 0)
	{
		RefreshMotosPos(pos);
		//SaveToNvArea(pos);		// 保存到掉电保护区域
	}
}

void NormalRefPosition(u32 para, s32 * posilist)
{
	SaveToNvArea(posilist);
}

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


