#include "clightdriver_wl_socket.h"

#include <iostream>
#include <tchar.h>

#include "clight.h"
#include "logic_eap.h"

//////////////////////////////////////////////////////////////////////////
#define CMD_SET_INTENSITY		3
#define CMD_GET_INTENSITY		4
#define CMD_TURNON_CHANNEL		1
#define CMD_TURNOFF_CHANNEL		2
#define CMD_SET_FLUSH_FIRE		7		// 开启一次频闪
#define CMD_SET_TRICK_MODE		8
#define CMD_SET_FLUSH_TIME		9
#define CMD_GET_SERIAL_ID		6		// 获取序列ID
#define CMD_SET_SPECIFIED_DATA	0		// 设置特殊数据

//////////////////////////////////////////////////////////////////////////
#define TRICK_MODE_LEVEL		1		// 电平触发模式
#define TRICK_MODE_NORMAL		0		// 常亮模式
#define TRICK_MODE_FLUSH_MS		2		// 毫秒频闪模式
#define TRICK_MODE_FLUSH_US		3		// 微秒频闪模式

CLightDriver_WL_Socket::CLightDriver_WL_Socket(const QString& name,int32_t id)
	:CLightDriverSocket(name, id)
{
	m_bMutexLock = FALSE;
	m_bConnectOK = FALSE;
}

CLightDriver_WL_Socket::~CLightDriver_WL_Socket()
{
}

int32_t CLightDriver_WL_Socket::setlight(int32_t iChid, int32_t ibright)
{
    CLight* pLight = (CLight*)FindChannel(iChid);
    Q_ASSERT(pLight);
    int isn = pLight->m_Variants.get_VData(Var_Base_SerialID_ID)->toInt();
#ifdef __SIMULATOR__
#else
    Q_ASSERT(isn > 0 && isn <= 6);
#endif // __SIMULATOR__
    

	if(ibright> 0){
		SetNormalMode(isn);
	}
    //通道号
    return SetIntensity(isn, ibright);
}

int32_t CLightDriver_WL_Socket::freshlight(int32_t iChid)
{
	CLight* pLight=(CLight*)FindChannel(iChid);
	Q_ASSERT(pLight);
	int isn=pLight->m_Variants.get_VData(Var_Base_SerialID_ID)->toInt();
	Q_ASSERT(isn > 0 && isn <= 6);

	int ilight=0;
	if(DBS_SUCCEED != ReadIntensity(isn, &ilight)){
		return RTN_FAILED1;
	}
	pLight->m_Variants.get_VData(Var_Light_Bright_ID)->setValue(int(ilight));
	return RTN_SUCCESS1;
}

int32_t CLightDriver_WL_Socket::setmultiplier(int32_t iChid, int32_t imultiplier)
{
	return CLightDriver::setmultiplier(iChid, imultiplier);
}

int32_t CLightDriver_WL_Socket::init_driver()
{
    m_tcpSocket.Init();

	QString ip = m_Variants.get_VData(VAR_Light_ServerIP_ID)->toString();
	int port = m_Variants.get_VData(VAR_Light_ServerPort_ID)->toInt();

    m_bConnectOK = m_tcpSocket.Connect(ip.toLatin1().data(), port);
	if(false == m_bConnectOK)
	{
		MQT_THROW_CODESTR(ALARM_LIGHT_COMMNUNICATION, QObject::trUtf8("Can not Open Light Controller at %1").arg(ip));
		return RTN_FAILED1;
	}

	return RTN_SUCCESS1;
}
int32_t CLightDriver_WL_Socket::exit_driver()
{
    m_tcpSocket.Uinit();
    return 0;
}

//显示消息函数
void CLightDriver_WL_Socket::DispString(const char *fmt, ...)
{
	//log
    va_list args;
    char rt_log_buf[0xFFFF];

    va_start(args, fmt);
    vsprintf_s(rt_log_buf, fmt, args);
    va_end(args);

	MqDebug() << rt_log_buf;
    std::cout << rt_log_buf << std::endl;
}


