Files
Tools_CPP/devices/Acquiring/BluePad/BluePad.cpp
2024-11-01 12:23:13 +05:00

2694 lines
86 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Для того чтобы войти в ражим настройки пароль: 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;
}
}
//---------------------------------------------------------------------------