//------------------------------------------------------------------------------ #pragma hdrstop #include #include "Validator.h" #include "ud_Module.h" //--------------------------------------------------------------------------- Validator* validator=NULL; //--------------------------------------------------------------------------- #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;iComNumber=ini->ReadInteger("Validator","Port",0); cPort->BaudRate=ini->ReadInteger("Validator","BaudRate",0); delete ini; } //--------------------------------------------------------------------------- void Validator::SaveSetup() { TIniFile* ini=new TIniFile(ExtractFilePath(ParamStr(0))+"\\Setup.ini"); ini->WriteInteger("Validator","Port",cPort->ComNumber); ini->WriteInteger("Validator","BaudRate",cPort->BaudRate); delete ini; } //--------------------------------------------------------------------------- bool Validator::startPay() //Стартуем поток { if(vThread!=NULL) vThread->Stop(); //На всяк случай vThread = new ValidatorThread(false); } //--------------------------------------------------------------------------- bool Validator::stopPay() //Стопим поток { if(vThread!=NULL) vThread->Stop(); } //--------------------------------------------------------------------------- //Сравнить последние 2 байта с CRC данных bool Validator::CheckOnCRC(unsigned char* lpBuffer,unsigned long nSize) { if(nSize<2) return false; unsigned int CRC=GetCRC16(lpBuffer,nSize-2); WORD* pCRC=(WORD*)&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]; DWORD BytesWritten=cPort->Write(req.c_str(),req.size()); //Чтение ответа ans=""; for(int i=0;i<255;i++) { Sleep(10); char ch; DWORD 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() { if(cPort->Open(cPort->ComNumber)) { cPort->BaudRate=cPort->BaudRate; if(!cPort->Setup(2)) return false; if(!Reset()) return false; //Перезагрузить валидатор if(!getSerialNumber()) return false; //Получить серийный номер if(!getNominals()) return false; //Получить номиналы прошитых купюр if(!SetEnableBillTypes(true)) return false; //Разрешить приём всех прошитых купюр }else return false; } //--------------------------------------------------------------------------- //Перезагрузить валидатор (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() { DWORD BytesWritten=cPort->Write(ConIdent,sizeof(ConIdent)); DWORD BytesRead=cPort->Read(ReadAr,sizeof(ReadAr)); if(!CheckOnCRC(ReadAr,BytesRead)) return false; //Нужный ли нам ответ if(BytesRead!=39) { saveLog(1,"Не удалось получить номер партии валидатора"); return false; } //Выбираем № партии AnsiString str1((char*)&ReadAr[3],15); BatchNumber=str1.Trim(); AnsiString str2((char*)&ReadAr[18],12); SerialNumber=str2.Trim(); Sleep(100); return true; } //--------------------------------------------------------------------------- //Получить номиналыы купюр принимаемые валидатором bool Validator::getNominals() { bNominals=false; Sleep(100); //на всяк DWORD BytesWritten=cPort->Write(ConGetBT,sizeof(ConGetBT)); DWORD 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::getPay(int &state) { state=0; if(!cPort->bOpen){Sleep(1000); return 0;} int result=0; DWORD BytesWritten=0; DWORD BytesRead=0; BytesWritten=cPort->Write(ConReACK, sizeof(ConReACK)); //Ответ валидатору что всё нормально Sleep(10); BytesWritten=cPort->Write(ConStPoll, sizeof(ConStPoll)); //Перейти в режим получения платежей BytesRead=cPort->Read(ReadAr,sizeof(ReadAr)); if(CheckOnCRC(ReadAr,BytesRead)) { if(ReadAr[3] == 0x13) //19 Ещё в режиме инициализации после выполнения команды RESET { //saveLog(1,"(State)0x13 Инициализация"); }else if(ReadAr[3]==0x14) //20 Означает что находимся в режиме ожидания приёма платежа (IDLING – The state in which Bill-to-Bill is ready accept bills) { //saveLog(1,"(State)0x14 В режиме ожидания купюры"); }else if(ReadAr[3]==0x15) //21 Производит сканирование купюры и определяется наминал (У меня 3 раза на купюру) { state=0x15; //saveLog(1,"(State)21 Прошла 1 из проверок"); }else if(ReadAr[3]==0x17) //23 Приём купюры в отсек если не получится положить то вернёт купюру обратно { //saveLog(1,"(State)23 Приём купюры!"); }else if(ReadAr[3]==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; //saveLog(1,"(State)25 отменён приём!!!"); SetEnableBillTypes(true); }else if(ReadAr[3]==0x1c) //28 Извлечена купюра { //saveLog(1,"(State)28 Купюра извлечена"); }else if(ReadAr[3]==0x41) //41H Заполнился мешок под завязку... { //saveLog(1,"(State)0x41 Заполнился мешок под завязку..."); }else if(ReadAr[3]==0x45) //69 Обнаружена попытка обмана "фальшивка". { //saveLog(1,"(State)69 Незнаю"); }else if(ReadAr[3]==0x81) //129 В какую касету попала купюра { state=0x81; //saveLog(1,"(State)129 Принята купюра"); if(ReadAr[4]<23) { result=bt[ReadAr[4]].val; //В касете ReadAr[5] saveLog(1,"(Pay)"+IntToStr(result)); } }else saveLog(1,"(State???)"+IntToStr(ReadAr[3])); saveLog(1,"(State???)"+IntToStr(ReadAr[3])); } Sleep(100); return result; } //--------------------------------------------------------------------------- //Завершение работы по приёму платежей void Validator::endPay() { SetEnableBillTypes(false); DWORD 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(! bNominals) getNominals(); //todo не подходит для проверки if(! bNominals) return 1; return 0; } //--------------------------------------------------------------------------- AnsiString Validator::GetStatusDescription(BYTE StatusCode) //Описание статуса { if (StatusCode == 0x00) return "OK"; else if (StatusCode == 1) return "Не удалось получить номиналы купюр"; else return "Error"; } //---------------------------------------------------------------------------