/*
 * UartContext.cpp
 *
 *  Created on: Sep 5, 2017
 *      Author: guoxs
 */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <memory.h>
#include <termio.h>
#include <sys/ioctl.h>

#include "uart/ProtocolSender.h"
#include "uart/UartContext.h"
#include "utils/CrcCheckUtil.h"
#include "utils/ByteUtil.h"
#include "utils/Log.h"
#include "base/strings.hpp"
#include "service/BusinessConfig.h"

#define UART_DATA_BUF_LEN			16384	// 16KB

extern int parseProtocol(std::string revStr);

static const char* getBaudRate(UINT baudRate) {
	struct {
		UINT baud;
		const char *pBaudStr;
	} baudInfoTab[] = {
		{ B1200, "B1200" },
		{ B2400, "B2400" },
		{ B4800, "B4800" },
		{ B9600, "B9600" },
		{ B19200, "B19200" },
		{ B38400, "B38400" },
		{ B57600, "B57600" },
		{ B115200, "B115200" },
		{ B230400, "B230400" },
		{ B460800, "B460800" },
		{ B921600, "B921600" }
	};

	int len = sizeof(baudInfoTab) / sizeof(baudInfoTab[0]);
	for (int i = 0; i < len; ++i) {
		if (baudInfoTab[i].baud == baudRate) {
			return baudInfoTab[i].pBaudStr;
		}
	}

	return NULL;
}

UartContext::UartContext(int uartNum) :
	mIsOpen(false),
	mUartID(0),
	mDataBufPtr(NULL),
	mDataBufLen(0),
	mUartNumber(uartNum){

}

UartContext::~UartContext() {
	delete[] mDataBufPtr;
	closeUart();
}

static bool mUart1IsOpen = false;
static bool mUart2IsOpen = false;
static bool mUart3IsOpen = false;


bool UartContext::openUart(const char *pFileName, UINT baudRate) {
	LOGD("openUart pFileName = %s, baudRate = %s\n", pFileName, getBaudRate(baudRate));
	mUartID = open(pFileName, O_RDWR|O_NOCTTY);

	if (mUartID <= 0) {
		mIsOpen = false;
		if (mUartNumber == 1) {
			mUart1IsOpen = false;
		}
		if (mUartNumber == 2) {
			mUart2IsOpen = false;
		}
		if (mUartNumber == 3) {
			mUart3IsOpen = false;
		}
		LOGD("uart%d open error", mUartNumber);
	} else {
		struct termios oldtio = { 0 };
		struct termios newtio = { 0 };
		tcgetattr(mUartID, &oldtio);

		newtio.c_cflag = baudRate|CS8|CLOCAL|CREAD;
		newtio.c_iflag = 0;	// IGNPAR | ICRNL
		newtio.c_oflag = 0;
		newtio.c_lflag = 0;	// ICANON
		newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
		newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
		tcflush(mUartID, TCIOFLUSH);
		tcsetattr(mUartID, TCSANOW, &newtio);

		// 设置为非阻塞 Set to non-blocking
		fcntl(mUartID, F_SETFL, O_NONBLOCK);

		mIsOpen = run("uart");
		if (!mIsOpen) {
			close(mUartID);
			mUartID = 0;
		}

		if(mUartNumber == 1) {
			mUart1IsOpen = true;
			LOGD("openUart1 mIsOpen = %d\n", mIsOpen);
		}
		if (mUartNumber == 2) {
			mUart2IsOpen = true;
			LOGD("openUart2 mIsOpen = %d\n", mIsOpen);
		}
		if(mUartNumber == 3) {
			mUart3IsOpen = true;
			LOGD("openUart3 mIsOpen = %d\n", mIsOpen);
		}
	}

	return mIsOpen;
}

void UartContext::closeUart() {
	LOGD("closeUart mIsOpen: %d...\n", mIsOpen);
	if (mIsOpen) {
		requestExit();

		close(mUartID);
		mUartID = 0;
		mIsOpen = false;
	}
}

bool UartContext::send(const BYTE *pData, UINT len) {
	// 这里是串口没有打开
	if (!mIsOpen) {
		LOGD("uart%d not opend", mUartNumber);
		return false;
	}


	int ret = write(mUartID, pData, len); // 这是发送串口消息
	if (ret != (int) len) {	// 这里是发送失败
		LOGD("发送串口消息失败\n");
		return false;
	}

//	std::string logInfo = " >>> ";
//	for (int i = 0; i < len; ++i) {
//		logInfo += base::format("%02x",pData[i]);
//	}
//	LOGD("发送串口消息： %s",logInfo.c_str());



	// success
	LOGD("send Success\n");
	if (len > 10) {
		usleep(1000 * 100);
	}
	else {
		usleep(1000 * 50);
	}

	return true;
}

//UartContext* UartContext::getInstance() {
//	static UartContext sUC;
//	return &sUC;
//}