/*!
* \函数名称 SetIntensity
* \函数内容 设置光源通道的亮度
* \输入参数 nCH:通道号 取值范围[1-4]
nIntensity:亮度 取值范围[0-255][10进制]
* \返回值   是否设置成功 1.设置成功 -1.设置失败
*/
int CLightDriver_WL_Socket::SetIntensity(int nCH, int nIntensity)
{
    // 给资源加锁
    if (m_bMutexLock == TRUE)
    {
        return DBS_ERR_COMM_TOO_QUICK;
    }
    m_bMutexLock = TRUE;

    int nRtn = 0;

    // 先清空接收队列
    //m_pRxBuf->clear();

    // 发送数据
    nRtn = SendCmd(CMD_SET_INTENSITY, nCH, nIntensity);
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:65] SendCmd:%d", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }

    // 等待返回
    nRtn = WaiteCmdFB();
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:73] WaiteCmdFB:%d", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }
    else
    {
        DispString("recive data", nRtn);
    }

    // 给资源解锁
    m_bMutexLock = FALSE;

    // 返回成功
    return DBS_SUCCEED;
}

/*!
* \函数名称 SetNormalMode
* \函数内容 设置成普通模式，即常亮模式
* \输入参数 nTime:时间 取值范围:10-990[个位数无效]
* \返回值   设置频闪时间成功 1.设置成功 -1.设置失败
*/
int CLightDriver_WL_Socket::SetNormalMode(int nCH)
{
    // 防止指令过快
    if (m_bMutexLock == TRUE)
    {
        return DBS_ERR_COMM_TOO_QUICK;
    }
    m_bMutexLock = TRUE;

    // 清空接收缓冲区
    //m_pRxBuf->clear();

    // 发送指令
    int nRtn = SendCmd(CMD_SET_TRICK_MODE, nCH, TRICK_MODE_NORMAL);
    if (nRtn != DBS_SUCCEED)
    {
        DispString(_T("[LED:224] SendCmd:%d"), nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }

    // 等待指令回复
    nRtn = WaiteCmdFB();
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:264] WaiteCmdFB:%d", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }
    else
    {
        DispString("已收到返回数据", nRtn);
    }

    m_bMutexLock = FALSE;

    return DBS_SUCCEED;
}

/*!
* \函数名称 ReadIntensity
* \函数内容 获取亮度
* \输入参数 nCH:通道号 取值范围:1-4
nIntensity: 数据指针
* \返回值   设置频闪时间成功 1.设置成功 -1.设置失败
*/
int CLightDriver_WL_Socket::ReadIntensity(int nCH, int *nIntensity)
{
    // 防止指令过快
    if (m_bMutexLock == TRUE)
    {
        return DBS_ERR_COMM_TOO_QUICK;
    }
    m_bMutexLock = TRUE;

    // 先清空接收队列
    //m_pRxBuf->clear();

    // 发送读取数据指令
    int nRtn = SendCmd(CMD_GET_INTENSITY, nCH, 0);
    if (nRtn != DBS_SUCCEED)
    {
        DispString(_T("[LED:178] SendCMD:%d."), nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }

    // 等待数据
    nRtn = WaiteCmdFB(CMD_SET_INTENSITY);
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:182] WaiteCMDFB:%d.", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }
    else
    {
        DispString("已收到返回数据", nRtn);
    }

    // 判断收到的数据的通道号是否正确
    if (nCH != m_tFrameInfo.nCH)
    {
        DispString(_T("[LED:193] CH Error:%d-%d."), nCH, m_tFrameInfo.nCH);
        m_bMutexLock = FALSE;
        return DBS_ERR_UNKNOWN;
    }

    // 使用数据
    *nIntensity = m_tFrameInfo.nLightHBit * 16 + m_tFrameInfo.nLightLBit;

    m_bMutexLock = FALSE;

    // 返回数据
    return DBS_SUCCEED;
}


/*!
* \函数名称 TurnOnChannel
* \函数内容 打开通道
* \输入参数 nCH:通道号 取值范围:1-4
* \返回值
*/
int CLightDriver_WL_Socket::TurnOnChannel(int nCH)
{
    // 防止指令过快
    if (m_bMutexLock == TRUE)
    {
        return DBS_ERR_COMM_TOO_QUICK;
    }
    m_bMutexLock = TRUE;

    // 清空接收缓冲区
    //	m_pRxBuf->clear();

    // 发送设置指令
    int nRtn = SendCmd(CMD_TURNON_CHANNEL, nCH, 0);
    if (nRtn != DBS_SUCCEED)
    {
        DispString(_T("[LED:241] SendCmd:%d"), nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }

    // 等待返回指令
    nRtn = WaiteCmdFB();
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:253] WaiteCmdFB:%d", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }
    else
    {
        DispString("已收到返回数据", nRtn);
    }

    m_bMutexLock = FALSE;

    return DBS_SUCCEED;
}

