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