bool UartContext::readyToRun() {
	if (mDataBufPtr == NULL) {
		mDataBufPtr = new BYTE[UART_DATA_BUF_LEN];
	}

	if (mDataBufPtr == NULL) {
		closeUart();
	}

	return (mDataBufPtr != NULL);
}


void alarmData(int ret, unsigned char* buffer) {
	if (ret<5){
		return;
	}
	std::string revStr = "";
	//依次将读取到的数据输出到日志
	for (int i = 0; i < ret; ++i) {
		if (i == 0 || i == (ret-1)){
			continue;
		}
		revStr += base::format("%02x",buffer[i]);
	}

	if (revStr.size() == 6) {
		parseProtocol(revStr);
	}
}


void oursLoraData(int ret, unsigned char* buffer) {
    if (buffer[0] != 0x24) {
        return;
    }

    // 检查数据是否以 0x23 0x0d 0x0a 结尾
    if (ret < 4 || buffer[ret - 3] != 0x23 || buffer[ret - 2] != 0x0d || buffer[ret - 1] != 0x0a) {
        return;
    }

	std::string revStr = "";
	//依次将读取到的数据输出到日志
	for (int i = 1; i < ret - 4; ++i) {
		revStr += base::format("%02x",buffer[i]);
	}
	parseProtocol(revStr);
}


static unsigned char loraBuffer[1024] = {0};
static int loraBufferSize = 0;
static int loraMsgSize = 0;
static std::string loraMsg = "";
void loraDataInit() {
	loraBufferSize = 0;
	loraMsgSize = 0;
	std::fill(std::begin(loraBuffer), std::end(loraBuffer), 0);
	loraMsg = "";
}

void loraData(int ret, unsigned char* buffer) {
	if (loraBufferSize == 0 && buffer[0] != 0xa8) {
		return;
	}

	for (int i = 0; i < ret; i++) {
		loraBuffer[loraBufferSize + i] = buffer[i];
	}
	loraBufferSize += ret;

	if (loraMsgSize == 0 && loraBufferSize > 2) {
		loraMsgSize = loraBuffer[1] + 3;
		if (loraMsgSize > 1024) {
			loraDataInit();
			return;
		}
	}

	if (loraMsgSize == 0 || loraMsgSize > loraBufferSize) {
		return;
	}

	for (int i = 0; i < loraMsgSize; ++i) {
		loraMsg += base::format("%02x",loraBuffer[i]);
	}


//	if (CrcCheckHelper::loraCheck(loraBuffer, loraBufferSize)) {
	parseProtocol(loraMsg);
//	}

	loraDataInit();
}



static unsigned char co2Buffer[16] = {0};
static int co2BufferSize = 0;
void co2Data(int ret, unsigned char* buffer) {
    if (ret < 16) {
    	for (int i = 0; i < ret; ++i) {
    		co2Buffer[co2BufferSize + i] = buffer[i];
    	}
    	co2BufferSize += ret;

    	if (co2BufferSize < 16) {
        	return;
    	}
    	else {
    		co2BufferSize = 0;
    	}
    }
    else {
    	ByteUtil::copyUnsignedCharArray(buffer, co2Buffer, ret);
    }

	if (co2Buffer[0] == 0x42 && co2Buffer[1] == 0x4D && CrcCheckHelper::Co2Check(co2Buffer, 15, co2Buffer[15])) {
		int co2 = co2Buffer[6] * 256 + co2Buffer[7];
		LOGD("co2 ========================> %d", co2);
	}
	return;
}



static unsigned char particleBuffer[32] = {0};
static int particleBufferSize = 0;
void particleData(int ret, unsigned char* buffer) {
    if (ret < 32) {
    	for (int i = 0; i < ret; ++i) {
    		particleBuffer[particleBufferSize + i] = buffer[i];
    	}
    	particleBufferSize += ret;

    	if (particleBufferSize < 32) {
        	return;
    	}
    	else {
    		particleBufferSize = 0;
    	}
    }
    else {
    	ByteUtil::copyUnsignedCharArray(buffer, particleBuffer, ret);
    }

	if (particleBuffer[0] == 0x42 && particleBuffer[1] == 0x4D && CrcCheckHelper::ParticleCheck(particleBuffer, 30, particleBuffer[31])) {

		uint16_t particle = CrcCheckHelper::CombineHighLow(particleBuffer[6], particleBuffer[7]);
		LOGD("particle ========================> %d μg/m³\n", particle);
	}
	return;
}



static unsigned char s433Buffer[1024] = {0};
static int s433BufferSize = 0;
static int s433DataSize = 0;
static std::string s433DataStr = "";
void s433DataInit() {
	s433BufferSize = 0;
	s433DataSize = 0;
	std::fill(std::begin(s433Buffer), std::end(s433Buffer), 0);
	s433DataStr = "";
}

