/* * Для того чтобы войти в ражим настройки пароль: 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 #include #include #include #include //--------------------------------------------------------------------------- #if defined(WIN32) || defined(_WINDOWS) || defined(_BORLAND) #include #include 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 //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; iComNumber = 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; iRead(&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 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 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; icsPort->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; } } //---------------------------------------------------------------------------