/*!
* \函数名称 TurnOffChannel
* \函数内容 打开通道
* \输入参数 nCH:通道号 取值范围:1-4
* \返回值
*/
int CLightDriver_WL_Socket::TurnOffChannel(int nCH)
{
    // 防止指令过快
    if (m_bMutexLock == TRUE)
    {
        return DBS_ERR_COMM_TOO_QUICK;
    }
    m_bMutexLock = TRUE;

    // 发送设置指令
    int nRtn = SendCmd(CMD_TURNOFF_CHANNEL, nCH, 0);
    if (nRtn != DBS_SUCCEED)
    {
        DispString(_T("[LED:277] SendCmd:%d"), nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }

    // 等待返回指令
    nRtn = WaiteCmdFB();
    if (nRtn != DBS_SUCCEED)
    {
        DispString("[LED:285] WaiteCmdFB:%d", nRtn);
        m_bMutexLock = FALSE;
        return nRtn;
    }
    else
    {
        DispString("已收到返回数据", nRtn);
    }

    m_bMutexLock = FALSE;

    return DBS_SUCCEED;
}

/*!
* \函数名称 SendCmd
* \函数内容 发送指令
* \输入参数 无
* \返回值   发送指令是否成功 1.发送成功 -1.发送失败
*/
int CLightDriver_WL_Socket::SendCmd(int nCMD, int nCH, int nData)
{
    if (m_bConnectOK == FALSE)
    {
        DispString("[LED:209] 网络未连接");
        return DBS_ERR_SOCKET_UNCONNECT;
    }

    unsigned char nSendBuf[20] = { '\0' };

    int nIndex = 0;
    int nSumCheck = 0;

    // 数据头
    nSendBuf[nIndex] = _T('$');
    nSumCheck = nSendBuf[nIndex];
    nIndex++;

    // 指令号
    nSendBuf[nIndex] = (nCMD % 256) + _T('0');
    nSumCheck ^= nSendBuf[nIndex];
    nIndex++;

    // 通道号或者信息1
    unsigned char nDataCH = nCH % 256;
    if (nDataCH < 10) nDataCH += _T('0');
    else nDataCH += _T('A') - 10;
    nSendBuf[nIndex] = nDataCH;
    nSumCheck ^= nSendBuf[nIndex];
    nIndex++;

    // 固定填充值
    nSendBuf[nIndex] = _T('0');
    nSumCheck ^= nSendBuf[nIndex];
    nIndex++;

    // 数据高位
    unsigned char nDataH = (nData % 256) / 16;
    if (nDataH < 10) nDataH += _T('0');
    else nDataH += _T('A') - 10;
    nSendBuf[nIndex] = nDataH;
    nSumCheck ^= nSendBuf[nIndex];
    nIndex++;

    // 数据低位
    unsigned char nDataL = (nData % 256) % 16;
    if (nDataL < 10) nDataL += _T('0');
    else nDataL += _T('A') - 10;
    nSendBuf[nIndex] = nDataL;
    nSumCheck ^= nSendBuf[nIndex];
    nIndex++;

    // 校验高位
    nDataH = nSumCheck / 16;
    if (nDataH < 10) nDataH += _T('0');
    else nDataH += _T('A') - 10;
    nSendBuf[nIndex++] = nDataH;

    // 校验低位
    nDataL = nSumCheck % 16;
    if (nDataL < 10) nDataL += _T('0');
    else nDataL += _T('A') - 10;
    nSendBuf[nIndex++] = nDataL;

    int nRtn = m_tcpSocket.Send((char *)nSendBuf, nIndex);
    if (nRtn == SOCKET_ERROR)	return DBS_ERR_SOCKET_UNCONNECT;

    return DBS_SUCCEED;
}

/*!
* \函数名称 WaiteCmdFB
* \函数内容 等待指令返回
* \输入参数 nCmd:指令号，-1表示只等待反馈
* \返回值
*/
int CLightDriver_WL_Socket::WaiteCmdFB(int nCMD)
{
    //CTimerProc cTimerProc;
    //cTimerProc.SetSystemTimer(1);

    unsigned char nRecvStep = 0;
    unsigned char nRecvData = 0;
    //unsigned char nRecvCnt = 0;
    unsigned char nIndex = 0;

    //unsigned char nRecvCRCBuf[10] = { 0 };	//用于计算校验和
    unsigned char nRecvBuf[1024] = { 0 };	// 接收缓冲区

    DispString(_T("等待数据返回..."));
    m_tcpSocket.Recv((char *)nRecvBuf, 1024);

    //$[cmd+0x30][channel(0~9 or A~F 0~15)]
    //&错误指令
    while (TRUE)
    {
        // 取数据
        nRecvData = nRecvBuf[nIndex++];

        // 处理数据
        switch (nRecvStep)
        {
        case 0:		// 指令头
                    // 仅接收反馈信号，不接收数据
            if (nCMD == -1)
            {
                // 校验成功
                if (nRecvData == _T('$'))
                {
                    return DBS_SUCCEED;
                }

                // 校验失败
                if (nRecvData == _T('&'))
                {
                    return DBS_ERR_VERIFY_FAILED;
                }
            }
            else
            {
                // 收到指令头
                if (nRecvData == _T('$'))
                {
                    nRecvBuf[0] = nRecvData;
                    nRecvStep = 1;
                }
            }
            break;
        case 1:		// 指令号
            if (nRecvData != nCMD + 0x30)
            {
                // 返回的指令号错误
                nRecvStep = 0;
            }
            else
            {
                // 指令号匹配，下一步
                nRecvBuf[1] = nRecvData;

                // 获取序列ID指令格式不同
                if (nCMD != CMD_GET_SERIAL_ID)
                {
                    nRecvStep = 2;
                }
                else
                {
                    nRecvStep = 11;
                    m_tFrameInfo.nCmd = nCMD;
                }
            }
            break;
        case 2:		// 通道号
            if (nRecvData >= _T('0') && nRecvData <= '9')
            {
                nRecvBuf[2] = nRecvData;
                m_tFrameInfo.nCH = nRecvData - '0'; //'0' 0x30
                nRecvStep = 3;
            }
            else if (nRecvData >= _T('A') && nRecvData <= _T('F'))
            {
                nRecvBuf[2] = nRecvData;
                m_tFrameInfo.nCH = nRecvData - 'A' + 10; //'A' 0x41
                nRecvStep = 3;
            }
            else
            {
                nRecvStep = 0;
            }
            break;
        case 3:		// 获取固定填充数据0
            if (nRecvData == _T('0'))
            {
                nRecvBuf[3] = nRecvData;
                nRecvStep = 4;
            }
            else
            {
                return DBS_ERR_BACK_DATA;
            }
            break;
        case 4:		// 接收数据高位
            if (nRecvData >= _T('0') && nRecvData <= '9')
            {
                m_tFrameInfo.nLightHBit = nRecvData - '0';
            }
            else if (nRecvData >= _T('A') && nRecvData <= _T('F'))
            {
                m_tFrameInfo.nLightHBit = nRecvData - 'A' + 10;
            }
            else
            {
                return DBS_ERR_BACK_DATA;
            }

            nRecvBuf[4] = nRecvData;
            nRecvStep = 5;
            break;
        case 5:		// 接收数据低位
            if (nRecvData >= _T('0') && nRecvData <= '9')
            {
                m_tFrameInfo.nLightLBit = nRecvData - '0';
            }
            else if (nRecvData >= _T('A') && nRecvData <= _T('F'))
            {
                m_tFrameInfo.nLightLBit = nRecvData - 'A' + 10;
            }
            else
            {
                return DBS_ERR_BACK_DATA;
            }

            nRecvBuf[5] = nRecvData;
            nRecvStep = 6;
            break;
        case 6:		// 接收校验高位
            if (nRecvData >= _T('0') && nRecvData <= '9')
            {
                m_tFrameInfo.nXORHBit = nRecvData - '0';
            }
            else if (nRecvData >= _T('A') && nRecvData <= _T('F'))
            {
                m_tFrameInfo.nXORHBit = nRecvData - 'A' + 10;
            }
            else
            {
                return DBS_ERR_BACK_DATA;
            }
            nRecvStep = 7;
            break;
        case 7:		// 接收校验低位
            if (nRecvData >= _T('0') && nRecvData <= '9')
            {
                m_tFrameInfo.nXORLBit = nRecvData - '0';
            }
            else if (nRecvData >= _T('A') && nRecvData <= _T('F'))
            {
                m_tFrameInfo.nXORLBit = nRecvData - 'A' + 10;
            }
            else
            {
                return DBS_ERR_BACK_DATA;
            }

            if (1)
            {
                //校验
                int nXORCheckCnt = nRecvBuf[0];
                for (int i = 1; i < 6; i++)
                {
                    nXORCheckCnt ^= nRecvBuf[i];
                }

                int nXORCheck = m_tFrameInfo.nXORHBit * 16 + m_tFrameInfo.nXORLBit;
                if (nXORCheck != nXORCheckCnt)
                {
                    return DBS_ERR_VERIFY_FAILED;
                }

                return DBS_SUCCEED;
            }
            break;
        case 11:
            break;
        default:
            break;
        }

    }
}