void s433Data(int ret, unsigned char* buffer) {
//	if (buffer[0] == 0x24 && buffer[1] == 0x30 && buffer[2] == 0x23) {
//		const char* sendMsg = "1";
//		sendProtocolTo(UART_TTYS1, (byte*)(sendMsg), strlen(sendMsg));
//		return;
//	}

	if (s433BufferSize == 0 && buffer[0] != 0x24) {
		return;
	}

	for (int i = 0; i < ret; i++) {
		s433Buffer[s433BufferSize + i] = buffer[i];
	}
	s433BufferSize += ret;

	if (s433DataSize == 0 && s433BufferSize > 3) {
		s433DataSize = (s433Buffer[1] << 8) | s433Buffer[2];
		if (s433DataSize> 1024) {
			s433DataInit();
			return;
		}
	}

	if (s433DataSize == 0 || s433DataSize > s433BufferSize) {
		return;
	}

	for (int i = 0; i < s433DataSize; ++i) {
		if (i == 0 || i == 1 || i == 2 || i >= (s433DataSize - 1)) {
			continue;
		}
		s433DataStr.push_back(s433Buffer[i]);
	}
	LOGD("收到433串口消息 =================> %s", s433DataStr.c_str());

	s433DataHandle(s433DataStr);
	s433DataInit();
}

bool UartContext::threadLoop() {
	if (mIsOpen) {
		unsigned char buffer[1024] = {0};
		int ret = read(mUartID, buffer, sizeof(buffer));
		if (ret > 0) {
			std::string revStr = "";
			std::string revStr2 = "";
			//依次将读取到的数据输出到日志
			for (int i = 0; i < ret; ++i) {
				revStr += base::format("%02x",buffer[i]);
				revStr2 += buffer[i];
			}
			LOGD("串口 %d 收到消息： %s", mUartNumber, revStr.c_str());
			LOGD("串口 %d 收到消息： %s", mUartNumber, revStr2.c_str());

			std::string msgText = "串口" + std::to_string(mUartNumber) + ":" + revStr2;
			setUartList(msgText);

			if (mUartNumber == 2) {
				if (uartBaudRate2 == B115200) {
					alarmData(ret, buffer);
				}
				else if (uartBaudRate2 == B9600) {
					loraData(ret, buffer);
				}
			}
			else if (mUartNumber == 3) {
				if (uartBaudRate3 == B9600) {
					particleData(ret, buffer);
				}
			}
			else if (mUartNumber == 1) {
				if (uartBaudRate1 == B9600) {
					co2Data(ret, buffer);
				}
				else {
//					if (StoragePreferences::getInt(STORE_TCP_PORT, 5086) == 5086) {
//						s433Data(ret, buffer);
//					}
					oursLoraData(ret, buffer);
				}
			}
		} else {
		  //没收到数据时，休眠50ms，防止过度消耗cpu
		  usleep(1000 * 50);
		}

		return true;
	}

	return false;
}

static UartContext* uart0 = NULL;
static UartContext* uart1 = NULL;
static UartContext* uart2 = NULL;
static UartContext* uart3 = NULL;

void UartContext::init() {
//    uart0 = new UartContext(UART_TTYS0);
//    uart0->openUart("/dev/ttyS0", B115200);

	uart1 = new UartContext(UART_TTYS1);
	uart1->openUart("/dev/ttyS1", uartBaudRate1);
//	uart1->openUart("/dev/ttyS1", B115200);
	LOGD("打开串口1");

	uart2 = new UartContext(UART_TTYS2);
	uart2->openUart("/dev/ttyS2", uartBaudRate2);
//	uart2->openUart("/dev/ttyS2", B115200);
	LOGD("打开串口2");

	uart3 = new UartContext(UART_TTYS3);
	uart3->openUart("/dev/ttyS3", uartBaudRate3);
//	uart3->openUart("/dev/ttyS3", B115200);
	LOGD("打开串口3");

}

void UartContext::destroy() {
    if (uart0) {
        delete uart0;
        uart0 = NULL;
    }
    if (uart1) {
        delete uart1;
        uart1 = NULL;
    }
    if (uart2) {
        delete uart1;
        uart2 = NULL;
    }
    if (uart3) {
        delete uart1;
        uart3 = NULL;
    }
}

bool UartContext::sendTo(int uart, const BYTE* pData, UINT len) {
	bool result = false;
    switch (uart) {
    case UART_TTYS0:
    	result = uart0->send(pData, len);
    	break;
    case UART_TTYS1:
    	result = uart1->send(pData, len);
    	break;
    case UART_TTYS2:
    	result = uart2->send(pData, len);
    	break;
    case UART_TTYS3:
    	result = uart3->send(pData, len);
    	break;
    }
    if (result) {
    	std::string logInfo = " >>> ";
    	for (int i = 0; i < len; ++i) {
    		logInfo += base::format("%02x",pData[i]);
    	}
    	LOGD("串口 %d %s", uart, logInfo.c_str());
    }
    return false;
}

bool UartContext::Uart1IsOpen() {return mUart1IsOpen;}
bool UartContext::Uart2IsOpen() {return mUart2IsOpen;}
bool UartContext::Uart3IsOpen() {return mUart3IsOpen;}
