/*
* Для того чтобы войти в ражим настройки пароль: 456
  O:\MyDocuments\projects\Program Files\Newton\Драйвер BluePad\Примеры\Delphi\Win32\Debug\BluePad.exe
  C:\Program Files (x86)\1cv8t\8.3.18.1334\bin\1cv8ct.exe
*/

//---------------------------------------------------------------------------
#pragma hdrstop
//#include "stdafx.h"
//---------------------------------------------------------------------------
#include "BluePad.h"

//#include "tools.h"
#include "stdTools.h"
#include "mathTools.h"
//#include "ascii.h"
//#include "mathTools.h"
#include "Sockets.h"

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string.h>

#include <cmath>

//---------------------------------------------------------------------------
#if defined(WIN32) || defined(_WINDOWS) || defined(_BORLAND)
#include <windows.h>
#include <process.h>
void usleep(__int64 usec)
{
	void* timer;
	LARGE_INTEGER ft;
	ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time
	timer = CreateWaitableTimer(NULL, TRUE, NULL);
	SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
	WaitForSingleObject(timer, INFINITE);
	CloseHandle(timer);
}
#else
#include <unistd.h>    //write
#endif
//---------------------------------------------------------------------------
///Постройка CRC специального для этого принтера
//start - С какого байта начинать подсчёт
//len - кол-во байт
unsigned int MakeCRC(unsigned char* Buf, unsigned int start, unsigned int len)
{
	unsigned int cs = 0;
	for (unsigned int i = start; i<start + len; i++)
		cs += Buf[i];
	return cs;
}
//---------------------------------------------------------------------------
BluePad::BluePad(std::string path)
{
	m_LogFilePath = path;
	m_open = false;
	csPort = new ComPort();
	/*	Status=new StatusDP25();
	PrintColumns = "40";
	FrameSeqNumber=0x20;
	CommandName=0;
	m_Dots=0;*/
	m_SaveLog = true;
	/*Sw1=false; Sw2=false; Sw3=false; Sw4=false; Sw5=false; Sw6=false; Sw7=false; Sw8=false; //Заполняются при вызове DiagnosticInfo
	m_OpCode=0;
	m_TillNmb=0;*/
	m_tagsInCnt = 0;

	TimeOut = 100; //Меньше 70 не ставить!!!
				  /*CuttingPluName = 0;

				  m_activated1=0;
				  m_activated2=1;*/
	m_LastErrorCode = 0;

	m_sendData = NULL;

	m_cnt = 0; //Кол-во прочитанных пакетов
	memset(m_ans, 0, sizeof(m_ans));

	//Для отправки через сокеты
	sockets = new Sockets(this);	
}
//---------------------------------------------------------------------------
BluePad::~BluePad()
{
	CloseSerialPort();

	delete sockets; sockets = NULL;
	delete csPort; csPort = NULL;
}
//---------------------------------------------------------------------------
MyError BluePad::OpenSerialPort(std::string ComNumber, int BaudRate)
{
	ComPort* port = (ComPort*)csPort;

	MyError result;
	result.ErrorCode = 0;

	port->ComNumber = ComNumber;
	port->BaudRate = BaudRate;
	port->Close();
	if (port->Open(port->ComNumber))
	{
		if (port->Setup(0) && port->SetTimeout(TimeOut))
		{
			m_open = true; //Открыт и настроен (переменная m_open для потока чтобы не)
		}
		else
			result.ErrorCode = ERRIO;
	}
	else result.ErrorCode = ERRIO;

	//std::this_thread::sleep_for(std::chrono::milliseconds(10000));
	//Раз последовательный порт открылся то запускаю потоки для чтения и записи
	if (m_open) {
		//Запускаю поток чтения данных(пакетов из последовательного порта)
		m_execute_thread_read = true;
		m_threadid_read = new std::thread(BluePad::thread_func_read, (void*)this);

		//Для отправки в своем потроке комманд
		m_execute_thread_write = true;
		m_threadid_write = new std::thread(BluePad::thread_func_write, (void*)this);
	}

	return result;
}
//---------------------------------------------------------------------------
MyError BluePad::CloseSerialPort()
{
	MyError result;
	result.ErrorCode = 0;

	//Прежде чем закрыть последовательный порт/сокет останавливаю потоки
	if (m_execute_thread_read) {
		m_execute_thread_read = false;
		m_threadid_read->join();
		delete m_threadid_read;
		m_threadid_read = NULL;
	}
	if (m_execute_thread_write) {
		m_execute_thread_write = false;
		m_threadid_write->join();
		delete m_threadid_write;
		m_threadid_write = NULL;
	}

	m_open = false;
	csPort->Close();
	Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Close Serial.", true);

	return result;
}
//---------------------------------------------------------------------------
MyError BluePad::Ping()
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start Ping();");
	
	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x01; //LL length of DATA 
	data->mas[5] = 0x00; //SUBCMD: 00: PING
	data->mas[6] = 0x00; //CRC считается ниже = 0x02
	data->len = 7;
	data->calcCRC();
	data->log_text = "Ping()";
	addData(data);

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int sec = 300; // 1/10 Секунды
	while(sec>0){
		sec--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
	}
	MyError result;
	result.ErrorCode = 0;
	if(sec==0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "Ping();";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
};
//---------------------------------------------------------------------------
/*int BluePad::SendPMessage(char* answer)
{
	//char ans[65535];
	char crc = 0;
	//читаю начало ответа
	char ch = 0;
	int cntRead = 0;
	while (true) {
		int len = csPort->Read(&ch, 1);
		if (len == 1)
		{
			if (ch == '>') {
				crc = crc ^ ch;
				break;
			}
		}
		if (cntRead > 20) {
			break; //Задержка на чтение 100мс, согласно документации принтер должен отправить не позднее 2сек
		}
		cntRead++;
	}
	if (cntRead > 20) return ERRIO; //Ошибка: Таймаут приёма первого байта пакета

									//Читаю 00 
	int len = csPort->Read(&ch, 1);
	crc = crc ^ ch;
	if (len != 1 || ch != 0) return ERRIO; //Ошибка: Нарушение структуры пакета

										   //Читаю: ST: status (see error codes)  
	len = csPort->Read(&ch, 1);
	crc = crc ^ ch;
	if (len != 1) return ERRIO; //Ошибка: Не удалост прочитать
	if (ch != 0) return ch;

	unsigned short size = 0;
	len = csPort->Read(&((char *)(&size))[1], 1);
	crc = crc ^ ((char *)(&size))[1];
	if (len != 1) return ERRIO; //Ошибка: Не удалост прочитать
	len = csPort->Read(&((char *)(&size))[0], 1);
	crc = crc ^ ((char *)(&size))[0];
	if (len != 1) return ERRIO; //Ошибка: Не удалост прочитать
								//Данные есть читаем их
	if (size > 0) {
		len = csPort->Read(answer, size);
		for (int i = 0; i<len; i++)
			crc = crc ^ answer[i];
	}
	//читаю контрольную сумму
	len = csPort->Read(&ch, 1);
	if (len != 1) return ERRIO; //Ошибка: Не удалост прочитать

	if (ch != crc) return ERRCRC; //Ошибка: В RCR 

								  //answer = ans;

	return 0;
}*/
//---------------------------------------------------------------------------
//Проверяем не отправились ли данные в пинпад
bool BluePad::existsData(int id) {

	std::lock_guard<std::mutex> lock(m_mutex);

	bool result = false;
	DataToSend *sd = m_sendData;
	while(sd!=NULL){
		if (sd->id == id) {
			result = true;
			break;
		}
		sd = sd->child;
	}
	return result;
}
//---------------------------------------------------------------------------
//Безопасно добавляем данные в конец списка
bool BluePad::addData(DataToSend* data) {

	std::lock_guard<std::mutex> lock(m_mutex);

	bool result = true;

	if (m_sendData == NULL) { //Если первый элемент в FIFO буфере не задан то задаём его
		m_sendData = data;
	} else { //Если первый элемент задан то ищём последний
		DataToSend *sd = m_sendData;
		while (sd->child!=NULL) {
			sd = sd->child;
		}
		sd->child = data;
	}

	return result;
}
//---------------------------------------------------------------------------
//Запускаю поток по отправке данных в последовательный порт из связанного списка
void BluePad::thread_func_write(void *pData)
{
	BluePad* bp = (BluePad*)pData;
	while (bp->m_execute_thread_write)
	{
		DataToSend *sd = NULL;
		//Безопасно забираем первый объект из связанного списка если он там есть
		bp->m_mutex.lock();
		if (bp->m_sendData != NULL) {
			sd = bp->m_sendData;
			bp->m_sendData = bp->m_sendData->child;
		}
		bp->m_mutex.unlock();

		if (sd != NULL) {
			int len=bp->csPort->Write(sd->mas, sd->len); //Отправляем данные

			std::stringstream ss;
			ss << "Write " << len << " bytes from " << sd->len << " in serial log_text = "<< sd->log_text;
			Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str()); //TODO закоментить как отлажу
		}

		//Проверяю есть ли данные для отправки в терминал пришедшие из сокета и если они есть то добавляю эти данные в последовательный список для отправки
		sd = bp->sockets->getDataToSend();
		if (sd != NULL) {
			bp->addData(sd);
		}
	}
	//TODO закоментить как отлажу
	if (bp->m_SaveLog) {
		std::stringstream ss;
		ss << "========== END SERIAL WRITE THREAD ==========";
		Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
}
//---------------------------------------------------------------------------
//Поток для постоянного чтения данных из последовательного порта
void BluePad::thread_func_read(void *pData)
{
	BluePad* bp = (BluePad*)pData;
	char* answer = bp->m_ans;
	std::string err = "";

	//За 1 проход читаем один пакет
	while (bp->m_execute_thread_read)
	{
		if (bp->m_SaveLog && err.length()>0) //В начале цикла потому что в теле есть continue
		{
			Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", err);
			err = "";
		}

		if (!bp->m_open) {
			std::this_thread::sleep_for(std::chrono::milliseconds(1000));
			continue;
		}

		int error = 0;
		char crc = 0;
		char ch = 0;
		//1й байт читаю начало ответа  '>' 0x3e
		int len = bp->csPort->Read(&ch, 1);
		if (len == 1)
		{
			if (ch == '>') { //0x3E
				crc = crc ^ ch;
			}else {
				err += " Error waste; ";
				continue;
			}
		} else continue;

		//2й байт Читаю 00 - если ответ на команду; 0x0F - если пинпад инициатор команды; 0x0E (14) - событие из пинпада; 0x3D - сдесь не должен появляться он только на отправку
		char tpy = 0;
		len = bp->csPort->Read(&tpy, 1);
		crc = crc ^ tpy;
		if (len != 1 || !(tpy == 0 || tpy == 0x0F || tpy == 0x0E)) {
			err += "2nd byte is error = "+Utility::IntToStdStr(tpy)+"; ";
			continue; //Ошибка: Нарушение структуры пакета
		}

		//3й байт читаю: ST: status (see error codes)
		len = bp->csPort->Read(&ch, 1);
		crc = crc ^ ch;
		if (len != 1 || ch != 0) {
			err += "3nd byte is error, code = "+ Utility::IntToStdStr(ch);
			//continue;
		}

		//4й и 5й длина без байта CRC
		unsigned short size = 0;
		len = bp->csPort->Read(&((char *)(&size))[1], 1); //LH
		crc = crc ^ ((char *)(&size))[1];
		if (len != 1) { //Ошибка: Не удалост прочитать
			err += "4nd error read LH byte size; ";
			continue; 
		}
		len = bp->csPort->Read(&((char *)(&size))[0], 1);
		crc = crc ^ ((char *)(&size))[0];
		if (len != 1) {
			err += "5nd error read LL byte size; ";
			continue;
		}
								
		//6й байт итд сами данные
		memset(answer, 0, sizeof(bp->m_ans));
		if (size > 0) {
			len = bp->csPort->Read(answer, size);
			for (int i = 0; i<len; i++)
				crc = crc ^ answer[i];
			if (len != size) {
				err += "6nd+N error read data; ";
			}
		}

		//читаю контрольную сумму
		len = bp->csPort->Read(&ch, 1);
		if (len != 1) {
			err += "error read CRC; ";
			continue;
		}

		if (ch != crc) {
			err += "error in CRC; ";
			continue; //Ошибка: В RCR 
		}
		bp->m_length = size;

		//Сохраняю в лог то что получили новый пакет данных
		if (bp->m_SaveLog)
		{
			std::stringstream ss;
			ss << "Read cnt = " << bp->m_cnt << " error = " << error << " type=" << (int)tpy << " length = " << size << " data = " << Utility::toHexString((unsigned char*)answer, size);
			Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
		}

		if (tpy == 0) {
			bp->m_cnt++;
		}
		else if (tpy == 0x0F) { //15
			//Может прилитетть команда открытия сокета поэтому обрабатываем её здесь
			if (bp->m_ans[0] == 0x01) {
				bp->SocketOpen();
			} else
			if (bp->m_ans[0] == 0x02) { //3e 0f 00 00 02 02 01 30
				bp->SocketClose();
			} else
			if (bp->m_ans[0] == 0x03) {
				bp->SocketSend();
			}else {
				if (bp->m_SaveLog)
				{
					std::stringstream ss;
					ss << "Error tpy 1";
					Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
				}
			}
			//3e 0f 00 00 02 02 01 30
		}
		else if (tpy == 0x0E) { //14 Пришли события
			if (bp->m_ans[0] == 0x01) { // 01: TRANSACTION COMPLETE (PAYMENT RESULT) - NO CONFIRMATION NEEDED 
				if (bp->m_SaveLog)
				{
					std::stringstream ss;
					ss << "TRANSACTION COMPLETE";
					Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
					//Разбираю результаты транзакции
					bp->parseEMVTLV((unsigned char *)answer, size); //Пока парсю в лог файл
				}
			} else 
			if (bp->m_ans[0] == 0x02) { // 02: INTERMEDIATE TRANSACTION COMPLETE (PAYMENT RESULT) - NO CONFIRMATION NEEDED SENT IF A HUNG TRANSACTION PASSED JUST BEFORE THE TRANSACTION CURRENTLY EXECUTING
				if (bp->m_SaveLog)
				{
					std::stringstream ss;
					ss << "INTERMEDIATE TRANSACTION COMPLETE";
					Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
				}
			}
			else
			if (bp->m_ans[0] == 0x10) { // 10: SEND LOG DATA.SENT AS A RESULT TO SUBCOMMAND GET REPORT TAGS(4)
				if (bp->m_SaveLog)
				{
					std::stringstream ss;
					ss << "SEND LOG DATA.SENT AS A RESULT TO SUBCOMMAND GET REPORT TAGS(4)";
					Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
				}
			} else
			if (bp->m_ans[0] == 0x65) { // 65: EVENT STATUS. Отображают текущее состояние терминала.
				unsigned short stat;
				bp->getStatus(stat);
			}
			else {
				if (bp->m_SaveLog)
				{
					std::stringstream ss;
					ss << "Error tpy 2";
					Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
				}
			}
		}

		/*if (error != 0) {
			std::this_thread::sleep_for(std::chrono::milliseconds(10000));
		}*/
	}
	//TODO закоментить как отлажу
	if (bp->m_SaveLog) {
		std::stringstream ss;
		ss << "========== END SERIAL READ THREAD ==========";
		Utility::logrotate(bp->m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
}
//---------------------------------------------------------------------------
//Открываю сокет в отдельном потоке для коммуникации с сервером
MyError BluePad::SocketOpen() {

	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start SocketOpen();");

	MyError result;
	result.ErrorCode = 0;

	//Разбираю запрос на подключение
	char SocketID = m_ans[1]; //Наверно чтобы можно было много сокетов открывать и обращатся к нам по ID
	char SocketType = m_ans[2];

	std::stringstream ssAddress;
	ssAddress << (int)((unsigned char)m_ans[3]) << "." << (int)((unsigned char)m_ans[4]) << "." << (int)((unsigned char)m_ans[5]) << "." << (int)((unsigned char)m_ans[6]);
	std::string address = ssAddress.str();
	int port=0;
	((char*)&port)[1] = m_ans[7];
	((char*)&port)[0] = m_ans[8];

	int timeout = 0;
	((char*)&timeout)[1] = m_ans[9];
	((char*)&timeout)[0] = m_ans[10];
	std::string vars;
	vars.append(&m_ans[11]);

	//Данные прочитали теперь реально открываем сокет
	bool ret = sockets->openSoket(SocketID, address.c_str(), port, timeout);

	//Высылаю подтверждение о открытии сокета (02: EVENT CONFIRM )
	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x40; // EXTERNAL INTERNET COMMANDS, 0x40
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x05; //LL length of DATA  (длина от этого байта до CRC)

	data->mas[5] = 0x02; //02: EVENT CONFIRM
	data->mas[6] = 0x01; //SUBCMD: [01]: SOCKET OPEN EVENT
	if (ret) data->mas[7] = 0x00; //[00]: CONFIRM OK
	else {
		data->mas[7] = 0x01; //[00]: CONFIRM ERR
		result.ErrorCode = ERRSOCKSND;
	}
	unsigned short size = 2048; //максимального пакета данных пересылаемых за раз
	data->mas[8] = ((char *)(&size))[1]; //[MTU HIGH]
	data->mas[9] = ((char *)(&size))[0]; //[MTU LOW]

	data->mas[10] = 0x00; //CSUM: считаю в функции calcCRC
	data->len = 11;
	data->calcCRC();
	data->log_text = "SocketOpen()";
	addData(data);

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1 и проверяем ответ пинпада примерно такой: 3E 00 00 00 00 3E
	/*Нельзя дожидаться ответа так как в потоке чтения находимся
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;*/

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "SocketOpen(SocketID = " << (int)SocketID << ", SocketType = " << (int)SocketType  << ", address = " << address <<", port="<< port <<", timeout = "<< timeout /*<<", vars = "<< vars*/ <<", open = "<< (ret ? "true" : "false") <<");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
// Закрыть сокет по ID (ID берётся из разобранного пакета)
MyError BluePad::SocketClose() {

	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start SocketClose();");

	MyError result;
	result.ErrorCode = 0;

	if (m_ans[0] == 0x02) {

		bool ret=sockets->closeSoket(m_ans[1]);

		//Добавляем ответ в пинпад что команду выполнили "02: EVENT CONFIRM"
		DataToSend* data = new DataToSend();
		data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
		data->mas[1] = 0x40; // EXTERNAL INTERNET COMMANDS, 0x40
		data->mas[2] = 0x00; // 00
		data->mas[3] = 0x00; //LH length of DATA 
		data->mas[4] = 0x03; //LL length of DATA  (длина от этого байта до CRC)

		data->mas[5] = 0x02; //02: EVENT CONFIRM
		data->mas[6] = 0x02; //SUBCMD: [02]: SOCKET CLOSE EVENT
		if(ret) data->mas[7] = 0x00; //[00]: CONFIRM OK
		else {
			data->mas[7] = 0x01; //[00]: CONFIRM ERR
			result.ErrorCode = ERRSOCK;
		}

		data->mas[8] = 0x00; //CSUM: считаю в calcCRC
		data->len = 9;
		data->calcCRC();
		data->log_text = "SocketClose()";
		addData(data);

		//Ожидаю когда количество прочитанных пакетов не увеличится на 1 и проверяем ответ пинпада примерно такой: 3E 00 00 00 00 3E
		/*
		не могу ждать ответа так как находимся в потоке приёма данных
		int cnt = m_cnt;
		int i = 2000;
		while (i>0) {
			i--;
			if (cnt < m_cnt)
				break;
			std::this_thread::sleep_for(std::chrono::milliseconds(1000));
		}
		if (i == 0) result.ErrorCode = ERRIO;*/

	} else {
		result.ErrorCode = 1;
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "SocketClose(SocketID = " << (int)m_ans[1] << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
// Отправить данные полученные от пинпада в сокет  (Данные берутся из разобранного пакета)
MyError BluePad::SocketSend() {

	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start SocketSend();");

	MyError result;
	result.ErrorCode = 0;

	char SocketID = m_ans[1]; //Наверно чтобы можно было много сокетов открывать и обращатся к нам по ID
	
	bool ret = sockets->sendData(m_ans[1], &m_ans[2], m_length - 2);

	//Добавляем ответ в пинпад что команду выполнили "02: EVENT CONFIRM"
	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x40; // EXTERNAL INTERNET COMMANDS, 0x40
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x03; //LL length of DATA  (длина от этого байта до CRC)

	data->mas[5] = 0x02; //02: EVENT CONFIRM
	data->mas[6] = 0x03; //SUBCMD: [03]: SEND DATA EVENT 
	if (ret) data->mas[7] = 0x00; //[00]: CONFIRM OK
	else {
		data->mas[7] = 0x01; //[00]: CONFIRM ERR
		result.ErrorCode = ERRSOCKSND;
	}
	data->mas[8] = 0x00; //CSUM: считаю в calcCRC
	data->len = 9;
	data->calcCRC();
	data->log_text = "SocketSend()";
	addData(data);

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1 и проверяем ответ пинпада примерно такой: 3E 00 00 00 00 3E
	/*
	не могу ждать ответа так как находимся в потоке приёма данных
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;
	*/

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "SocketSend(SocketID = " << (int)m_ans[1] << ");";
		if (m_LastErrorCode != 0)
			ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
MyError BluePad::getInfo(std::string& model, std::string& serial, std::string& ver, std::string& id, int* menu) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getInfo();");
	model = "";
	serial = "";
	ver = "";
	id = "";

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x01; //LL length of DATA 
	data->mas[5] = 0x06; //SUBCMD: 06: GET PINPAD INFO 
	data->mas[6] = 0x04; //CSUM: xor of all bytes in the packet 
	data->len = 7;
	data->calcCRC();
	data->log_text = "getInfo()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	if (result.ErrorCode == 0) {
		for(int i=0;i<20;i++) {
			if(m_ans[i]>0) model+=m_ans[i];
		}
		serial.append(&m_ans[20], 10);
		ver = Utility::IntToStdStr(m_ans[30]) + "." + Utility::IntToStdStr(m_ans[31]) + "." + Utility::IntToStdStr(m_ans[32]) + "." + Utility::IntToStdStr(m_ans[33]);
		id.append(&m_ans[34], 8);
		*menu = m_ans[42];
	}
	else {
		ReadingError(result.ErrorCode, result.ErrorMessage);
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getInfo(model=" << model << ",serial=" << serial << ",ver=" << ver << ",id = " << id << ",menu=" << menu << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
MyError BluePad::getRTC(std::string& date)
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getRTC();");
	date = "";

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x01; //LL length of DATA 
	data->mas[5] = 0x07; //SUBCMD: 07: GET RTC
	data->mas[6] = 0x05; //CSUM: xor of all bytes in the packet 
	data->len = 7;
	data->calcCRC();
	data->log_text = "getRTC()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	if (result.ErrorCode == 0) {
		std::stringstream rr;
		rr << "20" << (int)m_ans[0] << "-" << std::setw(2) << std::setfill('0') << (int)m_ans[1] << "-" << std::setw(2) << std::setfill('0') << (int)m_ans[2];
		rr << " " << std::setw(2) << std::setfill('0') << (int)m_ans[3] << ":" << std::setw(2) << std::setfill('0') << (int)m_ans[4] << ":" << std::setw(2) << std::setfill('0') << (int)m_ans[5];
		date = rr.str();
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getRTC(date=" << date << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Прочитать статус терминала
MyError BluePad::getStatus(unsigned short& status)
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getStatus();");
	MyError result;
	result.ErrorCode = 0;

	status = 0;
	((char *)(&status))[0] = m_ans[1]; //STH - старший байт статуса
	((char *)(&status))[1] = m_ans[2]; //STL - молодший байт статуса

	//Отправленный, терминалом, ивент не нуждается в подтверждении!

	std::string Message;
	ReadingStatus(status, Message);

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getStatus(status = " << status << ", description = " << Message << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
//reversal - 00: НЕТ ОБРАТНОЙ 'R': ОБРАТНАЯ 'R' 'C' : ЗАВЕРШЕНИЕ ТРАНЗАКЦИИ 'C'
//endday - ПОКАЗЫВАЕТ, ЕСЛИ НЕОБХОДИМО ВЫПОЛНИТЬ КОНЕЦ ДНЯ ПЕРЕД ЛЮБОЙ ДРУГОЙ ТИПОМ ТРАНЗАКЦИИ : 00 : КОНЕЦ ДНЯ НЕ ТРЕБУЕТСЯ 01 : ВАМ НУЖНО ВЫПОЛНИТЬ КОНЕЦ ДНЯ
MyError BluePad::getStatus(std::string& reversal, std::string& endday) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getStatus();");
	reversal = "";
	endday = "";

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA 
	data->mas[4] = 0x01; //LL length of DATA 
	data->mas[5] = 0x1A; //SUBCMD: 1A: GET PINPAD STATUS
	data->mas[6] = 0x18; //CSUM: xor of all bytes in the packet 
	data->len = 7;
	data->calcCRC();
	data->log_text = "getStatus()";
	addData(data);


	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	MyError result;
	result.ErrorCode = 0;
	if (i == 0) result.ErrorCode = ERRIO;

	if (result.ErrorCode == 0) {
		if (m_ans[0] == 0) reversal = '0';
		else reversal = m_ans[0];
		if (m_ans[1] == 0) endday = '0';
		else endday = m_ans[1];
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getStatus(reversal = " << reversal << ", endday = " << endday << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Отправить долученные данные через интернет на пинпад
/*MyError BluePad::setData(char* data,int length) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + sp3() + "log.txt", "Start setData();");
	char pack[] = {
		0x3E, // '>': start paket (ASCII symbol '>') 
		0x40, // EXTERNAL INTERNET COMMANDS
		0x00, // 00
		0x00, //LH length of DATA (старший наиболее значащий байт)
		0x00, //LL length of DATA
		0x01 //SUBCMD: 01: RECEIVE DATA 
	};
	pack[3] = ((char*)&length)[1];
	pack[4] = ((char*)&length)[0];

	char crc = 0;
	for (int i = 0; i < sizeof(pack); i++) {
		crc = crc ^ pack[i];
	}
	for (int i = 0; i < length; i++) {
		crc = crc ^ data[i];
	}
	csPort->Write(pack, sizeof(pack)); //Отправляем начало пакета
	csPort->Write(data, length); //Отправляем данные
	csPort->Write(&crc, 1); //Отправляем CRC

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 1000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	MyError result;
	result.ErrorCode = 0;
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "setData(length=" << length << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + sp3() + "log.txt", ss.str());
	}
	return result;
}*/
//---------------------------------------------------------------------------
//Запросить сколько байт можно передать в пинпад за 1 пакет
MyError BluePad::getMaxLenData(int* length) {

	*length = 0;

	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getMaxLenData();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x40; // EXTERNAL INTERNET COMMANDS
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA (старший наиболее значащий байт)
	data->mas[4] = 0x01; //LL length of DATA
	data->mas[5] = 0x03; //SUBCMD: 03: GET MAX MTU 
	data->mas[6] = 0x7C;  //CSUM: xor of all bytes in the packet 
	data->len = 7;
	data->calcCRC();
	data->log_text = "getMaxLenData()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 1000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	if (result.ErrorCode == 0) {
		((char*)length)[1] = m_ans[0];
		((char*)length)[0] = m_ans[1];
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getMaxLenData(length=" << *length << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
MyError BluePad::setEventStatus(bool val) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start setEventStatus();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x02; //LL length of DATA
	data->mas[5] = 0x66; //SUBCMD: 01: TRANSACTION START
	if(val)
		data->mas[6] = 0x01;
	else
		data->mas[6] = 0x00;
	data->mas[7] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = 8;
	data->calcCRC();
	data->log_text = "setEventStatus()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 1000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "setEventStatus(val=" << val << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Начало транзакции для оплаты
// amount - сумма
// timeout - сколько времени ждать ответа в секундах (не завершения операции а то что пинпад подтвердит команду) 5 сек должно хватать
MyError BluePad::startPurchase(double amount,int timeout) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start startPurchase();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x00; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_PURCH; //01 - PURCHASE 

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);

	data->mas[13] = 0x00; //CSUM: xor of all bytes in the packet 

	data->len = data->pos + 1; // 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "startPurchase()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	if (timeout > 0) {
		int cnt = m_cnt;
		timeout = timeout * 10;
		while (timeout > 0) {
			timeout--;
			if (cnt < m_cnt)
				break;
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
		}
		if (timeout == 0) result.ErrorCode = ERRIO;
	}

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "startPurchase(amount="<< amount  <<", timeout = "<< (timeout/10) <<");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Отмена оплаты
//amount это тег 0x81, 0xDF01
//RRN это тег 0xDF01
MyError BluePad::voidPurchase(double amount, std::string RRN)
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start voidPurchase();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x08; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_VOID_PURCH; //07

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);
	data->addStringTag(BOR_CMD_TAG_RRN, RRN); 

	data->mas[13] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "voidPurchase()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 1000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "voidPurchase(amount=" << amount << ", RRN = " << RRN << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Вернуть оплату
// RN - по моему это номер чека
MyError BluePad::startRetPurchase(double amount, std::string RN)
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start startRetPurchase();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x08; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_PURCH_RET; //22

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);
	data->addStringTag(BOR_CMD_TAG_RN, RN);

	data->mas[13] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "startRetPurchase()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 1000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "startRetPurchase(amount=" << amount << ", RN = " << RN << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Начать авторизацию оплаты
MyError BluePad::startAuthorization(double amount) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start startAuthorization();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x08; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_AUTH; //05

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);

	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "startAuthorization()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;


	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "startAuthorization(amount=" << amount << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Начать отмену авторизации, согласно примера: 11) START VOID OF AUTHORIZATION  
//Необходимые параметры (теги): 
//0x81 - BOR_CMD_TAG_AMOUNT
//0xDF01 - BOR_CMD_TAG_RRN
//0xDF02 - BOR_CMD_TAG_AUTH_ID
MyError BluePad::voidAuthorization(double amount, std::string RRN, std::string auth)
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start voidAuthorization();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x08; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_VOID_AUTH; //09

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);
	data->addStringTag(BOR_CMD_TAG_RRN, RRN);
	data->addStringTag(BOR_CMD_TAG_AUTH_ID, auth);

	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "voidAuthorization()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;


	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "voidAuthorization(amount=" << amount << ", RRN = " << RRN << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Подтвердить авторизацию, по примеру: 6) Транзакция   ** AUTHORISATION CONFIRMATION **
//Необходимые параметры (теги): 
//0x81 - BOR_CMD_TAG_AMOUNT
//0xDF01 - BOR_CMD_TAG_RRN
//0xDF02 - BOR_CMD_TAG_AUTH_ID
MyError BluePad::confirmAuthorization(double amount, std::string RRN, std::string auth) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start confirmAuthorization();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x00; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_PURCH_CODE; //09

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);
	data->addStringTag(BOR_CMD_TAG_RRN, RRN);
	data->addStringTag(BOR_CMD_TAG_AUTH_ID, auth);

	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "confirmAuthorization()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;


	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "confirmAuthorization(amount=" << amount << ", RRN = " << RRN << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}

	return result;
}
//---------------------------------------------------------------------------
//Проверить соединение с сервером
MyError BluePad::testConnection()
{
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start testConnection();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x02; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_TEST_CONN; //14 - TEST CONNECTION
	data->mas[7] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = 8;
	data->calcCRC();
	data->log_text = "testConnection()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "testConnection();";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
/*
	ОПИСАНИЕ: Эта команда используется, если УСТРОЙСТВУ необходимо извне принудительно завершить транзакцию, после ее запуска или в конце каждой транзакции.
	Если val = 0 то считаем что транзакция выполнена неудачно
	Если val = 1 то считаем что транзакция выполнена удачно
*/
MyError BluePad::transactionEnd(char value) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start transactionEnd();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x03; //LL length of DATA
	data->mas[5] = 0x03; //03: TRANSACTION END
	data->mas[6] = 0x00; //[CFM HIGH]
	data->mas[7] = value;  //[CFM LOW]
	data->mas[8] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = 9;
	data->calcCRC();
	data->log_text = "transactionEnd()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "transactionEnd(value = " << (int)value << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
// Завершить день (Z - отчёт)
MyError BluePad::endOfDay() {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start endOfDay();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x02; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_END_OF_DAY; //10
	data->mas[7] = 0x00; //CSUM: xor of all bytes in the packet 
	data->len = 8;
	data->calcCRC();
	data->log_text = "endOfDay()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "endOfDay();";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
// Отменить оплату по чеку в рамках одного дня
//amount - Сумма, тег:  0x81
//num - номер транзакции, тег: 0xDF04
MyError BluePad::cancelCheck(double amount, unsigned int num) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start cancelCheck();");

//	3E 3D 00 00 02 66 01 66
//	3E 3D 00 00 0D 01 12 81 04 00 00 27 10 DF 04 02	00 13 65
//	3E 40 00 00 03 02 03 00 7C                         >@...... |

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x00; //LL length of DATA
	data->mas[5] = 0x01; //SUBCMD: 01: TRANSACTION START
	data->mas[6] = BOR_CMD_TRANS_TYPE_LOYALTY_SPEND; //12

	unsigned int sum = round(amount * 100);
	data->pos = 7;
	data->addUIntTag(BOR_CMD_TAG_AMOUNT, sum);
	data->addUIntTag(BOR_CMD_TAG_DF04_AMOUNT_EUR, num);

	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "cancelCheck()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int i = 2000;
	while (i>0) {
		i--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	if (i == 0) result.ErrorCode = ERRIO;

	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "cancelCheck(amount = "<< amount <<", num = " << num << ");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
//Пример парсера: http://paymentcardtools.com/emv-tlv-parser
void BluePad::parseEMVTLV(unsigned char* data, int length) {

	m_tagsInCnt++;

	int tPos = 0;
	for (int i = 0; i < TAGSLEN; i++) {
		tags[i].tag = 0;
		tags[i].data = "";
	}

	int pos = 0;
	data++; //Пропускаю первый байт


	while (length > pos){
		int len = readTag(&data[pos], length, tags[tPos].tag, tags[tPos].data);
		if (len > 0) {
			tPos++;
			if (tPos >= TAGSLEN) {
				break;
			}
		} else {
			break;
		}
		pos += len;
	}



/*	std::stringstream ss;
	while (length > pos) {

		int val = data[pos];

		if (data[pos] == 0x5F) {
			if (data[pos + 1] == 0x20) { //0x5F20[STRING] TAG_5F20_CARDHOLDER_NAME
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x5F20;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "5F20 = " + tags[tPos].data << std::endl;				
				tPos++;
			}
			else
				break;
		}if (data[pos] == 0x81) { //0x81[HEX] TAG_81_AMOUNT_AUTHORISED
			if (tPos < TAGSLEN) {
				tags[tPos].tag = 0x81;
				tags[tPos].data = Utility::toHexString(&data[pos + 2], data[pos + 1]);
			}
			pos += data[pos + 1] + 2;
			ss << "81 = " + tags[tPos].data << std::endl;
			tPos++;
		}
		else if(data[pos] == 0x9A) { //0x9A[BCD] TAG_9A_TRANSACTION_DATE[Year:Month:Day]
			if (tPos < TAGSLEN) {
				tags[tPos].tag = 0x9A;
				tags[tPos].data = Utility::toHexString(&data[pos + 2], data[pos + 1]);
			}
			pos += data[pos + 1] + 2;
			ss << "9A = " + tags[tPos].data << std::endl;
			tPos++;
		}
		else  if (data[pos] == 0x9F) {
			if (data[pos + 1] == 0x1C) { //0x9F1C[STRING] TAG_9F1C_TERMINAL_ID
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F1C;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F1C = " + tags[tPos].data << std::endl;
				tPos++;
			}else if (data[pos + 1] == 0x41) { //0x9F41[BCD] TAG_9F41_TRANSACTION_SEQUENCE_COUNTER
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F41;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F41 = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else if (data[pos + 1] == 0x16) { //0x9F16[STRING] TAG_9F16_TERMINAL_MERCHANT_ID
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F16;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F16 = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else if (data[pos + 1] == 0x06) { //0x9F06[BCD] TAG_9F06_TERM_AID
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F06;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F06 = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else if (data[pos + 1] == 0x26) { //0x9F26[HEX] TAG_9F26_APP_CRYPTOGRAM
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F26;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F26 = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else if (data[pos + 1] == 0x21) { //0x9F21[BCD] TAG_9F21_TRANSACTION_TIME[Hour:Minute:Seconds]
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0x9F21;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "9F21 = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else
				break;
		}
		else  if (data[pos] == 0xDF) {

			if (data[pos + 1] == 0x05)//0xDF05[HEX] TAG_DF05_TRANSACTION_RESULT REF. 1)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF05;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF05 = " + tags[tPos].data << std::endl;
				tPos++;
			}else if (data[pos + 1] == 0x06) //0xDF06[HEX] TAG_DF06_TRANSACTION_ERROR_CODE REF. "ERROR CODES"
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF06;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF06 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x31) //0xDF31[STRING] TAG_DF31_TERMINAL_MERCHANT_NAME_BG
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF31;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF31 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x30) //0xDF30[STRING] TAG_DF30_TERMINAL_MERCHANT_CITY_BG
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF30;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF30 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x2F) //0xDF2F[STRING] TAG_DF2F_TERMINAL_MERCHANT_ADDRESS_BG
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF2F;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF2F = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x29) //0xDF29[STRING] TAG_DF29_TERMINAL_MERCHANT_POST_CODE
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF29;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF29 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x2E) //0xDF2E[STRING] TAG_DF2E_TERMINAL_MERCHANT_TITLE_BG
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF2E;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF2E = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x28) //0xDF28[STRING] TAG_DF28_TERMINAL_MERCHANT_PHONE
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF28;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF28 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x00) //0xDF00[STRING] TAG_DF00_CARD_SCHEME
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF00;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF00 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x0A) //0xDF0A[STRING] TAG_DF0A_MASKED_PAN
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF0A;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF0A = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x25) //0xDF25[HEX] BOR_TAG_PAY_INTERFACE REF. 2)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF25;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF25 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x60) //0xDF60[HEX] BOR_TAG_CARD_SCHEME_CL REF. 3)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF60;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF60 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x10) //0xDF10[HEX] TAG_DF10_TRANS_TYPE REF. 4)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF10;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF10 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x0B) //0xDF0B[HEX] TAG_DF0B_LOYALTY_PTS
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF0B;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF0B = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x04) //0xDF04[HEX] TAG_DF04_AMOUNT_EUR
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF04;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF04 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x23) //0xDF23[HEX] TAG_DF23_CVM_SIGNATURE REF. 5)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF23;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF23 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x07) //0xDF07[STRING] TAG_DF07_HOST_RRN
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF07;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF07 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x08) //0xDF08[STRING] BOR_TAG_HOST_AUTH_ID
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF08;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF08 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x09) //0xDF09[HEX] BOR_TAG_HOST_CODE
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF09;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF09 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x61) //0xDF61[HEX] BOR_TAG_TRANS_BATCH_NUM
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF61;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF61 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x62) //0xDF62[STRING] BOR_TAG_INTERFACE_ID
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF62;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF62 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x79) //0xDF79[HEX] BOR_TAG_ISSUER_ID REF. 6)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF79;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF79 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x12) //0xDF12[HEX] BOR_TAG_TO_TYPE REF. 7)
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF12;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF12 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x13) //0xDF13 RN
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF13;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF13 = " + tags[tPos].data << std::endl;
				tPos++;
			} else if (data[pos + 1] == 0x5A) //0xDF13 RN
			{
				if (tPos < TAGSLEN) {
					tags[tPos].tag = 0xDF5A;
					tags[tPos].data = Utility::toHexString(&data[pos + 3], data[pos + 2]);
				}
				pos += data[pos + 2] + 3;
				ss << "DF5A = " + tags[tPos].data << std::endl;
				tPos++;
			}
			else
				break;
		}
		else
			break;
	}
	Utility::logrotate(m_LogFilePath + sp3() + "log.txt", ss.str());
*/
}
//---------------------------------------------------------------------------
// Прочитать тег из массива, если тега нет среди предпологаемых то выходим
// Результат сколько удалось прочитать байт
int BluePad::readTag(unsigned char* data, int length, int& tag, std::string& tagData) {
	int result = 0;
	std::stringstream ss;

	switch (data[0]) {
	case 0x5F:{
			if (data[1] == 0x20) { //0x5F20[STRING] TAG_5F20_CARDHOLDER_NAME
				tag = 0x5F20;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);

				result = data[2] + 3;
				ss << "5F20 = " + tagData;
			}
			break;
		}
	case 0x81: { //0x81[HEX] TAG_81_AMOUNT_AUTHORISED
			tag = 0x81;
			tagData = Utility::toHexString(&data[2], data[1]);

			unsigned int sum = Utility::hexStringToInt(tagData);
			tagData = Utility::FloatToStdStr(sum/100.0f, 2, '.'); //tagData = Utility::UIntToStdStr(sum);

			result = data[1] + 2;
			ss << "81 = " + tagData;
			break;
		}
	case 0x9A: { //0x9A[BCD] TAG_9A_TRANSACTION_DATE[Year:Month:Day]
			tag = 0x9A;
			tagData = Utility::toHexString(&data[2], data[1]);
			
			result = data[1] + 2;
			ss << "9A = " + tagData;
			break;
		}
	case 0x9F: {
			if (data[1] == 0x1C) { //0x9F1C[STRING] TAG_9F1C_TERMINAL_ID
				tag = 0x9F1C;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F1C = " + tagData;	
			}
			else if (data[1] == 0x41) { //0x9F41[BCD] TAG_9F41_TRANSACTION_SEQUENCE_COUNTER
				tag = 0x9F41;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F41 = " + tagData;
				
			}
			else if (data[1] == 0x16) { //0x9F16[STRING] TAG_9F16_TERMINAL_MERCHANT_ID
				tag = 0x9F16;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F16 = " + tagData;
				
			}
			else if (data[1] == 0x06) { //0x9F06[BCD] TAG_9F06_TERM_AID
				tag = 0x9F06;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F06 = " + tagData;
				
			}
			else if (data[1] == 0x26) { //0x9F26[HEX] TAG_9F26_APP_CRYPTOGRAM
				tag = 0x9F26;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F26 = " + tagData;
				
			}
			else if (data[1] == 0x21) { //0x9F21[BCD] TAG_9F21_TRANSACTION_TIME[Hour:Minute:Seconds]
				tag = 0x9F21;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "9F21 = " + tagData;
				
			}
			else {
				break;
			}
			break;
		}
	case 0xDF: {

			if (data[1] == 0x05)//0xDF05[HEX] TAG_DF05_TRANSACTION_RESULT REF. 1)
			{
				tag = 0xDF05;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF05 = " + tagData;
				
			}
			else if (data[1] == 0x06) //0xDF06[HEX] TAG_DF06_TRANSACTION_ERROR_CODE REF. "ERROR CODES"
			{
				tag = 0xDF06;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF06 = " + tagData;
				
			}
			else if (data[1] == 0x31) //0xDF31[STRING] TAG_DF31_TERMINAL_MERCHANT_NAME_BG
			{
				tag = 0xDF31;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF31 = " + tagData;
				
			}
			else if (data[1] == 0x30) //0xDF30[STRING] TAG_DF30_TERMINAL_MERCHANT_CITY_BG
			{
				tag = 0xDF30;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF30 = " + tagData;
				
			}
			else if (data[1] == 0x2F) //0xDF2F[STRING] TAG_DF2F_TERMINAL_MERCHANT_ADDRESS_BG
			{
				tag = 0xDF2F;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF2F = " + tagData;
				
			}
			else if (data[1] == 0x29) //0xDF29[STRING] TAG_DF29_TERMINAL_MERCHANT_POST_CODE
			{
				tag = 0xDF29;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF29 = " + tagData;
				
			}
			else if (data[1] == 0x2E) //0xDF2E[STRING] TAG_DF2E_TERMINAL_MERCHANT_TITLE_BG
			{
				tag = 0xDF2E;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF2E = " + tagData;
				
			}
			else if (data[1] == 0x28) //0xDF28[STRING] TAG_DF28_TERMINAL_MERCHANT_PHONE
			{
				tag = 0xDF28;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF28 = " + tagData;
				
			}
			else if (data[1] == 0x00) //0xDF00[STRING] TAG_DF00_CARD_SCHEME
			{
				tag = 0xDF00;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF00 = " + tagData;
				
			}
			else if (data[1] == 0x0A) //0xDF0A[STRING] TAG_DF0A_MASKED_PAN
			{
				tag = 0xDF0A;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF0A = " + tagData;
				
			}
			else if (data[1] == 0x25) //0xDF25[HEX] BOR_TAG_PAY_INTERFACE REF. 2)
			{
				tag = 0xDF25;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF25 = " + tagData;
				
			}
			else if (data[1] == 0x60) //0xDF60[HEX] BOR_TAG_CARD_SCHEME_CL REF. 3)
			{
				tag = 0xDF60;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF60 = " + tagData;
				
			}
			else if (data[1] == 0x10) //0xDF10[HEX] TAG_DF10_TRANS_TYPE REF. 4)
			{
				tag = 0xDF10;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF10 = " + tagData;
				
			}
			else if (data[1] == 0x0B) //0xDF0B[HEX] TAG_DF0B_LOYALTY_PTS
			{
				tag = 0xDF0B;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF0B = " + tagData;
				
			}
			else if (data[1] == 0x04) //0xDF04[HEX] TAG_DF04_AMOUNT_EUR
			{
				tag = 0xDF04;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF04 = " + tagData;
				
			}
			else if (data[1] == 0x23) //0xDF23[HEX] TAG_DF23_CVM_SIGNATURE REF. 5)
			{
				tag = 0xDF23;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF23 = " + tagData;
				
			}
			else if (data[1] == 0x07) //0xDF07[STRING] TAG_DF07_HOST_RRN
			{
				tag = 0xDF07;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF07 = " + tagData;
				
			}
			else if (data[1] == 0x08) //0xDF08[STRING] BOR_TAG_HOST_AUTH_ID
			{
				tag = 0xDF08;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF08 = " + tagData;
				
			}
			else if (data[1] == 0x09) //0xDF09[HEX] BOR_TAG_HOST_CODE
			{
				tag = 0xDF09;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF09 = " + tagData;
				
			}
			else if (data[1] == 0x61) //0xDF61[HEX] BOR_TAG_TRANS_BATCH_NUM
			{
				tag = 0xDF61;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF61 = " + tagData;
				
			}
			else if (data[1] == 0x62) //0xDF62[STRING] BOR_TAG_INTERFACE_ID
			{
				tag = 0xDF62;
				//tagData = Utility::toHexString(&data[3], data[2]);
				tagData.append((char*)&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF62 = " + tagData;
				
			}
			else if (data[1] == 0x79) //0xDF79[HEX] BOR_TAG_ISSUER_ID REF. 6)
			{
				tag = 0xDF79;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF79 = " + tagData;
				
			}
			else if (data[1] == 0x12) //0xDF12[HEX] BOR_TAG_TO_TYPE REF. 7)
			{
				tag = 0xDF12;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF12 = " + tagData;
				
			}
			else if (data[1] == 0x13) //0xDF13 RN
			{
				tag = 0xDF13;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF13 = " + tagData;
				
			}
			else if (data[1] == 0x5A) //0xDF13 RN
			{
				tag = 0xDF5A;
				tagData = Utility::toHexString(&data[3], data[2]);
				
				result = data[2] + 3;
				ss << "DF5A = " + tagData;
				
			}
			else {
				break;
			}
			break;
		}
	}
	Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	return result;
}
//---------------------------------------------------------------------------
bool BluePad::getLastTag(int id, std::string& tag) {
	for (int i = 0; i < TAGSLEN; i++) {
		if(tags[i].tag == id)
			tag = tags[i].data;
	}
	return true;
}
//---------------------------------------------------------------------------
/** Подождать появления новых тегов (проверку тегов сделал 10 раз в секунду 100 миллисекунд или 1000 микросекунд)
* Вызывается только в основном потоке
* @param timeout - в секундах
* return false если не удалось дождаться данных
*/
bool BluePad::waitTags(int timeout) {
	bool result = false;
	int t=m_tagsInCnt;

	timeout = timeout * 100;
	while(timeout>0){
		timeout--;
		if (t != m_tagsInCnt) {
			result = true;
			break;
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
	if (timeout == 0) {
		m_LastErrorCode = ERRTIMEOUT;
		m_LastErrorDescription = "Тайм-аут операции";
	}
	else {
		m_LastErrorCode = 0;
		m_LastErrorDescription = "";
	}

	return result;
}
//---------------------------------------------------------------------------
//Прочитать из пинпада 04: GET REPORT TAGS 
//type - 1 первая, 2 следующая, 3 последняя, 4 предыдущая
//tags - список тегов через запятую, пример: 81DAAA
MyError BluePad::getReportTags(int type, std::string tags, std::string& tagData) {
	if (m_SaveLog) Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", "Start getReportTags();");

	DataToSend* data = new DataToSend();
	data->mas[0] = 0x3E; // '>': start paket (ASCII symbol '>') 
	data->mas[1] = 0x3D; // COM: command number 
	data->mas[2] = 0x00; // 00
	data->mas[3] = 0x00; //LH length of DATA
	data->mas[4] = 0x00; //LL length of DATA
	data->mas[5] = 0x04; //04: GET REPORT TAGS
	data->mas[6] = 0x00; //Type 1
	data->mas[7] = type; //Type 2

	data->pos = 8;
	for (int i = 0; i < tags.length()/2; i++) {
		std::string str;
		str += tags[i * 2];
		str += tags[i * 2 + 1];
		data->addUChar(Utility::hexStdStrToUInt(str));
	}

	data->len = data->pos + 1;// 14
	data->mas[4] = data->len - 6; //8
	data->calcCRC();
	data->log_text = "getReportTags()";
	addData(data);

	MyError result;
	result.ErrorCode = 0;

	//Ожидаю когда количество прочитанных пакетов не увеличится на 1
	int cnt = m_cnt;
	int sec = 5 * 100; //5 секунд
	while (sec>0) {
		sec--;
		if (cnt < m_cnt)
			break;
		std::this_thread::sleep_for(std::chrono::milliseconds(10));
	}
	if (sec == 0) result.ErrorCode = ERRIO;

	int tag = 0;
	if (result.ErrorCode == 0) {

		if (m_length > 0) {
			std::string tags;
			int len = 0;
			int pos = 0;
			for (int i = 0; i < 33; i++) {
				len = readTag((unsigned char*)&m_ans[pos], m_length, tag, tags);
				tagData += tags + ";";
				pos += len;
				if (pos >= m_length)
					break;
			}
		}
		
	}


	ReadingError(result.ErrorCode, result.ErrorMessage);
	m_LastErrorCode = result.ErrorCode;
	m_LastErrorDescription = result.ErrorMessage;
	if (m_SaveLog)
	{
		std::stringstream ss;
		ss << "getReportTags(type = " << type << ",tags = "<< tags <<",tag = "<< tag <<",tagData = "<< tagData <<");";
		if (m_LastErrorCode != 0) ss << " ErrorCode: " << m_LastErrorCode << " ErrorDescription: " << m_LastErrorDescription;
		Utility::logrotate(m_LogFilePath + Utility::sp3() + "log.txt", ss.str());
	}
	return result;
}
//---------------------------------------------------------------------------
void BluePad::ReadingError(int Code, std::string& ErrorMessage) {

	switch (Code) {
	case 1:
		ErrorMessage = "errGeneral: Some error";
		break;
	case 2:
		ErrorMessage = "errInvCmd: No valid command or subcommand code";
		break;
	case 3:
		ErrorMessage = "errInvPar: Invalid paremeter";
		break;
	case 4:
		ErrorMessage = "errInvAdr: Address is outside limits";
		break;
	case 5:
		ErrorMessage = "errInvVal: Value is outside limits";
		break;
	case 6:
		ErrorMessage = "errInvLen: Length is outside limiuts";
		break;
	case 7:
		ErrorMessage = "errNoPermit: The action is not permit in current state";
		break;
	case 8:
		ErrorMessage = "errNoData: There is no data to be returned";
		break;
	case 9:
		ErrorMessage = "errTimeOut: Timeout is occur";
		break;
	case 10:
		ErrorMessage = "errKeyNum: Invalid key number";
		break;
	case 11:
		ErrorMessage = "errKeyAttr: Invalid key attributes(ussage)";
		break;
		/*case 11:
		ErrorMessage = "errKeyUsage: Invalid key attributes(ussage)";
		break;*/
	case 12:
		ErrorMessage = "errInvDevice: Calling of non - existing device";
		break;
	case 13:
		ErrorMessage = "errNoSupport: (No used in this FW version)";
		break;
	case 14:
		ErrorMessage = "errPinLimit: Pin entering limit exceed";
		break;
	case 15:
		ErrorMessage = "errFlash: Some error in flash commands";
		break;
	case 16:
		ErrorMessage = "errHard: Some hardware error";
		break;
	case 17:
		ErrorMessage = "errInvCRC: (No used in this FW version)";
		break;
	case 18:
		ErrorMessage = "errCancel: The button \"CANCEL\" is pressed";
		break;
	case 19:
		ErrorMessage = "errInvSign: Invalid signature";
		break;
	case 20:
		ErrorMessage = "errInvHead: Invalid data in header";
		break;
	case 21:
		ErrorMessage = "errInvPass: Incorrent password";
		break;
	case 22:
		ErrorMessage = "errKeyFormat: Invalid key format";
		break;
	case 23:
		ErrorMessage = "errSCR: Some error in smart card reader";
		break;
	case 24:
		ErrorMessage = "errHAL: Error code is returned from HAL functions";
		break;
	case 25:
		ErrorMessage = "errInvKey: Invalid key(may be no pressent)";
		break;
	case 26:
		ErrorMessage = "errNoPinData: The PIN length is <4 or >12";
		break;
	case 27:
		ErrorMessage = "errInvRemainder: Issuer or ICC key invalid remainder length";
		break;
	case 28:
		ErrorMessage = "errNoInit: (No used in this FW version)";
		break;
	case 29:
		ErrorMessage = "errLimit: (No used in this FW version)";
		break;
	case 30:
		ErrorMessage = "errInvSeq: (No used in this FW version)";
		break;
	case 31:
		ErrorMessage = "errNoPerm: The action is not permited";
		break;
	case 32:
		ErrorMessage = "errNoTMK: TMK is not loaded.The action cannot be executed";
		break;
	case 33:
		ErrorMessage = "errInvKek: Wrong kek format";
		break;
	case 34:
		ErrorMessage = "errDubKey: Dublicated key";
		break;
	case 35:
		ErrorMessage = "errKBD: General keyboard error";
		break;
	case 36:
		ErrorMessage = "errKBDNoCal: The keyboard is no calibrated";
		break;
	case 37:
		ErrorMessage = "errKBDBug: Keyboard bug detected";
		break;
	case 38:
		ErrorMessage = "errBusy: The device is busy, tray again";
		break;
	case 39:
		ErrorMessage = "errTampered: The devicete in security tampered";
		break;
	case 40:
		ErrorMessage = "errEmsr: Error in encrypted head";
		break;
	case 41:
		ErrorMessage = "errAccept: The button \"OK\" is pressed";
		break;
	case 42:
		ErrorMessage = "errInvPAN: Wrong PAN";
		break;
	case 43:
		ErrorMessage = "errOutOfMemory: No enought memory";
		break;
	case 44:
		ErrorMessage = "errEMV: Some EMV error";
		break;
	case 45:
		ErrorMessage = "errCrypt: Cryptographic error";
		break;
	case 46:
		ErrorMessage = "errComRcv: Something is received";
		break;
	case 47:
		ErrorMessage = "errWrongVer: Wrong version.update to old firmware for example";
		break;
	case 48:
		ErrorMessage = "errNoPaper: Printer is out of paper";
		break;
	case 49:
		ErrorMessage = "errTooHot: Printer is overheating";
		break;
	case 50:
		ErrorMessage = "errNoConnected: The device is not connected";
		break;
	case 51:
		ErrorMessage = "errUseChip: Use the chip reader";
		break;
	case 52:
		ErrorMessage = "errEndDay: End the day first";
		break;
	case ERRIO:
		ErrorMessage = "errIO: Ошибка связи, устройство не отвечает";
		break;
	case ERRCRC:
		ErrorMessage = "errCRC: Ошибка при подсчёте CRC";
		break;
	case ERRSOCK:
		ErrorMessage = "ERRSOCK: Ошибка закрытия сокета";
		break;
	case ERRSOCKSND:
		ErrorMessage = "ERRSOCKSND: Ошибка отправки данных в сокет";
		break;
	case ERRTIMEOUT:
		ErrorMessage = "ERRTIMEOUT: Тайм-аут операции";
		break;
	}
}
//---------------------------------------------------------------------------
//Получить описание статуса
void BluePad::ReadingStatus(int Status, std::string& Message) {

	switch (Status) {
	case PAY_CL_UI_NOT_WORKING:
		Message = "Не работает";
		break;
	case PAY_CL_UI_APPROVED:
		Message = "Утверждено";
		break;
	case PAY_CL_UI_DECLINED:
		Message = "Отклонено";
		break;
	case PAY_CL_UI_ENTER_PIN:
		Message = "Введите PIN";
		break;
	case PAY_CL_UI_ERROR_PROCESSING:
		Message = "Обработка ошибки";
		break;
	case PAY_CL_UI_REMOVE_CARD:
		Message = "Уберите карту";
		break;
	case PAY_CL_UI_IDLE:
		Message = "Бездейственный";
		break;
	case PAY_CL_UI_PRESENT_CARD:
		Message = "Приложите карту";
		break;
	case PAY_CL_UI_PROCESSING:
		Message = "Обработка";
		break;
	case PAY_CL_UI_CARD_READ_OK_REMOVE:
		Message = "Считывание карты удалено";
		break;
	case PAY_CL_UI_TRY_OTHER_INTERFACE:
		Message = "Попробуйте другой интерфейс";
		break;
	case PAY_CL_UI_CARD_COLLISION:
		Message = "Столкновение карт";
		break;
	case PAY_CL_UI_SIGN_APPROVED:
		Message = "Подпись подтверждена";
		break;
	case PAY_CL_UI_ONLINE_AUTHORISATION:
		Message = "Онлайн авторизация";
		break;
	case PAY_CL_UI_TRY_OTHER_CARD:
		Message = "Попробуйте другую карту";
		break;
	case PAY_CL_UI_INSERT_CARD:
		Message = "Вставте картку";
		break;
	case PAY_CL_UI_CLEAR_DISPLAY:
		Message = "Очистить дисплей";
		break;
	case PAY_CL_UI_SEE_PHONE:
		Message = "Посмотреть на телефон";
		break;
	case PAY_CL_UI_PRESENT_CARD_AGAIN:
		Message = "Приложите карту еще раз";
		break;
	case PAY_CL_UI_CARD_ERROR:
		Message = "Ошибка карты";
		break;
	case PAY_CL_UI_CARD_BLOCKED:
		Message = "Карта заблокирована";
		break;
	case PAY_CL_UI_CARD_NUMBER:
		Message = "Номер карты";
		break;
	case PAY_CL_UI_INVALID_NUMBER:
		Message = "Недействительный номер";
		break;
	case PAY_CL_UI_EXPIRATION_DATE:
		Message = "Срок годности";
		break;
	case PAY_CL_UI_ENTER_CVV:
		Message = "Введите cvv";
		break;
	case PAY_CL_UI_MANUAL_BUTTON:
		Message = "Ручной ввод";
		break;
	case PAY_CL_UI_MAGNETIC_BUTTON:
		Message = "Магнитная кнопка";
		break;
	case PAY_CL_UI_SWIPE_MAGNETIC_CARD:
		Message = "Магнитная карта";
		break;
	case EMV_UI_TRY_AGAIN:
		Message = "Попробуйте еще раз";
		break;
	}
}
//---------------------------------------------------------------------------