//--------------------------------------------------------------------------- #include "stdafx.h" //------------------------------------------------------------------------------ #pragma hdrstop #include #include //#include #include "Validator.h" #include "inifile.h" #include "stdTools.h" //#include "ud_Module.h" //--------------------------------------------------------------------------- //Validator* validator=NULL; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- unsigned char ConReset[6] = { 0x02,0x03,0x06,0x30,0x41,0xB3 }; //RESET Перезагрузить валидатор unsigned char ConReACK[6] = { 0x02,0x03,0x06,0x00,0xC2,0x82 }; //Ответ валидатору что всё нормально... unsigned char ConStPoll[6] = { 0x02,0x03,0x06,0x33,0xDA,0x81 }; //POLL 33H Request for Bill-to-Bill unit activity Status (Перейти в режим получения платежей) unsigned char ConIdent[6] = { 0x02,0x03,0x06,0x37,0xFE,0xC7 }; //IDENTIFICATION 37H Request for Model, Serial Number, Country ISO code, Asset Number //#pragma package(smart_init) //--------------------------------------------------------------------------- #define POLYNOMIAL 0x08408 unsigned int GetCRC16(unsigned char* bufData, unsigned int sizeData) { unsigned int CRC, i; unsigned char j; CRC = 0; for(i=0; i < sizeData; i++) { CRC ^= bufData[i]; for(j=0; j < 8; j++) { if(CRC & 0x0001) {CRC >>= 1; CRC ^= POLYNOMIAL;} else CRC >>= 1; } } return CRC; } //--------------------------------------------------------------------------- /*unsigned int GetCRC16(char* bufData, unsigned int sizeData) { return GetCRC16((unsigned char*)bufData, sizeData); }*/ //--------------------------------------------------------------------------- //Добавить нули к цифре int addZero(int val,int cnt) { for(int i=0;iLoad("settings.ini"); cPort->ComNumber=ini->ReadString("Validator","Port","0"); cPort->BaudRate=ini->ReadLong("Validator","BaudRate","0"); m_testmode=ini->ReadBool("Validator","TestMode","0"); delete ini; }*/ //--------------------------------------------------------------------------- bool Validator::OpenCOMPort(std::string ComNumber, int BaudRate) { cPort->ComNumber = ComNumber; cPort->BaudRate = BaudRate; cPort->Close(); if (cPort->Open(cPort->ComNumber)) { if (!cPort->Setup(2)) return false; if (!cPort->SetTimeout(500)) //50 это 5 секунд так как задаётся в 1/10 секунды return false; } else return false; return true; } //--------------------------------------------------------------------------- //Сравнить последние 2 байта с CRC данных bool Validator::CheckOnCRC(unsigned char* lpBuffer,unsigned long nSize) { if(nSize<2) return false; unsigned int CRC=GetCRC16(lpBuffer,nSize-2); unsigned int* pCRC=(unsigned int*)&lpBuffer[nSize-2]; return (CRC==*pCRC); } //--------------------------------------------------------------------------- //req - Строка запроса без CRC //ans - Ответ на команду //Результата совпал CRC или нет bool Validator::SendCommand(std::string req, std::string &ans) { unsigned short crc=GetCRC16((unsigned char*)req.c_str(),req.size()); req+=((char*)(&crc))[0]; req+=((char*)(&crc))[1]; unsigned int BytesWritten=cPort->Write(req.c_str(),req.size()); //Чтение ответа ans=""; for(int i=0;i<255;i++) { Sleep(10); char ch; unsigned int BytesRead=cPort->Read(&ch,1); if (BytesRead>0) ans+=ch; else break; } //Проверка ответа на CRC if(ans.size()>=2) { crc=GetCRC16((unsigned char*)ans.c_str(),ans.size()-2); if(crc==((unsigned short*)(&ans.c_str()[ans.size()-2]))[0]) return true; } return false; } //--------------------------------------------------------------------------- //Инициализация переменных валидатора bool Validator::Start() { bool result=true; if(result) result=result && Reset(); //Перезагрузить валидатор if(result) result=result && getSerialNumber(); //Получить серийный номер валидатора if(result) result=result && getNominals(); //Получить номиналы прошитых купюр if(result) result=result && SetEnableBillTypes(true); //Разрешить приём всех прошитых купюр return result || m_testmode; //В тестовом режиме всегда всё OK } //--------------------------------------------------------------------------- //Перезагрузить валидатор (RESET 30H Command for Bill-to-Bill unit to self-reset) bool Validator::Reset() { std::string req,ans; req+=(char)0x02; req+=(char)0x03; req+=(char)0x06; req+=(char)0x30; return SendCommand(req,ans); } //--------------------------------------------------------------------------- //Получить статус валидатора (GET STATUS 31H Request for Bill-to-Bill unit set-up status) bool Validator::GetStatus() { std::string req,ans; req+=(char)0x02; req+=(char)0x03; req+=(char)0x06; req+=(char)0x31; //req+=(char)0x41; req+=(char)0xB3; bool r=SendCommand(req,ans); if(r && ans.length()>6) //Почему то всегда без данных { //Первые 3 байта показывают какие типы платижей разрешены //Следующие 3 байта указывают какой уровень защиты установлен //Следующие 3 По моему какие касеты готовы принимать деньги } return r; } //--------------------------------------------------------------------------- //Разрешить либо запретить приём заданных видов купюр //enable - true разрешить всё, false запретить всё bool Validator::SetEnableBillTypes(bool enable) { std::string req,ans; if(enable) { req+=(char)0x02; req+=(char)0x03; req+=(char)0x0C; req+=(char)0x34; req+=(char)0xFF; req+=(char)0xFF; req+=(char)0xFF; //24 бита req+=(char)0x00; req+=(char)0x00; req+=(char)0x00; //24 бита }else { req+=(char)0x02; req+=(char)0x03; req+=(char)0x0C; req+=(char)0x34; req+=(char)0x00; req+=(char)0x00; req+=(char)0x00; //24 бита req+=(char)0x00; req+=(char)0x00; req+=(char)0x00; //24 бита } bool r=SendCommand(req,ans); return r; } //--------------------------------------------------------------------------- bool Validator::getSerialNumber() { unsigned int BytesWritten=cPort->Write(ConIdent,sizeof(ConIdent)); unsigned int BytesRead=cPort->Read(ReadAr,sizeof(ReadAr)); if(!CheckOnCRC(ReadAr,BytesRead)) return false; //Нужный ли нам ответ if(BytesRead!=39) { Utility::logrotate("validator.log","Не удалось получить номер партии валидатора"); return false; } //Выбираем № партии std::string str1((char*)&ReadAr[3],15); BatchNumber= Utility::trim(str1); std::string str2((char*)&ReadAr[18],12); SerialNumber= Utility::trim(str2); Sleep(100); return true; } //--------------------------------------------------------------------------- //Получить номиналыы купюр принимаемые валидатором bool Validator::getNominals() { unsigned char ConGetBT[6] = { 0x02,0x03,0x06,0x41,0x4F,0xD1 }; //GET BILL TABLE Какие купюры прошиты в валидаторе ConGetBT[5] = GetCRC16(ConGetBT, 5); //Считаю CRC bNominals=false; Sleep(100); //на всяк unsigned int BytesWritten=cPort->Write(ConGetBT,sizeof(ConGetBT)); unsigned int BytesRead=cPort->Read(ReadAr,sizeof(ReadAr)); if(!CheckOnCRC(ReadAr,BytesRead)) return bNominals; Sleep(100); //на всяк for(unsigned char i=0;i<23;i++) { bt[i].val=addZero(ReadAr[3+i*5],ReadAr[3+i*5+4]); //Код страны 3 буквы bt[i].country[0]=ReadAr[3+i*5+1]; bt[i].country[1]=ReadAr[3+i*5+2]; bt[i].country[2]=ReadAr[3+i*5+3]; bt[i].val=addZero(ReadAr[3+i*5],ReadAr[3+i*5+4]); } bNominals=true; return bNominals; } //--------------------------------------------------------------------------- //Попытка приёма платежа, выполняется в цикле в отдельном потоке. //state - текущее состояние валидатора (См. документацию) //результат принятая сумма или 0 если ничего не принято int Validator::getTHPay(int &state) { state=0; int result = 0; if(!cPort->isOpen()){Sleep(1000); return result;} unsigned char buffer[255]; memset(buffer, 0, sizeof(buffer)); unsigned int BytesWritten=0; unsigned int BytesRead=0; BytesWritten=cPort->Write(ConReACK, sizeof(ConReACK)); //Ответ валидатору что всё нормально Sleep(10); BytesWritten=cPort->Write(ConStPoll, sizeof(ConStPoll)); //Перейти в режим получения платежей BytesRead=cPort->Read(buffer,sizeof(buffer)); if(CheckOnCRC(buffer,BytesRead)) { switch (buffer[3]) { case 0x13://19 Ещё в режиме инициализации после выполнения команды RESET //Utility::logrotate("validator.log","(State)0x13 Инициализация"); break; case 0x14: //20 Означает что находимся в режиме ожидания приёма платежа (IDLING – The state in which Bill-to-Bill is ready accept bills) //Utility::logrotate("validator.log","(State)0x14 В режиме ожидания купюры"); break; case 0x15: //21 Производит сканирование купюры и определяется наминал (У меня 3 раза на купюру) state = 0x15; //Utility::logrotate("validator.log","(State)21 Прошла 1 из проверок"); break; case 0x17: //23 Приём купюры в отсек если не получится положить то вернёт купюру обратно state = 0x17; //Utility::logrotate("validator.log","(State)23 Приём купюры!"); break; case 0x19://25 DISABLED – The Bill-to-Bill unit has been disabled by the Controller and also the state in which Bill-to-Bill unit is after initialization. state = 0x19; //Utility::logrotate("validator.log","(State)25 отменён приём!!!"); SetEnableBillTypes(true); break; case 0x1c: //28 Извлечена купюра //Utility::logrotate("validator.log","(State)28 Купюра извлечена"); break; case 0x41: //41H Заполнился мешок под завязку... //Utility::logrotate("validator.log","(State)0x41 Заполнился мешок под завязку..."); break; case 0x45: //69 Обнаружена попытка обмана "фальшивка". //Utility::logrotate("validator.log","(State)69 Незнаю"); break; case 0x81: //129 В какую касету попала купюра state = 0x81; //Utility::logrotate("validator.log","(State)129 Принята купюра"); if (buffer[4]<23) { result = bt[buffer[4]].val; //В касете buffer[5] Utility::logrotate("validator.log", "(Pay)" + Utility::IntToStdStr(result)); } break; default: Utility::logrotate("validator.log", "(State???)" + Utility::IntToStdStr(buffer[3])); } Utility::logrotate("validator.log", "buffer[3] = " + Utility::IntToStdStr(buffer[3])); Utility::logrotate("validator.log", "state = " + Utility::IntToStdStr(state)); } Sleep(100); return result; } //--------------------------------------------------------------------------- //Завершение работы по приёму платежей void Validator::endPay() { SetEnableBillTypes(false); unsigned int BytesWritten,BytesRead; BytesWritten=cPort->Write(ConReACK , sizeof(ConReACK)); BytesWritten=cPort->Write(ConStPoll , sizeof(ConStPoll)); BytesRead=cPort->Read(ReadAr,sizeof(ReadAr)); } //--------------------------------------------------------------------------- int Validator::GetState() //Если 0 то всё в порядке { if(m_testmode) return 0; //if(! bNominals) getNominals(); //todo не подходит для проверки if(! bNominals) return 1; return 0; } //--------------------------------------------------------------------------- std::string Validator::GetStatusDescription(char StatusCode) //Описание статуса { if (StatusCode == 0x00) return "OK"; else if (StatusCode == 1) return "Не удалось получить номиналы купюр"; else return "Error"; } //--------------------------------------------------------------------------- bool Validator::startPay() //Стартуем поток { if (!execute_thread) //Чтобы не запускать поток заново { int ret = pthread_create(&m_threadid, NULL, Validator::thread_func, (void*)this); if (ret == 0) execute_thread = true; } return execute_thread; } //--------------------------------------------------------------------------- bool Validator::stopPay() //Стопим поток с ожиданием его завершения { if (execute_thread) { execute_thread = false; void* ret = NULL; pthread_join(m_threadid, &ret); } return !execute_thread; } //--------------------------------------------------------------------------- void* Validator::thread_func(void *pData) { Validator* validator=(Validator*) pData; while (validator->execute_thread) { int pay,state; pay = validator->getTHPay(state); //Защищаем переменную мютексом if (pthread_mutex_lock(&validator->m_mutex) == 0) { validator->m_payState = state; pthread_mutex_unlock(&validator->m_mutex); } if (pay > 0) //Если произвели оплату то добавляем в список платежей { if (pthread_mutex_lock(&validator->m_mutex) == 0) //Защищаем список мютексом { validator->m_pays.add(pay); pthread_mutex_unlock(&validator->m_mutex); } } } validator->endPay(); return NULL; } //--------------------------------------------------------------------------- //Получить значение из нокопившегося списка оплат, значение удаляется из списка //Если что заплатили то результат больше нуля int Validator::getPay() { int pay = 0; if (pthread_mutex_lock(&m_mutex) == 0) //Защищаем список мютексом { if (m_pays.count() > 0) { pay = m_pays.get(0); m_pays.del((unsigned int)0); } pthread_mutex_unlock(&m_mutex); } return pay; } //--------------------------------------------------------------------------- int Validator::getPayState() { int result = 0; if (pthread_mutex_lock(&m_mutex) == 0) //Защищаем список мютексом { result = m_payState; pthread_mutex_unlock(&m_mutex); } return result; } //---------------------------------------------------------------------------