幽冥大陆(十六)纸币器BV20识别纸币——东方仙盟筑基期
纸币检测软件
#include "StdAfx.h"
#include "Validator.h"CValidator::CValidator(void)
{cmd = new SSP_COMMAND();keys = new SSP_KEYS(); info = new SSP_COMMAND_INFO();// Create ssp library functionsInitialiseLibrary();m_NumberOfChannels = 0; m_Type = 0;m_NumStackedNotes = 0;m_UnitData = 0;
}CValidator::~CValidator(void)
{if (m_UnitData)delete[] m_UnitData; delete info;delete keys;delete cmd;
}bool CValidator::IsUnitValid()
{if(GetUnitType() != 0x00){return false;}return true;
}bool CValidator::InitialiseLibrary()
{// Load dllCString strLib = _T("ITLSSPProc.dll");HINSTANCE hInst = LoadLibrary(strLib);if (hInst != NULL){// Link function names// Open the COM portOpenPort = (LPFNDLLFUNC1)GetProcAddress(hInst, "OpenSSPComPortUSB");if (OpenPort == NULL){FreeLibrary(hInst);return false;}// Close the COM portClosePort = (LPFNDLLFUNC2)GetProcAddress(hInst, "CloseSSPComPortUSB");if (ClosePort == NULL){FreeLibrary(hInst);return false;}// Send a command to the unitSSPSendCommand = (LPFNDLLFUNC3)GetProcAddress(hInst, "SSPSendCommand");if (SSPSendCommand == NULL){FreeLibrary(hInst);return false;}// Create the generator and modulus prime numbers for the key encryptionInitiateSSPHostKeys = (LPFNDLLFUNC4)GetProcAddress(hInst, "InitiateSSPHostKeys");if (InitiateSSPHostKeys == NULL){FreeLibrary(hInst);return false;}// Create the final encryption keyCreateSSPHostEncryptionKey = (LPFNDLLFUNC5)GetProcAddress(hInst, "CreateSSPHostEncryptionKey");if (CreateSSPHostEncryptionKey == NULL){FreeLibrary(hInst);return false;}}elsereturn false;return true;
}// The enable command allows the validator to accept all commands.
bool CValidator::EnableValidator()
{cmd->CommandData[0] = SSP_CMD_ENABLE;cmd->CommandDataLength = 1;if (!SendCommand()) return false;// check responseif (CheckGenericResponses()){ }return true;
}// Disable command stops the validator accepting most commands.
bool CValidator::DisableValidator()
{cmd->CommandData[0] = SSP_CMD_DISABLE;cmd->CommandDataLength = 1;if (!SendCommand()) return false;// check responseif (CheckGenericResponses()){}return true;
}// The reset command instructs the validator to restart (same effect as switching on and off)
bool CValidator::ResetValidator()
{cmd->CommandData[0] = SSP_CMD_RESET;cmd->CommandDataLength = 1;if (!SendCommand()){return false;}// check responseif(CheckGenericResponses()){ }return true;
}// This function sets the protocol version in the validator to the version passed across. Whoever calls
// this needs to check the response to make sure the version is supported.
bool CValidator::SetProtocolVersion(char pVersion)
{cmd->CommandData[0] = SSP_CMD_HOST_PROTOCOL_VERSION;cmd->CommandData[1] = pVersion;cmd->CommandDataLength = 2;if (!SendCommand()) return false;return true;
}// This function sends the command LAST REJECT CODE which gives info about why a note has been rejected. It then
// outputs the info.
void CValidator::QueryRejection()
{cmd->CommandData[0] = SSP_CMD_LAST_REJECT_CODE;cmd->CommandDataLength = 1;if (!SendCommand()) return;if (CheckGenericResponses()){switch (cmd->ResponseData[1]) // Reason for rejection located in second byte of response{case 0x00: //*m_Output << "Note accepted" << endl; break;case 0x01: //*m_Output << "Note length incorrect" << endl; break;case 0x02: //*m_Output << "Invalid note" << endl; break;case 0x03: //*m_Output << "Invalid note" << endl; break;case 0x04: //*m_Output << "Invalid note" << endl; break;case 0x05: //*m_Output << "Invalid note" << endl; break;case 0x06: //*m_Output << "Channel inhibited" << endl; break;case 0x07: //*m_Output << "Second note inserted during read" << endl; break;case 0x08: //*m_Output << "Host rejected note" << endl; break;case 0x09: //*m_Output << "Invalid note" << endl; break;case 0x0A: //*m_Output << "Invalid note read" << endl; break;case 0x0B: //*m_Output << "Note too long" << endl; break;case 0x0C: //*m_Output << "Validator disabled" << endl; break;case 0x0D: //*m_Output << "Mechanism slow/stalled" << endl; break;case 0x0E: //*m_Output << "Strim attempt" << endl; break;case 0x0F: //*m_Output << "Fraud channel reject" << endl; break;case 0x10: //*m_Output << "No notes inserted" << endl; break;case 0x11: //*m_Output << "Invalid note read" << endl; break;case 0x12: //*m_Output << "Twisted note detected" << endl; break;case 0x13: //*m_Output << "Escrow time-out" << endl; break;case 0x14: //*m_Output << "Bar code scan fail" << endl; break;case 0x15: //*m_Output << "Invalid note read" << endl; break;case 0x16: //*m_Output << "Invalid note read" << endl; break;case 0x17: //*m_Output << "Invalid note read" << endl; break;case 0x18: //*m_Output << "Invalid note read" << endl; break;case 0x19: //*m_Output << "Incorrect note width" << endl; break;case 0x1A: //*m_Output << "Note too short" << endl; break;}}
}// This function performs a number of commands in order to setup the encryption between the host and the validator.
bool CValidator::NegotiateKeys()
{int i; // make sure encryption is offcmd->EncryptionStatus = false;// send synccmd->CommandData[0] = SSP_CMD_SYNC;cmd->CommandDataLength = 1;if (!SendCommand()) return false;InitiateSSPHostKeys(keys, cmd);// send generatorcmd->CommandData[0] = SSP_CMD_SET_GENERATOR;cmd->CommandDataLength = 9;for (i = 0; i < 8; ++i){cmd->CommandData[i + 1] = (char)(keys->Generator >> (8 * i));}if (!SendCommand()) return false;// send moduluscmd->CommandData[0] = SSP_CMD_SET_MODULUS;cmd->CommandDataLength = 9;for (i = 0; i < 8; ++i){cmd->CommandData[i + 1] = (char)(keys->Modulus >> (8 * i));}if (!SendCommand()) return false;// send key exchangecmd->CommandData[0] = SSP_CMD_KEY_EXCHANGE;cmd->CommandDataLength = 9;for (i = 0; i < 8; ++i){cmd->CommandData[i + 1] = (char)(keys->HostInter >> (8 * i));}if (!SendCommand()) return false;keys->SlaveInterKey = 0;for (i = 0; i < 8; ++i){keys->SlaveInterKey += (ULONG)cmd->ResponseData[1 + i] << (8 * i);}CreateSSPHostEncryptionKey(keys);// get full encryption keycmd->Key.FixedKey = 0x0123456701234567;cmd->Key.EncryptKey = keys->KeyHost;cmd->EncryptionStatus = true; // turn on encrypting//*m_Output << "Negotiated keys" << endl;return true;
}// This function uses the setup request command to get information about the validator. The response
// packet is a variable length due to the fact that the number of channels is not known beforehand.
bool CValidator::SetupRequest()
{ // send setup requestcmd->CommandData[0] = SSP_CMD_SETUP_REQUEST;cmd->CommandDataLength = 1;if (!SendCommand()) return false;// check responseif (CheckGenericResponses()){// Output setup request data// Unit type//*m_Output << "Unit type: ";m_Type = cmd->ResponseData[1];switch (m_Type){case 0x00: //*m_Output << "Note Validator" << endl; break;case 0x03: //*m_Output << "SMART Hopper" << endl; break;case 0x06: //*m_Output << "SMART Payout" << endl;break;case 0x07: //*m_Output << "NV11" << endl; break;}// Firmware//*m_Output << "Firmware: ";//*m_Output << cmd->ResponseData[2] << cmd->ResponseData[3] << "." <<// cmd->ResponseData[4] << cmd->ResponseData[5] << endl;// Channel setup// End of fixed dataint index = 12;m_NumberOfChannels = cmd->ResponseData[index++];m_UnitData = new SChannelData[m_NumberOfChannels];index += m_NumberOfChannels; // Skip old channel valuesindex += m_NumberOfChannels; // Skip channel security levelsindex += 3; // Skip value multiplier// Protocol versionm_ProtocolVersion = cmd->ResponseData[index++];//*m_Output << "Protocol Version: " << (int)m_ProtocolVersion << endl;// Setup channel data// Currencies//*m_Output << "Channel Currencies: ";for (int i = 0; i < m_NumberOfChannels; ++i){m_UnitData[i].Channel = i + 1;for (int j = 0; j < 3; ++j){m_UnitData[i].Currency[j] = cmd->ResponseData[index + j];//*m_Output << m_UnitData[i].Currency[j];}index += 3;//*m_Output << " ";}//*m_Output << endl;// Values//*m_Output << "Channel Values: ";int i;for( i = 0; i < m_NumberOfChannels; ++i){for (int j = 0; j < 4; ++j)m_UnitData[i].Value += (int)cmd->ResponseData[index++] << (8*j);//*m_Output << m_UnitData[i].Value << " ";}//*m_Output << endl; }return true;
}// This function sends the set inhibits command to set the inhibits on the validator.
// The two bytes after the command byte represent two bit registers with each bit being
// a channel. 1-8 and 9-16 respectively. 0xFF = 11111111 in binary indicating all channels
// in this register are able to accept notes.
bool CValidator::SetInhibits()
{// set inhibitscmd->CommandData[0] = SSP_CMD_SET_INHIBITS;cmd->CommandData[1] = 0xFF;cmd->CommandData[2] = 0xFF;cmd->CommandDataLength = 3;if (!SendCommand()) return false;// check responseif (CheckGenericResponses()){// *m_Output << "Inhibits set" << endl;}return true;
}// The poll function is called repeatedly to poll to validator for information, it returns as
// a response in the command structure what events are currently happening.
bool CValidator::DoPoll(int &nRMB_value)
{// send pollcmd->CommandData[0] = SSP_CMD_POLL;cmd->CommandDataLength = 1;nRMB_value = 0;if (!SendCommand()) return false;CheckGenericResponses();//parse poll responseint noteVal;char *currency;for (int i = 1; i < cmd->ResponseDataLength; ++i){switch (cmd->ResponseData[i]){// The unit has been reset since the last time a poll was sent.case SSP_POLL_RESET: break;// If the byte after is greater than 0 then the note is being held in// escrow. If it is zero then the note is still being read.case SSP_POLL_NOTE_READ:if (cmd->ResponseData[i + 1] > 0){noteVal = GetChannelValue(cmd->ResponseData[i + 1]);currency = GetChannelCurrency(cmd->ResponseData[i + 1]); }else{ }++i;break;// The note has been accepted and credit given, the following byte will// contain the channel number of the credited note.case SSP_POLL_CREDIT:noteVal = GetChannelValue(cmd->ResponseData[i + 1]);nRMB_value = noteVal;currency = GetChannelCurrency(cmd->ResponseData[i + 1]); ++m_NumStackedNotes;++i;break;// Validator is in the process of rejecting a note.case SSP_POLL_REJECTING:break;// A note has been rejected from the validator.case SSP_POLL_REJECTED: QueryRejection(); // This will output info about the reason for the rejectionbreak;// The validator is stacking a note.case SSP_POLL_STACKING: break;// The validator has completed stacking a note.case SSP_POLL_STACKED: break;// A note has become jammed in a place where it cannot be recovered.case SSP_POLL_SAFE_JAM: break;// A note has become jammed in a place where it may possibly be recovered.case SSP_POLL_UNSAFE_JAM: break;// The unit is disabled and will not accept notes.case SSP_POLL_DISABLED: break;// The validator has detected a fraud attempt.case SSP_POLL_FRAUD_ATTEMPT:noteVal = GetChannelValue(cmd->ResponseData[i + 1]);currency = GetChannelCurrency(cmd->ResponseData[i + 1]); ++i;break;// The cashbox of the unit is full and cannot stack any more notes.case SSP_POLL_STACKER_FULL: break;// A note has been rejected from the front of the validator on startup. This // may happen in the case of power loss while a note is reading.case SSP_POLL_NOTE_CLEARED_FROM_FRONT:noteVal = GetChannelValue(cmd->ResponseData[i + 1]);currency = GetChannelCurrency(cmd->ResponseData[i + 1]);++i;break;// A note has been stacked to the cashbox of the validator on startup. This // may happen in the case of power loss while a note is stacking.case SSP_POLL_NOTE_CLEARED_TO_CASHBOX:noteVal = GetChannelValue(cmd->ResponseData[i + 1]);currency = GetChannelCurrency(cmd->ResponseData[i + 1]); ++i;break;// The cashbox of the unit has been removed.case SSP_POLL_CASHBOX_REMOVED: break;// The cashbox of the unit has been replaced.case SSP_POLL_CASHBOX_REPLACED: break;case SSP_POLL_BARCODE_TICKET_VALIDATED: break;case SSP_POLL_BARCODE_TICKET_ACK: break;// The unit's top section has been opened (only applies to NV9/NV11 and NV200).// Protocol >= 6.case SSP_POLL_NOTE_PATH_OPEN: break;// This poll response indicates the unit is disabled as all the channels are// inhibited. Protocol >= 7.case SSP_POLL_CHANNEL_DISABLE: break;// If a poll response is detected and is not in this list default: break;}}return true;
}/* Non-Command functions */// This function calls the open com port function of the SSP library and sets up
// the command structure.
bool CValidator::OpenComPort(char portNum)
{if (OpenPort(cmd) == 0)return false;return true;
}/* Exception and Error Handling */// This is used for generic response error catching, it outputs the info in a
// meaningful way.
bool CValidator::CheckGenericResponses()
{if (cmd->ResponseData[0] == SSP_RESPONSE_CMD_OK)return true;else{ switch (cmd->ResponseData[0]){case SSP_RESPONSE_CMD_CANNOT_PROCESS:{//*m_Output << "Command response is CANNOT PROCESS COMMAND";if (cmd->ResponseDataLength > 1){// *m_Output << ", error code - 0x" << cmd->ResponseData[1];}//*m_Output << endl;return false;}case SSP_RESPONSE_CMD_FAIL:{//*m_Output << "Command response is FAIL" << endl;return false;}case SSP_RESPONSE_CMD_KEY_NOT_SET:{//*m_Output << "Command response is KEY NOT SET, renegotiate keys" << endl;return false;}case SSP_RESPONSE_CMD_PARAM_OUT_OF_RANGE:{//*m_Output << "Command response is PARAM OUT OF RANGE" << endl;return false;}case SSP_RESPONSE_CMD_SOFTWARE_ERROR:{//*m_Output << "Command response is SOFTWARE ERROR" << endl;return false;}case SSP_RESPONSE_CMD_UNKNOWN:{//*m_Output << "Command response is UNKNOWN" << endl;return false;}case SSP_RESPONSE_CMD_WRONG_PARAMS:{//*m_Output << "Command response is WRONG PARAMETERS" << endl;return false;}default:return false; }}
}// Takes a byte and converts it to a command name, returns a char string
char* CValidator::GetCommandName(char commandByte)
{switch (commandByte){case 0x4A: return "SET GENERATOR";case 0x4B: return "SET MODULUS";case 0x4C: return "REQUEST KEY EXCHANGE";case 0x01: return "RESET";case 0x02: return "SET INHIBITS";case 0x03: return "DISPLAY ON";case 0x04: return "DISPLAY OFF";case 0x05: return "SETUP REQUEST";case 0x06: return "HOST PROTOCOL VERSION";case 0x07: return "POLL";case 0x08: return "REJECT";case 0x09: return "DISABLE";case 0x0A: return "ENABLE";case 0x0B: return "PROGRAM FIRMWARE";case 0x0C: return "GET SERIAL NUMBER";case 0x0D: return "UNIT DATA";case 0x0E: return "CHANNEL VALUE DATA";case 0x0F: return "CHANNEL SECURITY DATA";case 0x10: return "CHANNEL RETEACH DATA";case 0x11: return "SYNC";case 0x12: return "UPDATE COIN ROUTE";case 0x13: return "DISPENSE";case 0x14: return "HOST SERIAL NUMBER REQUEST";case 0x15: return "SETUP REQUEST";case 0x17: return "LAST REJECT CODE";case 0x18: return "HOLD";case 0x19: return "ENABLE PROTOCOL VERSION EVENTS";case 0x23: return "GET BAR CODE READER CONFIGURATION";case 0x24: return "SET BAR CODE READER CONFIGURATION";case 0x25: return "GET BAR CODE INHIBIT";case 0x26: return "SET BAR CODE INHIBIT";case 0x27: return "GET BAR CODE DATA"; case 0x54: return "CONFIGURE BEZEL";case 0x56: return "POLL WITH ACK";case 0x57: return "EVENT ACK";case 0x3B: return "SET ROUTING";case 0x3C: return "GET ROUTING";case 0x33: return "PAYOUT AMOUNT";case 0x35: return "GET NOTE/COIN AMOUNT";case 0x34: return "SET NOTE/COIN AMOUNT";case 0x38: return "HALT PAYOUT";case 0x3D: return "FLOAT AMOUNT";case 0x3E: return "GET MINIMUM PAYOUT";case 0x40: return "SET COIN MECH INHIBITS";case 0x46: return "PAYOUT BY DENOMINATION";case 0x44: return "FLOAT BY DENOMINATION";case 0x47: return "SET COMMAND CALIBRATION";case 0x48: return "RUN COMMAND CALIBRATION";case 0x3F: return "EMPTY ALL";case 0x50: return "SET OPTIONS";case 0x51: return "GET OPTIONS";case 0x49: return "COIN MECH GLOBAL INHIBIT";case 0x52: return "SMART EMPTY";case 0x53: return "CASHBOX PAYOUT OPERATION DATA";case 0x5C: return "ENABLE PAYOUT DEVICE";case 0x5B: return "DISABLE PAYOUT DEVICE";case 0x58: return "GET NOTE COUNTERS";case 0x59: return "RESET NOTE COUNTERS";case 0x30: return "SET REFILL MODE";case 0x41: return "GET NOTE POSITIONS";case 0x42: return "PAYOUT NOTE";case 0x43: return "STACK NOTE";case 0x45: return "SET VALUE REPORTING TYPE";default: return "COMMAND NOT FOUND";}
}bool CValidator::SendCommand()
{// set the command nameinfo->CommandName = (unsigned char*)GetCommandName(cmd->CommandData[0]);// attempt to send the command using the libraryif (SSPSendCommand(cmd, info) == 0){// If the command failsClosePort(); // close the com port//*m_Output << "Failed to send command, port status: ";//*m_Output << (int)cmd->ResponseStatus << endl; return false;}return true;
}// This function sends a series of commands to the validator to initialise it for use.
// It opens the com port, negotiates keys for encryption, sets the protocol version,
// sets the inhibits and calls the setup request. After this function the validator is
// ready to be enabled and used.
bool CValidator::ConnectToValidator(const SSP_COMMAND& command, int protocolVersion, int attempts)
{// Set command structure data to the copy passed across// cmd is the internal command structure used by this class instancecmd->BaudRate = command.BaudRate;cmd->RetryLevel = command.RetryLevel;cmd->Timeout = command.Timeout;cmd->PortNumber = command.PortNumber;cmd->SSPAddress = command.SSPAddress;cmd->IgnoreError = command.IgnoreError;for (int i = 0; i < attempts; ++i){// Close port in case it was left openClosePort();// Open the com portif (!OpenComPort(cmd->PortNumber)){//*m_Output << "Failed to open port " << (int)cmd->PortNumber << endl;continue;}// Negotiate keys for encryptionif (!NegotiateKeys()){//*m_Output << "Failed on key negotiation..." << endl;continue;}// Set the protocol version to the value passed to this functionif (!SetProtocolVersion(protocolVersion)){//*m_Output << "Failed on setting protocol version..." << endl;continue;}// Set the inhibits (all uninhibited in this SDK)if (!SetInhibits()){//*m_Output << "Failed on setting inhibits..." << endl;continue;}// Call setup requestif (!SetupRequest()){//*m_Output << "Failed on setup request..." << endl;continue;}return true;}return false;
}
东方仙盟筑基期之灵钞鉴真秘术指南
在东方仙盟的筑基期,修仙者们为确保灵钞交易的公正与安全,探寻出一套借助 “鉴真灵匣(CValidator)” 施展灵钞鉴真及相关操控的秘术。此秘术依托 “灵库妙法(SSP)” 灵诀库,涵盖灵匣初始化、灵钞鉴真指令发送、加密密钥协商、设备信息获取等诸多关键环节。
鉴真灵匣构建
cpp
鉴真灵匣::鉴真灵匣(void)
{灵令 = new 灵匣指令();灵钥 = new 灵匣密钥(); 灵讯 = new 灵匣指令灵讯();// 凝炼灵库妙法凝炼灵库妙法();灵匣通道数量 = 0; 灵匣类型 = 0;堆叠灵钞数量 = 0;灵匣单元数据 = 0;
}
修仙者凝化 “鉴真灵匣” 时,会同时生成 “灵令”“灵钥”“灵讯” 等灵具,并启动 “凝炼灵库妙法”,初始化相关参数。
灵库妙法凝炼
cpp
bool 鉴真灵匣::凝炼灵库妙法()
{// 唤出灵库宝册灵库宝册名 = _T("ITLSSPProc.dll");灵库宝册实例 = 唤出灵库宝册(灵库宝册名);if (灵库宝册实例 != NULL){// 勾连灵诀之名// 开启灵窍通联开启灵窍通联 = (灵诀指针1)获取灵诀指针(灵库宝册实例, "OpenSSPComPortUSB");if (开启灵窍通联 == NULL){归还灵库宝册(灵库宝册实例);return false;}// 闭合灵窍通联闭合灵窍通联 = (灵诀指针2)获取灵诀指针(灵库宝册实例, "CloseSSPComPortUSB");if (闭合灵窍通联 == NULL){归还灵库宝册(灵库宝册实例);return false;}// 发送灵令至灵匣发送灵令 = (灵诀指针3)获取灵诀指针(灵库宝册实例, "SSPSendCommand");if (发送灵令 == NULL){归还灵库宝册(灵库宝册实例);return false;}// 凝化密钥灵晶凝化密钥灵晶 = (灵诀指针4)获取灵诀指针(灵库宝册实例, "InitiateSSPHostKeys");if (凝化密钥灵晶 == NULL){归还灵库宝册(灵库宝册实例);return false;}// 铸就加密灵钥铸就加密灵钥 = (灵诀指针5)获取灵诀指针(灵库宝册实例, "CreateSSPHostEncryptionKey");if (铸就加密灵钥 == NULL){归还灵库宝册(灵库宝册实例);return false;}}elsereturn false;return true;
}
此过程通过 “唤出灵库宝册” 加载灵库宝册,勾连各关键灵诀,若任一环节失败,则终止并 “归还灵库宝册”。
灵匣启用与停用
cpp
// 启用灵匣,接纳诸般灵令
bool 鉴真灵匣::启用鉴真灵匣()
{灵令->灵令数据[0] = 启用灵匣灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()) return false;// 核验灵讯回应if (核验通用灵讯回应()){ }return true;
}// 停用灵匣,阻绝多数灵令
bool 鉴真灵匣::停用鉴真灵匣()
{灵令->灵令数据[0] = 停用灵匣灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()) return false;// 核验灵讯回应if (核验通用灵讯回应()){}return true;
}
“启用鉴真灵匣” 与 “停用鉴真灵匣” 灵诀分别设置对应灵令,发送并核验回应,决定灵匣对灵令的接纳状态。
灵匣重置
cpp
// 重置灵匣,仿若重启
bool 鉴真灵匣::重置鉴真灵匣()
{灵令->灵令数据[0] = 重置灵匣灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()){return false;}// 核验灵讯回应if(核验通用灵讯回应()){ }return true;
}
“重置鉴真灵匣” 灵诀设定重置灵令,发送并核验回应,实现灵匣重启效果。
协议版本设定
cpp
// 设定灵匣协议版本
bool 鉴真灵匣::设定协议版本(灵纹字符 版本灵纹)
{灵令->灵令数据[0] = 设定协议版本灵令;灵令->灵令数据[1] = 版本灵纹;灵令->灵令数据长度 = 2;if (!发送灵令至灵匣()) return false;return true;
}
“设定协议版本” 灵诀依传入的 “版本灵纹” 设置协议版本灵令并发送。
灵钞拒钞缘由探查
cpp
// 探查灵钞拒钞缘由并输出灵讯
void 鉴真灵匣::探查拒钞缘由()
{灵令->灵令数据[0] = 探查拒钞缘由灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()) return;if (核验通用灵讯回应()){switch (灵令->回应数据[1]) {case 0x00: //*输出灵讯 << "灵钞接纳" << 灵境换行符; break;case 0x01: //*输出灵讯 << "灵钞长度有误" << 灵境换行符; break;case 0x02: //*输出灵讯 << "灵钞无效" << 灵境换行符; break;case 0x03: //*输出灵讯 << "灵钞无效" << 灵境换行符; break;case 0x04: //*输出灵讯 << "灵钞无效" << 灵境换行符; break;case 0x05: //*输出灵讯 << "灵钞无效" << 灵境换行符; break;case 0x06: //*输出灵讯 << "灵匣通道禁制" << 灵境换行符; break;case 0x07: //*输出灵讯 << "读钞时插入第二张灵钞" << 灵境换行符; break;case 0x08: //*输出灵讯 << "仙盟拒钞" << 灵境换行符; break;case 0x09: //*输出灵讯 << "灵钞无效" << 灵境换行符; break;case 0x0A: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x0B: //*输出灵讯 << "灵钞过长" << 灵境换行符; break;case 0x0C: //*输出灵讯 << "鉴真灵匣停用" << 灵境换行符; break;case 0x0D: //*输出灵讯 << "灵匣机制迟缓/停滞" << 灵境换行符; break;case 0x0E: //*输出灵讯 << "剪钞企图" << 灵境换行符; break;case 0x0F: //*输出灵讯 << "欺诈通道拒钞" << 灵境换行符; break;case 0x10: //*输出灵讯 << "无灵钞插入" << 灵境换行符; break;case 0x11: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x12: //*输出灵讯 << "灵钞扭曲检测" << 灵境换行符; break;case 0x13: //*输出灵讯 << "暂存超时" << 灵境换行符; break;case 0x14: //*输出灵讯 << "条码扫描失败" << 灵境换行符; break;case 0x15: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x16: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x17: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x18: //*输出灵讯 << "灵钞读取无效" << 灵境换行符; break;case 0x19: //*输出灵讯 << "灵钞宽度有误" << 灵境换行符; break;case 0x1A: //*输出灵讯 << "灵钞过短" << 灵境换行符; break;}}
}
“探查拒钞缘由” 灵诀发送探查灵令,依回应数据解析拒钞原因并输出灵讯。
加密密钥协商
cpp
// 协商灵匣与仙盟主机间的加密密钥
bool 鉴真灵匣::协商加密密钥()
{整数值; // 确保加密关闭灵令->加密状态 = 假;// 发送同步灵令灵令->灵令数据[0] = 同步灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()) return false;凝化密钥灵晶(灵钥, 灵令);// 发送生成器灵令灵令->灵令数据[0] = 发送生成器灵令;灵令->灵令数据长度 = 9;for (整数值 = 0; 整数值 < 8; ++整数值){灵令->灵令数据[整数值 + 1] = (灵纹字符)(灵钥->生成器 >> (8 * 整数值));}if (!发送灵令至灵匣()) return false;// 发送模数灵令灵令->灵令数据[0] = 发送模数灵令;灵令->灵令数据长度 = 9;for (整数值 = 0; 整数值 < 8; ++整数值){灵令->灵令数据[整数值 + 1] = (灵纹字符)(灵钥->模数 >> (8 * 整数值));}if (!发送灵令至灵匣()) return false;// 发送密钥交换灵令灵令->灵令数据[0] = 发送密钥交换灵令;灵令->灵令数据长度 = 9;for (整数值 = 0; 整数值 < 8; ++整数值){灵令->灵令数据[整数值 + 1] = (灵纹字符)(灵钥->主机交互值 >> (8 * 整数值));}if (!发送灵令至灵匣()) return false;灵钥->从机交互密钥 = 0;for (整数值 = 0; 整数值 < 8; ++整数值){灵钥->从机交互密钥 += (无符号长整数)灵令->回应数据[1 + 整数值] << (8 * 整数值);}铸就加密灵钥(灵钥);// 获取完整加密密钥灵令->密钥.固定密钥 = 0x0123456701234567;灵令->密钥.加密密钥 = 灵钥->主机密钥;灵令->加密状态 = 真; // 开启加密//*输出灵讯 << "协商密钥完成" << 灵境换行符;return true;
}
此灵诀按序发送同步、生成器、模数、密钥交换等灵令,借助 “凝化密钥灵晶” 和 “铸就加密灵钥” 灵诀完成加密密钥协商。
灵匣信息获取
cpp
// 获取灵匣信息
bool 鉴真灵匣::获取灵匣信息()
{ // 发送获取信息灵令灵令->灵令数据[0] = 获取灵匣信息灵令;灵令->灵令数据长度 = 1;if (!发送灵令至灵匣()) return false;// 核验灵讯回应if (核验通用灵讯回应()){// 输出获取信息灵讯// 灵匣类型//*输出灵讯 << "灵匣类型: ";灵匣类型 = 灵令->回应数据[1];switch (灵匣类型){case 0x00: //*输出灵讯 << "灵钞鉴真匣" << 灵境换行符; break;case 0x03: //*输出灵讯 << "灵晶储纳器" << 灵境换行符; break;case 0x06: //*输出灵讯 << "灵晶发放器" << 灵境换行符;break;case 0x07: //*输出灵讯 << "NV11 型灵匣" << 灵境换行符; break;}// 固件版本//*输出灵讯 << "固件版本: ";//*输出灵讯 << 灵令->回应数据[2] << 灵令->回应数据[3] << "." <<// 灵令->回应数据[4] << 灵令->回应数据[5] << 灵境换行符;// 通道设置// 固定数据结束索引值 = 12;灵匣通道数量 = 灵令->回应数据[索引值++];灵匣单元数据 = new 通道数据[灵匣通道数量];索引值 += 灵匣通道数量; // 跳过旧通道值索引值 += 灵匣通道数量; // 跳过通道安全级别索引值 += 3; // 跳过值乘数// 协议版本协议版本 = 灵令->回应数据[索引值++];//*输出灵讯 << "协议版本: " << (整数)协议版本 << 灵境换行符;// 设置通道数据// 灵钞币种//*输出灵讯 << "通道币种: ";for (整数值 = 0; 整数值 < 灵匣通道数量; ++整数值){灵匣单元数据[整数值].通道 = 整数值 + 1;for (整数值2 = 0; 整数值2 < 3; ++整数值2){灵匣单元数据[整数值].币种[整数值2] = 灵令->回应数据[索引值 + 整数值2];//*输出灵讯 << 灵匣单元数据[整数值].币种[整数值2];}索引值 += 3;//*输出灵讯 << " ";}//*输出灵讯 << 灵境换行符;// 灵钞面值//*输出灵讯 << "通道面值: ";整数值;for(整数值 = 0; 整数值 < 灵匣通道数量; ++整数值){for (整数值2 = 0; 整数值2 < 4; ++整数值2)灵匣单元数据[整数值].面值 += (整数)灵令->回应数据[索引值++] << (8*整数值2);//*输出灵讯 << 灵匣单元数据[整数值].面值 << " ";}//*输出灵讯 << 灵境换行符; }return true;
}
阿雪技术观
在科技发展浪潮中,我们不妨积极投身技术共享。不满足于做受益者,更要主动担当贡献者。无论是分享代码、撰写技术博客,还是参与开源项目维护改进,每一个微小举动都可能蕴含推动技术进步的巨大能量。东方仙盟是汇聚力量的天地,我们携手在此探索硅基生命,为科技进步添砖加瓦。
Hey folks, in this wild tech - driven world, why not dive headfirst into the whole tech - sharing scene? Don't just be the one reaping all the benefits; step up and be a contributor too. Whether you're tossing out your code snippets, hammering out some tech blogs, or getting your hands dirty with maintaining and sprucing up open - source projects, every little thing you do might just end up being a massive force that pushes tech forward. And guess what? The Eastern FairyAlliance is this awesome place where we all come together. We're gonna team up and explore the whole silicon - based life thing, and in the process, we'll be fueling the growth of technology