Initial re-upload of spice2x-24-08-24
This commit is contained in:
85
reader/crypt.cpp
Normal file
85
reader/crypt.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <cstring>
|
||||
#include "crypt.h"
|
||||
|
||||
static uint16_t CRC_TABLE[256] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
|
||||
0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b,
|
||||
0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210,
|
||||
0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c,
|
||||
0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401,
|
||||
0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b,
|
||||
0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6,
|
||||
0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738,
|
||||
0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5,
|
||||
0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969,
|
||||
0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96,
|
||||
0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc,
|
||||
0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03,
|
||||
0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd,
|
||||
0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6,
|
||||
0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a,
|
||||
0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb,
|
||||
0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1,
|
||||
0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c,
|
||||
0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2,
|
||||
0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb,
|
||||
0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447,
|
||||
0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
|
||||
0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2,
|
||||
0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9,
|
||||
0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
|
||||
0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c,
|
||||
0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0,
|
||||
0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
|
||||
0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07,
|
||||
0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba,
|
||||
0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
|
||||
0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
Crypt::Crypt() {
|
||||
memset(this->keys, 0, sizeof(uint32_t) * 4);
|
||||
}
|
||||
|
||||
void Crypt::set_keys(uint32_t reader_key, uint32_t game_key) {
|
||||
this->keys[0] = reader_key ^ 0x5491333;
|
||||
this->keys[1] = game_key ^ 0x1F123BB5;
|
||||
this->keys[2] = reader_key ^ 0x159A55E5;
|
||||
this->keys[3] = game_key ^ 0x75BCD15;
|
||||
}
|
||||
|
||||
void Crypt::crypt(uint8_t *data, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
|
||||
// shift keys
|
||||
int low = (int) i & 3;
|
||||
if (low == 0) {
|
||||
uint32_t key_new = (this->keys[3] << 11) ^ this->keys[3];
|
||||
this->keys[3] = this->keys[2];
|
||||
this->keys[2] = this->keys[1];
|
||||
this->keys[1] = this->keys[0];
|
||||
this->keys[0] = ((((this->keys[0] >> 11) ^ key_new) >> 8) ^ key_new ^ this->keys[0]);
|
||||
}
|
||||
|
||||
// process data
|
||||
data[i] = (uint8_t) (this->keys[0] >> (((3 - low) << 3)) ^ data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Crypt::crc(const uint8_t *data, size_t len) {
|
||||
uint16_t crc = 0;
|
||||
for (size_t x = 0; x < len; x++) {
|
||||
crc = CRC_TABLE[data[x] ^ (uint8_t) (crc >> 8)] ^ (crc << 8);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
17
reader/crypt.h
Normal file
17
reader/crypt.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
class Crypt {
|
||||
private:
|
||||
uint32_t keys[4];
|
||||
|
||||
public:
|
||||
Crypt();
|
||||
|
||||
void set_keys(uint32_t reader_key, uint32_t game_key);
|
||||
|
||||
void crypt(uint8_t *data, size_t len);
|
||||
|
||||
uint16_t crc(const uint8_t *data, size_t len);
|
||||
};
|
||||
51
reader/message.cpp
Normal file
51
reader/message.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "message.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
Message::Message(std::vector<uint8_t> data) {
|
||||
this->data = std::move(data);
|
||||
}
|
||||
|
||||
uint8_t Message::chk_sum() {
|
||||
|
||||
// initial checksum of 0
|
||||
uint64_t chk = 0;
|
||||
|
||||
// add all bytes to checksum
|
||||
for (uint8_t c : this->data)
|
||||
chk += c;
|
||||
|
||||
// return checksum
|
||||
return (uint8_t) (chk & 0xFF);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Message::get_data_encoded() {
|
||||
|
||||
// check if already encoded
|
||||
if (data.size() <= encoded.size())
|
||||
return encoded;
|
||||
|
||||
// encode data
|
||||
for (uint8_t c : this->data) {
|
||||
if (c == 0xAA || c == 0xFF) {
|
||||
encoded.push_back(0xFF);
|
||||
encoded.push_back(~c);
|
||||
} else {
|
||||
encoded.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
// return data
|
||||
return this->encoded;
|
||||
}
|
||||
|
||||
void Message::print_debug() {
|
||||
std::ostringstream ss;
|
||||
for (uint8_t b : this->data)
|
||||
ss << " " << (void *) ((long long) b);
|
||||
ss << " / ";
|
||||
for (uint8_t b : this->get_data_encoded())
|
||||
ss << " " << (void *) ((long long) b);
|
||||
|
||||
log_info("reader", "{}", ss.str());
|
||||
}
|
||||
|
||||
24
reader/message.h
Normal file
24
reader/message.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
class Message {
|
||||
private:
|
||||
std::vector<uint8_t> encoded;
|
||||
protected:
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
inline void reencode() { encoded.clear(); }
|
||||
|
||||
public:
|
||||
explicit Message(std::vector<uint8_t> data);
|
||||
|
||||
uint8_t chk_sum();
|
||||
|
||||
std::vector<uint8_t> get_data_encoded();
|
||||
|
||||
inline std::vector<uint8_t> get_data() { return data; }
|
||||
|
||||
void print_debug();
|
||||
};
|
||||
474
reader/reader.cpp
Normal file
474
reader/reader.cpp
Normal file
@@ -0,0 +1,474 @@
|
||||
#include "reader.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include "util/logging.h"
|
||||
#include "misc/eamuse.h"
|
||||
#include "util/utils.h"
|
||||
#include "structuredmessage.h"
|
||||
|
||||
static std::vector<std::thread *> READER_THREADS;
|
||||
static bool READER_THREAD_RUNNING = false;
|
||||
|
||||
Reader::Reader(const std::string &port) : port(port) {
|
||||
|
||||
// open port using an NT path to support COM ports past 9
|
||||
std::filesystem::path serial_path = fmt::format("\\\\.\\{}", this->port);
|
||||
this->serial_handle = CreateFileW(
|
||||
serial_path.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
// check if valid
|
||||
this->valid = this->serial_handle != INVALID_HANDLE_VALUE;
|
||||
if (!this->valid) {
|
||||
auto last_error = get_last_error_string();
|
||||
|
||||
log_warning("reader", "{}: failed to open serial connection for reader: {}",
|
||||
this->port,
|
||||
last_error);
|
||||
}
|
||||
}
|
||||
|
||||
Reader::~Reader() {
|
||||
if (this->serial_handle) {
|
||||
CloseHandle(this->serial_handle);
|
||||
log_info("reader", "closed reader on {}", this->port);
|
||||
}
|
||||
}
|
||||
|
||||
bool Reader::is_valid() {
|
||||
return this->valid;
|
||||
}
|
||||
|
||||
bool Reader::initialize() {
|
||||
if (!this->set_comm_state(CBR_57600) || !this->wait_for_handshake())
|
||||
return false;
|
||||
|
||||
log_info("reader", "{}: card reader connected", this->port);
|
||||
|
||||
// assign reader ID
|
||||
std::vector<uint8_t> set_id_data;
|
||||
set_id_data.push_back(0x00);
|
||||
if (this->msg_write_read(StructuredMessage(
|
||||
0,
|
||||
this->reinitialized,
|
||||
READER_CMD_SET_ID,
|
||||
this->gen_msg_id(),
|
||||
set_id_data)).empty())
|
||||
return false;
|
||||
|
||||
// get version
|
||||
std::vector<Message> ret = this->msg_write_cmd_read(READER_CMD_VERSION);
|
||||
if (ret.empty())
|
||||
return false;
|
||||
|
||||
// print version info
|
||||
std::vector<uint8_t> version_data = ret[ret.size() - 1].get_data();
|
||||
std::ostringstream model;
|
||||
model << version_data[13] << version_data[14] << version_data[15] << version_data[16];
|
||||
log_info("reader", "{}: card reader model: {}", this->port, model.str());
|
||||
std::ostringstream date;
|
||||
date << (const char *) &version_data[17];
|
||||
log_info("reader", "{}: card reader date: {}", this->port, date.str());
|
||||
std::ostringstream clock;
|
||||
clock << (const char *) &version_data[33];
|
||||
log_info("reader", "{}: card reader clock: {}", this->port, clock.str());
|
||||
|
||||
// init 2
|
||||
if (this->msg_write_cmd_read(READER_CMD_INIT2).empty())
|
||||
return false;
|
||||
|
||||
// reinitialize
|
||||
this->reinitialized = 1;
|
||||
std::vector<uint8_t> reinitialize_data;
|
||||
reinitialize_data.push_back(0x00);
|
||||
if (this->msg_write_cmd_read(READER_CMD_REINITIALIZE, reinitialize_data).empty())
|
||||
return false;
|
||||
|
||||
log_info("reader", "{}: card reader init done", this->port);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::init_crypt() {
|
||||
|
||||
// generate game key
|
||||
std::vector<uint8_t> gk;
|
||||
for (int i = 0; i < 4; i++)
|
||||
gk.push_back((uint8_t) (rand() % 256));
|
||||
|
||||
// reader crypt init
|
||||
std::vector<Message> ret = this->msg_write_cmd_read(READER_CMD_KEY_EXCHANGE, gk);
|
||||
if (ret.empty())
|
||||
return false;
|
||||
|
||||
// validate message
|
||||
Message msg = ret[ret.size() - 1];
|
||||
std::vector<uint8_t> md = msg.get_data();
|
||||
if (md.size() != 9)
|
||||
return false;
|
||||
|
||||
// convert keys to int32
|
||||
uint32_t game_key = gk[0] << 24 | gk[1] << 16 | gk[2] << 8 | gk[3];
|
||||
uint32_t reader_key = md[5] << 24 | md[6] << 16 | md[7] << 8 | md[8];
|
||||
log_info("reader", "{}: reader crypt client key: {}", this->port, bin2hex((char *) &gk[0], 4));
|
||||
log_info("reader", "{}: reader crypt reader key: {}", this->port, bin2hex((char *) &md[5], 4));
|
||||
|
||||
// set crypt keys
|
||||
this->crypt.set_keys(reader_key, game_key);
|
||||
|
||||
// crypt done
|
||||
log_info("reader", "{}: reader crypt init done", this->port);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::read_card() {
|
||||
|
||||
// read card UID
|
||||
std::vector<uint8_t> status_ruid_data;
|
||||
status_ruid_data.push_back(0x00);
|
||||
status_ruid_data.push_back(0x03);
|
||||
status_ruid_data.push_back(0xFF);
|
||||
status_ruid_data.push_back(0xFF);
|
||||
if (this->msg_write_cmd_read(READER_CMD_RFID_READ_UID, status_ruid_data).empty()) {
|
||||
this->valid = false;
|
||||
return false;
|
||||
}
|
||||
Sleep(200);
|
||||
|
||||
// get reader status
|
||||
std::vector<uint8_t> status_req_data;
|
||||
status_req_data.push_back(0x10);
|
||||
std::vector<Message> ret = this->msg_write_cmd_read(READER_CMD_GET_STATUS_ENC, status_req_data);
|
||||
if (ret.empty()) {
|
||||
this->valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// get data
|
||||
Message status_msg = ret[ret.size() - 1];
|
||||
std::vector<uint8_t> status_data = status_msg.get_data();
|
||||
if (status_data.size() != 23)
|
||||
return false;
|
||||
|
||||
// decrypt data
|
||||
this->crypt.crypt(&status_data[5], 18);
|
||||
|
||||
// check CRC
|
||||
uint16_t crc_old = status_data[21] << 8 | status_data[22];
|
||||
uint16_t crc_new = this->crypt.crc(&status_data[5], 16);
|
||||
if (crc_old != crc_new) {
|
||||
this->valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// get keypad state
|
||||
this->keypad_started = status_data[16];
|
||||
this->keypad_state = status_data[19] << 8 | status_data[20];
|
||||
|
||||
// check for card input
|
||||
if (status_data[5] == 2) {
|
||||
memcpy(this->card_uid, &status_data[7], 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Reader::set_comm_state(DWORD BaudRate) {
|
||||
|
||||
// settings
|
||||
DCB serial_params{};
|
||||
serial_params.DCBlength = sizeof(serial_params);
|
||||
if (!GetCommState(this->serial_handle, &serial_params)) {
|
||||
log_warning("reader", "{}: unable to get COM port state: 0x{:x}", this->port, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
serial_params.BaudRate = BaudRate;
|
||||
serial_params.ByteSize = 8;
|
||||
serial_params.StopBits = ONESTOPBIT;
|
||||
serial_params.Parity = NOPARITY;
|
||||
if (!SetCommState(this->serial_handle, &serial_params)) {
|
||||
log_warning("reader", "{}: unable to set COM port state: 0x{:x}", this->port, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// timeouts
|
||||
COMMTIMEOUTS timeouts{};
|
||||
timeouts.ReadIntervalTimeout = 30;
|
||||
timeouts.ReadTotalTimeoutConstant = 30;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 5;
|
||||
timeouts.WriteTotalTimeoutConstant = 30;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 5;
|
||||
if (!SetCommTimeouts(this->serial_handle, &timeouts)) {
|
||||
log_warning("reader", "{}: unable to set COM port timeouts: 0x{:x}", this->port, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Reader::wait_for_handshake() {
|
||||
|
||||
// baud rates
|
||||
DWORD baud_rates[] = { CBR_57600, CBR_38400, CBR_19200, CBR_9600 };
|
||||
|
||||
// variables
|
||||
DWORD bytes_written = 0;
|
||||
DWORD bytes_read = 0;
|
||||
uint8_t read_buffer[565];
|
||||
|
||||
// generate handshake buffer
|
||||
uint8_t handshake_buffer[565];
|
||||
memset(handshake_buffer, 0, 525);
|
||||
memset(handshake_buffer + 525, 0xAA, 40);
|
||||
|
||||
// try all the baud rates
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
|
||||
this->set_comm_state(baud_rates[i]);
|
||||
|
||||
// handshake loop
|
||||
for (size_t n = 0; n < 10; n++) {
|
||||
|
||||
// write handshake
|
||||
if (!WriteFile(
|
||||
this->serial_handle,
|
||||
handshake_buffer,
|
||||
sizeof(handshake_buffer),
|
||||
&bytes_written,
|
||||
nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// read handshake
|
||||
bytes_read = 0;
|
||||
if (!ReadFile(
|
||||
this->serial_handle,
|
||||
read_buffer,
|
||||
sizeof(read_buffer),
|
||||
&bytes_read,
|
||||
nullptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// check handshake
|
||||
if (bytes_read > 0 && read_buffer[bytes_read - 1] == 0xAA) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// sleep
|
||||
Sleep(50);
|
||||
}
|
||||
|
||||
log_warning("reader", "{}: no handshake received for {} baud", this->port, baud_rates[i]);
|
||||
}
|
||||
|
||||
// no handshake on all baud rates
|
||||
log_warning("reader", "{}: no handshake received for any attempted baud rate", this->port);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Reader::msg_write(Message msg) {
|
||||
|
||||
// get message data
|
||||
std::vector<uint8_t> msg_encoded = msg.get_data_encoded();
|
||||
uint8_t chk_sum = msg.chk_sum();
|
||||
|
||||
// create write buffer
|
||||
uint8_t write_buffer[512];
|
||||
DWORD write_buffer_len = 0;
|
||||
|
||||
// fill write buffer
|
||||
write_buffer[write_buffer_len++] = 0xAA;
|
||||
for (const uint8_t c : msg_encoded) {
|
||||
write_buffer[write_buffer_len++] = c;
|
||||
}
|
||||
|
||||
// write checksum
|
||||
if (chk_sum == 0xAA || chk_sum == 0xFF) {
|
||||
write_buffer[write_buffer_len++] = 0xFF;
|
||||
write_buffer[write_buffer_len++] = ~chk_sum;
|
||||
} else {
|
||||
write_buffer[write_buffer_len++] = chk_sum;
|
||||
}
|
||||
|
||||
// write buffer
|
||||
DWORD bytes_written = 0;
|
||||
return WriteFile(this->serial_handle,
|
||||
write_buffer,
|
||||
write_buffer_len,
|
||||
&bytes_written,
|
||||
nullptr) != 0;
|
||||
}
|
||||
|
||||
std::vector<Message> Reader::msg_write_read(Message msg) {
|
||||
this->msg_write(msg);
|
||||
return this->msg_read();
|
||||
}
|
||||
|
||||
std::vector<Message> Reader::msg_write_cmd_read(uint8_t cmd) {
|
||||
return this->msg_write_cmd_read(cmd, std::vector<uint8_t>());
|
||||
}
|
||||
|
||||
std::vector<Message> Reader::msg_write_cmd_read(uint8_t cmd, std::vector<uint8_t> data) {
|
||||
this->msg_write(StructuredMessage(
|
||||
this->node,
|
||||
this->reinitialized,
|
||||
cmd,
|
||||
this->gen_msg_id(),
|
||||
data
|
||||
));
|
||||
return this->msg_read();
|
||||
}
|
||||
|
||||
std::vector<Message> Reader::msg_read() {
|
||||
|
||||
// create buffer
|
||||
std::vector<Message> msgs;
|
||||
uint8_t read_buffer[4096];
|
||||
DWORD read_buffer_len = 0;
|
||||
|
||||
// read to buffer
|
||||
if (ReadFile(
|
||||
this->serial_handle,
|
||||
read_buffer,
|
||||
sizeof(read_buffer),
|
||||
&read_buffer_len,
|
||||
nullptr) && read_buffer_len > 0)
|
||||
{
|
||||
std::vector<uint8_t> msg_data;
|
||||
size_t msg_remaining = 0;
|
||||
bool escape = false;
|
||||
for (size_t i = 0; i < read_buffer_len; i++) {
|
||||
uint8_t b = read_buffer[i];
|
||||
if (msg_remaining > 0) {
|
||||
|
||||
// add msg data length
|
||||
if (msg_data.size() < 6 && msg_remaining == 1)
|
||||
msg_remaining += msg_data[4];
|
||||
|
||||
if (escape) { // escaped byte
|
||||
b = ~b;
|
||||
msg_data.push_back(b);
|
||||
msg_remaining--;
|
||||
escape = false;
|
||||
} else if (b == 0xAA) { // message start
|
||||
msg_remaining = 6;
|
||||
msg_data.clear();
|
||||
} else if (b == 0xFF) { // escape
|
||||
escape = true;
|
||||
} else { // normal data
|
||||
msg_data.push_back(b);
|
||||
msg_remaining--;
|
||||
}
|
||||
} else if (b == 0xAA) { // message start
|
||||
msg_remaining = 6;
|
||||
msg_data.clear();
|
||||
}
|
||||
|
||||
if (msg_remaining == 0 && msg_data.size() >= 6) { // message done
|
||||
std::vector<uint8_t> msg_ext_data;
|
||||
for (size_t n = 0; n < msg_data[4] && n < msg_data.size() - 6; n++) {
|
||||
msg_ext_data.push_back(msg_data[5 + n]);
|
||||
}
|
||||
StructuredMessage msg(
|
||||
msg_data[0],
|
||||
msg_data[1],
|
||||
msg_data[2],
|
||||
msg_data[3],
|
||||
msg_ext_data
|
||||
);
|
||||
if (msg.chk_sum() == msg_data[msg_data.size() - 1]) {
|
||||
msgs.push_back(msg);
|
||||
}
|
||||
msg_data.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return message buffer
|
||||
return msgs;
|
||||
}
|
||||
|
||||
void start_reader_thread(const std::string &port, int id) {
|
||||
READER_THREAD_RUNNING = true;
|
||||
READER_THREADS.push_back(new std::thread([port, id]() {
|
||||
log_info("reader", "{}: starting reader thread", port);
|
||||
|
||||
while (READER_THREAD_RUNNING) {
|
||||
|
||||
// create reader
|
||||
Reader reader(port);
|
||||
|
||||
// check if serial handle is still valid
|
||||
if (!reader.is_valid()) {
|
||||
log_warning("reader", "{}: serial handle no longer valid", port);
|
||||
} else if (!reader.initialize()) {
|
||||
log_warning("reader", "{}: unable to initialize reader", port);
|
||||
} else if (reader.init_crypt()) {
|
||||
|
||||
// reader loop
|
||||
while (READER_THREAD_RUNNING && reader.is_valid()) {
|
||||
bool did_read_card = reader.read_card();
|
||||
|
||||
if (did_read_card) {
|
||||
const uint8_t *uid = reader.get_card_uid();
|
||||
log_info("reader", "{}: reader input: {}", port, bin2hex(uid, 8));
|
||||
if (id >= 0) {
|
||||
eamuse_card_insert(id, uid);
|
||||
} else {
|
||||
eamuse_card_insert(GetKeyState(VK_NUMLOCK) & 1, uid);
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.keypad_started > 0) {
|
||||
if (id >= 0) {
|
||||
eamuse_set_keypad_overrides_reader(id, reader.keypad_state);
|
||||
} else {
|
||||
auto unit = GetKeyState(VK_NUMLOCK) & 1;
|
||||
eamuse_set_keypad_overrides_reader(unit, reader.keypad_state);
|
||||
}
|
||||
}
|
||||
|
||||
if (did_read_card) {
|
||||
Sleep(2500);
|
||||
}
|
||||
|
||||
Sleep(20);
|
||||
}
|
||||
}
|
||||
|
||||
// sleep between reader connection retries
|
||||
if (READER_THREAD_RUNNING)
|
||||
Sleep(5000);
|
||||
}
|
||||
}));
|
||||
|
||||
// wait for thread to start
|
||||
Sleep(10);
|
||||
}
|
||||
|
||||
void stop_reader_thread() {
|
||||
|
||||
// stop threads
|
||||
if (READER_THREAD_RUNNING) {
|
||||
READER_THREAD_RUNNING = false;
|
||||
}
|
||||
|
||||
// kill threads
|
||||
while (!READER_THREADS.empty()) {
|
||||
delete READER_THREADS.back();
|
||||
READER_THREADS.pop_back();
|
||||
}
|
||||
}
|
||||
72
reader/reader.h
Normal file
72
reader/reader.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "crypt.h"
|
||||
#include "message.h"
|
||||
|
||||
enum reader_cmd {
|
||||
READER_CMD_SET_ID = 0x01,
|
||||
READER_CMD_VERSION = 0x02,
|
||||
READER_CMD_INIT2 = 0x03,
|
||||
READER_CMD_REINITIALIZE = 0x30,
|
||||
READER_CMD_READ_CARD_UID = 0x31,
|
||||
READER_CMD_GET_STATUS = 0x34,
|
||||
READER_CMD_SET_ACTION = 0x35,
|
||||
READER_CMD_SLEEP_MODE = 0x3A,
|
||||
READER_CMD_KEY_EXCHANGE = 0x60,
|
||||
READER_CMD_RFID_READ_UID = 0x61,
|
||||
READER_CMD_GET_STATUS_ENC = 0x64,
|
||||
};
|
||||
|
||||
enum reader_action {
|
||||
READER_ACTION_BLOCK = 0x00,
|
||||
READER_ACTION_ACCEPT_CARD = 0x11,
|
||||
READER_ACTION_EJECT_CARD = 0x12,
|
||||
};
|
||||
|
||||
class Reader {
|
||||
|
||||
public:
|
||||
uint8_t keypad_started = 0;
|
||||
uint16_t keypad_state = 0;
|
||||
|
||||
explicit Reader(const std::string &port);
|
||||
|
||||
~Reader();
|
||||
|
||||
inline const uint8_t *get_card_uid() {
|
||||
return this->card_uid;
|
||||
}
|
||||
|
||||
bool is_valid();
|
||||
bool initialize();
|
||||
bool init_crypt();
|
||||
|
||||
bool read_card();
|
||||
|
||||
private:
|
||||
const std::string port;
|
||||
HANDLE serial_handle;
|
||||
bool valid;
|
||||
uint8_t card_uid[8];
|
||||
uint8_t reinitialized = 0, node = 1;
|
||||
uint8_t cur_msg_id = 0;
|
||||
Crypt crypt;
|
||||
|
||||
inline uint8_t gen_msg_id() { return ++cur_msg_id; }
|
||||
|
||||
bool set_comm_state(DWORD BaudRate);
|
||||
bool wait_for_handshake();
|
||||
bool msg_write(Message msg);
|
||||
|
||||
std::vector<Message> msg_write_read(Message msg);
|
||||
std::vector<Message> msg_write_cmd_read(uint8_t cmd);
|
||||
std::vector<Message> msg_write_cmd_read(uint8_t cmd, std::vector<uint8_t> data);
|
||||
std::vector<Message> msg_read();
|
||||
};
|
||||
|
||||
void start_reader_thread(const std::string &serial_str, int id);
|
||||
void stop_reader_thread();
|
||||
14
reader/structuredmessage.cpp
Normal file
14
reader/structuredmessage.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "structuredmessage.h"
|
||||
|
||||
StructuredMessage::StructuredMessage(uint8_t node, uint8_t param, uint8_t cmd,
|
||||
uint8_t packet_id, std::vector<uint8_t> request_data)
|
||||
: Message(std::vector<uint8_t>()) {
|
||||
this->data.clear();
|
||||
this->data.push_back(node);
|
||||
this->data.push_back(param);
|
||||
this->data.push_back(cmd);
|
||||
this->data.push_back(packet_id);
|
||||
this->data.push_back((uint8_t) request_data.size());
|
||||
this->data.insert(this->data.end(), std::begin(request_data), std::end(request_data));
|
||||
this->reencode();
|
||||
}
|
||||
9
reader/structuredmessage.h
Normal file
9
reader/structuredmessage.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "message.h"
|
||||
|
||||
class StructuredMessage : public Message {
|
||||
public:
|
||||
StructuredMessage(uint8_t node, uint8_t param, uint8_t cmd,
|
||||
uint8_t packet_id, std::vector<uint8_t> request_data);
|
||||
};
|
||||
Reference in New Issue
Block a user