幽冥大陆(十六)纸币器BV20识别纸币——东方仙盟筑基期

纸币检测软件

幽冥大陆(十六)纸币器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 functions
    InitialiseLibrary();
    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 dll
	CString strLib = _T("ITLSSPProc.dll");
	HINSTANCE hInst = LoadLibrary(strLib);

	if (hInst != NULL)
	{
		// Link function names

		// Open the COM port
		OpenPort = (LPFNDLLFUNC1)GetProcAddress(hInst, "OpenSSPComPortUSB");
		if (OpenPort == NULL)
		{
			FreeLibrary(hInst);
			return false;
		}

		// Close the COM port
		ClosePort = (LPFNDLLFUNC2)GetProcAddress(hInst, "CloseSSPComPortUSB");
		if (ClosePort == NULL)
		{
			FreeLibrary(hInst);
			return false;
		}

		// Send a command to the unit
		SSPSendCommand = (LPFNDLLFUNC3)GetProcAddress(hInst, "SSPSendCommand");
		if (SSPSendCommand == NULL)
		{
			FreeLibrary(hInst);
			return false;
		}

		// Create the generator and modulus prime numbers for the key encryption
		InitiateSSPHostKeys = (LPFNDLLFUNC4)GetProcAddress(hInst, "InitiateSSPHostKeys");
		if (InitiateSSPHostKeys == NULL)
		{
			FreeLibrary(hInst);
			return false;
		}

		// Create the final encryption key
		CreateSSPHostEncryptionKey = (LPFNDLLFUNC5)GetProcAddress(hInst, "CreateSSPHostEncryptionKey");
		if (CreateSSPHostEncryptionKey == NULL)
		{
			FreeLibrary(hInst);
			return false;
		}
	}
	else
		return 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 response
	if (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 response
    if (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 response
    if(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 off
    cmd->EncryptionStatus = false;

    // send sync
    cmd->CommandData[0] = SSP_CMD_SYNC;
    cmd->CommandDataLength = 1;

    if (!SendCommand()) return false;

    InitiateSSPHostKeys(keys, cmd);

    // send generator
    cmd->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 modulus
    cmd->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 exchange
    cmd->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 key
    cmd->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 request
    cmd->CommandData[0] = SSP_CMD_SETUP_REQUEST;
    cmd->CommandDataLength = 1;

    if (!SendCommand()) return false;
	
	// check response
    if (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 data
		int index = 12;
		m_NumberOfChannels = cmd->ResponseData[index++];
		m_UnitData = new SChannelData[m_NumberOfChannels];

		index += m_NumberOfChannels; // Skip old channel values
		index += m_NumberOfChannels; // Skip channel security levels
		index += 3; // Skip value multiplier

		// Protocol version
		m_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 inhibits
    cmd->CommandData[0] = SSP_CMD_SET_INHIBITS;
    cmd->CommandData[1] = 0xFF;
    cmd->CommandData[2] = 0xFF;
    cmd->CommandDataLength = 3;

    if (!SendCommand()) return false;
    // check response
    if (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 poll
    cmd->CommandData[0] = SSP_CMD_POLL;
    cmd->CommandDataLength = 1;
	nRMB_value = 0;

    if (!SendCommand()) 
		return false;

	CheckGenericResponses();

    //parse poll response
    int 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 rejection
                break;
			// 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 name
	info->CommandName = (unsigned char*)GetCommandName(cmd->CommandData[0]);

    // attempt to send the command using the library
    if (SSPSendCommand(cmd, info) == 0)
    {
		// If the command fails
        ClosePort(); // 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 instance
	cmd->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 open
		ClosePort();

		// Open the com port
		if (!OpenComPort(cmd->PortNumber))
		{
			//*m_Output << "Failed to open port " << (int)cmd->PortNumber << endl;
			continue;
		}

		// Negotiate keys for encryption
		if (!NegotiateKeys())
		{
			//*m_Output << "Failed on key negotiation..." << endl;
			continue;
		}

		// Set the protocol version to the value passed to this function
		if (!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 request
		if (!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;
        }
    }
    else
        return 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

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
none
暂无评论...