partial : Cleaned code a bit, prepping for reading Mifare tags
Added two new options in settings : - One to not error out if a reader is missing - One to force using a reader using it's name.
This commit is contained in:
parent
d794acb7b7
commit
3987e35b3d
207
src/aimeio.c
207
src/aimeio.c
@ -1,41 +1,12 @@
|
|||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "aimeio.h"
|
#include "aimeio.h"
|
||||||
#include "scard/scard.h"
|
#include "scard/scard.h"
|
||||||
|
|
||||||
char module[] = "CardReader";
|
|
||||||
|
|
||||||
// Reader Thread
|
// Reader Thread
|
||||||
static bool READER_RUNNER_INITIALIZED = false;
|
|
||||||
static HANDLE READER_POLL_THREAD;
|
static HANDLE READER_POLL_THREAD;
|
||||||
static bool READER_POLL_STOP_FLAG;
|
static bool READER_POLL_STOP_FLAG;
|
||||||
|
|
||||||
static bool polling = false;
|
|
||||||
static bool HasCard = false;
|
|
||||||
uint8_t UID[8] = {0};
|
|
||||||
|
|
||||||
struct aime_io_config
|
|
||||||
{
|
|
||||||
bool debug;
|
|
||||||
wchar_t aime_path[MAX_PATH];
|
|
||||||
wchar_t felica_path[MAX_PATH];
|
|
||||||
bool felica_gen;
|
|
||||||
uint8_t vk_scan;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct aime_io_config aime_io_cfg;
|
static struct aime_io_config aime_io_cfg;
|
||||||
static uint8_t aime_io_aime_id[10];
|
static struct card_data card_data;
|
||||||
static uint8_t aime_io_felica_id[8];
|
|
||||||
static bool aime_io_aime_id_present;
|
|
||||||
static bool aime_io_felica_id_present;
|
|
||||||
|
|
||||||
#pragma region CONFIG
|
#pragma region CONFIG
|
||||||
static void aime_io_config_read(struct aime_io_config *cfg, const wchar_t *filename)
|
static void aime_io_config_read(struct aime_io_config *cfg, const wchar_t *filename)
|
||||||
@ -65,10 +36,18 @@ static void aime_io_config_read(struct aime_io_config *cfg, const wchar_t *filen
|
|||||||
_countof(cfg->felica_path),
|
_countof(cfg->felica_path),
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
cfg->felica_gen = GetPrivateProfileIntW(
|
GetPrivateProfileStringW(
|
||||||
L"aimeio",
|
L"aimeio",
|
||||||
L"felicaGen",
|
L"readerName",
|
||||||
1,
|
L"",
|
||||||
|
cfg->reader_name,
|
||||||
|
_countof(cfg->reader_name),
|
||||||
|
filename);
|
||||||
|
|
||||||
|
cfg->reader_optional = GetPrivateProfileIntW(
|
||||||
|
L"aimeio",
|
||||||
|
L"readerOptional",
|
||||||
|
0,
|
||||||
filename);
|
filename);
|
||||||
|
|
||||||
cfg->vk_scan = GetPrivateProfileIntW(
|
cfg->vk_scan = GetPrivateProfileIntW(
|
||||||
@ -104,7 +83,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t
|
|||||||
if (c == EOF)
|
if (c == EOF)
|
||||||
{
|
{
|
||||||
// If the end of the file is reached before the desired line, print an error
|
// If the end of the file is reached before the desired line, print an error
|
||||||
printf("%s: %S: Error: Line %d does not exist\n", module, path, LineToRead);
|
printf("aime_io_read_id_file: %S: Error: Line %d does not exist\n", path, LineToRead);
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -125,7 +104,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t
|
|||||||
|
|
||||||
if (r != 1)
|
if (r != 1)
|
||||||
{
|
{
|
||||||
printf("%s: %S: Error parsing line %d\n", module, path, LineToRead);
|
printf("aime_io_read_id_file: %S: Error parsing line %d\n", path, LineToRead);
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -136,7 +115,7 @@ static HRESULT aime_io_read_id_file(const wchar_t *path, uint8_t *bytes, size_t
|
|||||||
// Check if the line is not nbytes long
|
// Check if the line is not nbytes long
|
||||||
if (fgetc(f) != '\n' && !feof(f))
|
if (fgetc(f) != '\n' && !feof(f))
|
||||||
{
|
{
|
||||||
printf("%s: %S: Error: Line %d is not %zu bytes long\n", module, path, LineToRead, nbytes);
|
printf("aime_io_read_id_file: %S: Error: Line %d is not %zu bytes long\n", path, LineToRead, nbytes);
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -151,43 +130,6 @@ end:
|
|||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT aime_io_generate_felica(const wchar_t *path, uint8_t *bytes, size_t nbytes)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
assert(path != NULL);
|
|
||||||
assert(bytes != NULL);
|
|
||||||
assert(nbytes > 0);
|
|
||||||
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
for (i = 0; i < nbytes; i++)
|
|
||||||
bytes[i] = rand();
|
|
||||||
|
|
||||||
/* FeliCa IDm values should have a 0 in their high nibble. I think. */
|
|
||||||
bytes[0] &= 0x0F;
|
|
||||||
|
|
||||||
f = _wfopen(path, L"w");
|
|
||||||
|
|
||||||
if (f == NULL) // If we somehow can't create the file, we error out.
|
|
||||||
{
|
|
||||||
printf("%s: %S: fopen failed: %i\n", module, path, (int)errno);
|
|
||||||
return E_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nbytes; i++)
|
|
||||||
fprintf(f, "%02X", bytes[i]);
|
|
||||||
|
|
||||||
fprintf(f, "\n");
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
printf("%s: Generated random FeliCa ID\n", module);
|
|
||||||
|
|
||||||
return S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region READER SPECIFIC
|
#pragma region READER SPECIFIC
|
||||||
@ -197,20 +139,8 @@ static unsigned int __stdcall reader_poll_thread_proc(void *ctx)
|
|||||||
printf("DEBUG: reader_poll_thread_proc(). \r\n");
|
printf("DEBUG: reader_poll_thread_proc(). \r\n");
|
||||||
while (!READER_POLL_STOP_FLAG)
|
while (!READER_POLL_STOP_FLAG)
|
||||||
{
|
{
|
||||||
if (!HasCard && polling)
|
if (card_data.card_type != 0) // Halting polling once a card is found, waiting for the game to read it's value.
|
||||||
{
|
scard_poll(&card_data);
|
||||||
uint8_t _UID[8] = {0};
|
|
||||||
scard_update(_UID);
|
|
||||||
|
|
||||||
if (_UID[0] > 0) // If a card was read, format it properly and set HasCard to true so the game can insert it on next frame.
|
|
||||||
{
|
|
||||||
printf("%s: Read card %02X%02X%02X%02X%02X%02X%02X%02X\n", module, _UID[0], _UID[1], _UID[2], _UID[3], _UID[4], _UID[5], _UID[6], _UID[7]);
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
UID[i] = _UID[i];
|
|
||||||
|
|
||||||
HasCard = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -233,26 +163,26 @@ HRESULT aime_io_init(void)
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
freopen_s(&fp, "CONOUT$", "w", stdout); // only when we allocate a console, we need to redirect stdout
|
freopen_s(&fp, "CONOUT$", "w", stdout); // only when we allocate a console, we need to redirect stdout
|
||||||
|
|
||||||
|
memset(&card_data, 0, sizeof(card_data)); // Init card_data structure
|
||||||
|
|
||||||
// We then read the segatools config file to get settings.
|
// We then read the segatools config file to get settings.
|
||||||
aime_io_config_read(&aime_io_cfg, L".\\segatools.ini");
|
aime_io_config_read(&aime_io_cfg, L".\\segatools.ini");
|
||||||
|
|
||||||
if (aime_io_cfg.debug)
|
|
||||||
printf("DEBUG: aime_io_init(). \r\n");
|
|
||||||
|
|
||||||
// Find and initialize reader(s)
|
// Find and initialize reader(s)
|
||||||
if (!READER_RUNNER_INITIALIZED)
|
printf("aime_io_init: Initializing SmartCard\n");
|
||||||
|
if (!scard_init(aime_io_cfg))
|
||||||
{
|
{
|
||||||
READER_RUNNER_INITIALIZED = true;
|
// If we couldn't init reader, error out.
|
||||||
printf("%s: Initializing SmartCard\n", module);
|
printf("aime_io_init: Couldn't init SmartCard\n");
|
||||||
|
if (!aime_io_cfg.reader_optional)
|
||||||
if (!scard_init())
|
|
||||||
{
|
|
||||||
printf("%s: Couldn't init SmartCard\n", module);
|
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
|
||||||
|
// If however the readerOptional flag is set to 1 in segatools.ini, continue with keyboard only.
|
||||||
|
printf("aime_io_init: Reader is optional, using keyboard only !\n");
|
||||||
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: Starting reader thread.\n", module);
|
printf("aime_io_init: Starting reader thread.\n");
|
||||||
|
|
||||||
// Start reader thread
|
// Start reader thread
|
||||||
READER_POLL_STOP_FLAG = false;
|
READER_POLL_STOP_FLAG = false;
|
||||||
@ -275,8 +205,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
|
|||||||
if (unit_no != 0)
|
if (unit_no != 0)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
polling = true;
|
|
||||||
|
|
||||||
bool sense;
|
bool sense;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
@ -284,8 +212,6 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
|
|||||||
sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
|
sense = GetAsyncKeyState(aime_io_cfg.vk_scan) & 0x8000;
|
||||||
if (!sense)
|
if (!sense)
|
||||||
{
|
{
|
||||||
aime_io_aime_id_present = false;
|
|
||||||
aime_io_felica_id_present = false;
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,48 +227,33 @@ HRESULT aime_io_nfc_poll(uint8_t unit_no)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: Attempting to read card %d from file. \r\n", module, card);
|
printf("aime_io_nfc_poll: Attempting to read card %d from file. \r\n", card);
|
||||||
|
|
||||||
// Try AiMe IC
|
// Try AiMe IC
|
||||||
hr = aime_io_read_id_file(
|
hr = aime_io_read_id_file(
|
||||||
aime_io_cfg.aime_path,
|
aime_io_cfg.aime_path,
|
||||||
aime_io_aime_id,
|
card_data.card_id,
|
||||||
sizeof(aime_io_aime_id),
|
10,
|
||||||
card);
|
card);
|
||||||
|
|
||||||
if (SUCCEEDED(hr) && hr != S_FALSE)
|
if (SUCCEEDED(hr) && hr != S_FALSE)
|
||||||
{
|
{
|
||||||
aime_io_aime_id_present = true;
|
card_data.card_type = Mifare;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try FeliCa IC
|
// Try FeliCa IC
|
||||||
hr = aime_io_read_id_file(
|
hr = aime_io_read_id_file(
|
||||||
aime_io_cfg.felica_path,
|
aime_io_cfg.felica_path,
|
||||||
aime_io_felica_id,
|
card_data.card_id,
|
||||||
sizeof(aime_io_felica_id),
|
8,
|
||||||
card);
|
card);
|
||||||
|
|
||||||
if (SUCCEEDED(hr) && hr != S_FALSE)
|
if (SUCCEEDED(hr) && hr != S_FALSE)
|
||||||
{
|
{
|
||||||
aime_io_felica_id_present = true;
|
card_data.card_type = FeliCa;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try generating FeliCa IC (if enabled)
|
|
||||||
if (aime_io_cfg.felica_gen)
|
|
||||||
{
|
|
||||||
hr = aime_io_generate_felica(
|
|
||||||
aime_io_cfg.felica_path,
|
|
||||||
aime_io_felica_id,
|
|
||||||
sizeof(aime_io_felica_id));
|
|
||||||
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
aime_io_felica_id_present = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,18 +263,17 @@ HRESULT aime_io_nfc_get_aime_id(uint8_t unit_no, uint8_t *luid, size_t luid_size
|
|||||||
printf("DEBUG: aime_io_nfc_get_aime_id(unit_no : %d). \r\n", unit_no);
|
printf("DEBUG: aime_io_nfc_get_aime_id(unit_no : %d). \r\n", unit_no);
|
||||||
|
|
||||||
assert(luid != NULL);
|
assert(luid != NULL);
|
||||||
assert(luid_size == sizeof(aime_io_aime_id));
|
assert(luid_size == 10);
|
||||||
|
|
||||||
if (unit_no != 0)
|
if (unit_no != 0)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
if (aime_io_aime_id_present)
|
if (card_data.card_type == Mifare)
|
||||||
{
|
{
|
||||||
memcpy(luid, aime_io_aime_id, luid_size);
|
memcpy(luid, card_data.card_id, luid_size);
|
||||||
printf("%s: Read Aime card from file with uid ", module);
|
printf("aime_io_nfc_get_aime_id: Read Aime card from file with uid %02X%02X %02X%02X %02X%02X %02X%02X %02X%02X\r\n", card_data.card_id[0], card_data.card_id[1], card_data.card_id[2], card_data.card_id[3], card_data.card_id[4], card_data.card_id[5], card_data.card_id[6], card_data.card_id[7], card_data.card_id[8], card_data.card_id[9]);
|
||||||
for (int i = 0; i < 10; i++)
|
|
||||||
printf("%02x ", aime_io_aime_id[i]);
|
memset(&card_data, 0, sizeof(card_data)); // Reset card_data structure
|
||||||
printf("\r\n");
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,33 +292,34 @@ HRESULT aime_io_nfc_get_felica_id(uint8_t unit_no, uint64_t *IDm)
|
|||||||
if (unit_no != 0)
|
if (unit_no != 0)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
if (aime_io_felica_id_present)
|
if (card_data.card_type == FeliCa)
|
||||||
{
|
{
|
||||||
val = 0;
|
val = 0;
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
val = (val << 8) | aime_io_felica_id[i];
|
val = (val << 8) | card_data.card_id[i];
|
||||||
|
|
||||||
*IDm = val;
|
*IDm = val;
|
||||||
printf("%s: Read FeliCa card from file with uid %llx\r\n", module, val);
|
printf("aime_io_nfc_get_felica_id: Read FeliCa card from file with uid %02X%02X %02X%02X %02X%02X %02X%02X\r\n", card_data.card_id[0], card_data.card_id[1], card_data.card_id[2], card_data.card_id[3], card_data.card_id[4], card_data.card_id[5], card_data.card_id[6], card_data.card_id[7]);
|
||||||
|
|
||||||
|
memset(&card_data, 0, sizeof(card_data)); // Reset card_data structure
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasCard)
|
// if (HasCard)
|
||||||
{
|
// {
|
||||||
polling = false;
|
// polling = false;
|
||||||
HasCard = false;
|
// HasCard = false;
|
||||||
|
|
||||||
uint64_t val;
|
// uint64_t val;
|
||||||
for (int i = 0; i < 8; i++)
|
// for (int i = 0; i < 8; i++)
|
||||||
{
|
// {
|
||||||
val = (val << 8) | UID[i];
|
// val = (val << 8) | UID[i];
|
||||||
}
|
// }
|
||||||
*IDm = val;
|
// *IDm = val;
|
||||||
printf("%s: FeliCa card has been scanned ! %llx\r\n", module, val);
|
// printf("aime_io_nfc_get_felica_id: FeliCa card has been scanned ! %llx\r\n", val);
|
||||||
|
|
||||||
return S_OK;
|
// return S_OK;
|
||||||
}
|
// }
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/aimeio.h
16
src/aimeio.h
@ -1,9 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
struct aime_io_config
|
||||||
|
{
|
||||||
|
bool debug;
|
||||||
|
wchar_t aime_path[MAX_PATH];
|
||||||
|
wchar_t felica_path[MAX_PATH];
|
||||||
|
wchar_t reader_name[MAX_PATH];
|
||||||
|
bool reader_optional;
|
||||||
|
uint8_t vk_scan;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get the version of the Aime IO API that this DLL supports. This function
|
Get the version of the Aime IO API that this DLL supports. This function
|
||||||
|
@ -14,16 +14,16 @@ int main()
|
|||||||
switch (aime_io_init())
|
switch (aime_io_init())
|
||||||
{
|
{
|
||||||
case E_FAIL:
|
case E_FAIL:
|
||||||
printf("aime_io_init() returned E_FAIL. Reader is either missing or incompatible !\r\n");
|
printf("AIMETEST: aime_io_init() returned E_FAIL. Reader is either missing or incompatible !\r\n");
|
||||||
break;
|
return E_FAIL;
|
||||||
|
|
||||||
case S_OK:
|
case S_OK:
|
||||||
printf("aime_io_init() returned S_OK !\r\n");
|
printf("AIMETEST: aime_io_init() returned S_OK !\r\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("aime_io_init() returned an unknown state !\r\n");
|
printf("AIMETEST: aime_io_init() returned an unknown state !\r\n");
|
||||||
break;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("aime_io_led_set_color(red) : ");
|
// printf("aime_io_led_set_color(red) : ");
|
||||||
@ -40,7 +40,7 @@ int main()
|
|||||||
// Sleep(2000);
|
// Sleep(2000);
|
||||||
// aime_io_led_set_color(0, 0, 0, 0);
|
// aime_io_led_set_color(0, 0, 0, 0);
|
||||||
|
|
||||||
printf("Running input loop. Press Ctrl+C to exit.\r\n");
|
printf("AIMETEST: Running input loop. Press Ctrl+C to exit.\r\n");
|
||||||
|
|
||||||
uint8_t luid[10] = {0};
|
uint8_t luid[10] = {0};
|
||||||
uint64_t IDm = 0;
|
uint64_t IDm = 0;
|
||||||
@ -51,12 +51,12 @@ int main()
|
|||||||
if (aime_io_nfc_get_felica_id(0, &IDm) == S_OK)
|
if (aime_io_nfc_get_felica_id(0, &IDm) == S_OK)
|
||||||
{
|
{
|
||||||
// aime_io_led_set_color(0, 0, 255, 0);
|
// aime_io_led_set_color(0, 0, 255, 0);
|
||||||
printf("Found FeliCa card with uid %llx\r\n\n", IDm);
|
printf("AIMETEST: Found FeliCa card with uid %llx\r\n\n", IDm);
|
||||||
}
|
}
|
||||||
if (aime_io_nfc_get_aime_id(0, luid, 10) == S_OK)
|
if (aime_io_nfc_get_aime_id(0, luid, 10) == S_OK)
|
||||||
{
|
{
|
||||||
// aime_io_led_set_color(0, 0, 0, 255);
|
// aime_io_led_set_color(0, 0, 0, 255);
|
||||||
printf("Found old card with uid ");
|
printf("AIMETEST: Found old card with uid ");
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
printf("%02x ", luid[i]);
|
printf("%02x ", luid[i]);
|
||||||
|
@ -1,33 +1,4 @@
|
|||||||
/**
|
|
||||||
* MIT-License
|
|
||||||
* Copyright (c) 2018 by nolm <nolan@nolm.name>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* Modified version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "scard.h"
|
#include "scard.h"
|
||||||
// #include <tchar.h>
|
|
||||||
// #include <thread>
|
|
||||||
|
|
||||||
extern char module[];
|
|
||||||
|
|
||||||
#define MAX_APDU_SIZE 255
|
#define MAX_APDU_SIZE 255
|
||||||
int readCooldown = 500;
|
int readCooldown = 500;
|
||||||
@ -35,35 +6,168 @@ int readCooldown = 500;
|
|||||||
// based off acr122u reader, see page 26 in api document.
|
// based off acr122u reader, see page 26 in api document.
|
||||||
// https://www.acs.com.hk/en/download-manual/419/API-ACR122U-2.04.pdf
|
// https://www.acs.com.hk/en/download-manual/419/API-ACR122U-2.04.pdf
|
||||||
|
|
||||||
#define PICC_OPERATING_PARAMS 0xDFu
|
#define PARAM_POLLRATE 0xDFu
|
||||||
BYTE PICC_OPERATING_PARAM_CMD[5] = {0xFFu, 0x00u, 0x51u, PICC_OPERATING_PARAMS, 0x00u};
|
static const BYTE PARAM_SET_PICC[5] = {0xFFu, 0x00u, 0x51u, PARAM_POLLRATE, 0x00u};
|
||||||
|
static const BYTE COMMAND_GET_UID[5] = {0xFFu, 0xCAu, 0x00u, 0x00u, 0x00u};
|
||||||
|
|
||||||
// return bytes from device
|
// return bytes from device
|
||||||
#define PICC_SUCCESS 0x90u
|
#define PICC_SUCCESS 0x90u
|
||||||
#define PICC_ERROR 0x63u
|
#define PICC_ERROR 0x63u
|
||||||
|
|
||||||
static const BYTE UID_CMD[5] = {0xFFu, 0xCAu, 0x00u, 0x00u, 0x00u};
|
|
||||||
|
|
||||||
enum scard_atr_protocol
|
enum scard_atr_protocol
|
||||||
{
|
{
|
||||||
SCARD_ATR_PROTOCOL_ISO14443_PART3 = 0x03,
|
SCARD_ATR_PROTOCOL_ISO14443_PART3 = 0x03,
|
||||||
SCARD_ATR_PROTOCOL_ISO15693_PART3 = 0x0B,
|
|
||||||
SCARD_ATR_PROTOCOL_FELICA_212K = 0x11,
|
SCARD_ATR_PROTOCOL_FELICA_212K = 0x11,
|
||||||
SCARD_ATR_PROTOCOL_FELICA_424K = 0x12,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// winscard_config_t WINSCARD_CONFIG;
|
// winscard_config_t WINSCARD_CONFIG;
|
||||||
SCARDCONTEXT hContext = 0;
|
static SCARDCONTEXT hContext = 0;
|
||||||
SCARD_READERSTATE reader_states[2];
|
static SCARD_READERSTATE reader_state;
|
||||||
LPTSTR reader_name_slots[2] = {NULL, NULL};
|
static LONG lRet = 0;
|
||||||
int reader_count = 0;
|
|
||||||
LONG lRet = 0;
|
|
||||||
|
|
||||||
void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8_t unit_no)
|
bool scard_init(struct aime_io_config config)
|
||||||
{
|
{
|
||||||
printf("%s: Update on reader : %s\n", module, reader_states[unit_no].szReader);
|
if ((lRet = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext)) != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
// log_warning("scard", "failed to establish SCard context: {}", bin2hex(&lRet, sizeof(LONG)));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get list of readers
|
||||||
|
LPTSTR reader_list = NULL;
|
||||||
|
auto pcchReaders = SCARD_AUTOALLOCATE;
|
||||||
|
lRet = SCardListReaders(hContext, NULL, (LPTSTR)&reader_list, &pcchReaders);
|
||||||
|
|
||||||
|
switch (lRet)
|
||||||
|
{
|
||||||
|
case SCARD_E_NO_READERS_AVAILABLE:
|
||||||
|
printf("scard_init: No readers available\n");
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case SCARD_S_SUCCESS:
|
||||||
|
LPTSTR reader_name = NULL;
|
||||||
|
int readerNameLen = 0;
|
||||||
|
|
||||||
|
// Iterate through the multi-string to get individual reader names
|
||||||
|
printf("scard_init: listing all readers : ");
|
||||||
|
while (*reader_list != '\0')
|
||||||
|
{
|
||||||
|
printf("%s, ", reader_list);
|
||||||
|
reader_list += strlen(reader_list) + 1;
|
||||||
|
}
|
||||||
|
printf("\r\n", reader_list);
|
||||||
|
|
||||||
|
// if the readerName array is populated, replace the first reader in the list
|
||||||
|
char ReaderCharArray[sizeof(config.reader_name)];
|
||||||
|
wcstombs(ReaderCharArray, config.reader_name, sizeof(ReaderCharArray));
|
||||||
|
if (strcmp(ReaderCharArray, "") != 0)
|
||||||
|
{
|
||||||
|
size_t newLen = strlen(ReaderCharArray) + 1;
|
||||||
|
LPSTR newMszReaders = (LPSTR)malloc(newLen);
|
||||||
|
if (newMszReaders != NULL)
|
||||||
|
{
|
||||||
|
// Copy the new selected reader
|
||||||
|
strcpy(newMszReaders, ReaderCharArray);
|
||||||
|
|
||||||
|
// Update the original pointer to the new modified list
|
||||||
|
reader_list = newMszReaders;
|
||||||
|
}
|
||||||
|
printf("scard_init: Forced using reader : %hs\n", ReaderCharArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to reader and send PICC operating params command
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
DWORD dwActiveProtocol;
|
||||||
|
lRet = SCardConnect(hContext, reader_list, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol);
|
||||||
|
if (lRet != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("scard_init: Error connecting to the reader: 0x%08X\n", lRet);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
printf("scard_init: Connected to reader: %s, sending PICC params\n", reader_list);
|
||||||
|
|
||||||
|
// set the reader params
|
||||||
|
DWORD cbRecv = MAX_APDU_SIZE;
|
||||||
|
BYTE pbRecv[MAX_APDU_SIZE];
|
||||||
|
lRet = SCardControl(hCard, SCARD_CTL_CODE(3500), PARAM_SET_PICC, sizeof(PARAM_SET_PICC), pbRecv, cbRecv, &cbRecv);
|
||||||
|
Sleep(100);
|
||||||
|
if (lRet != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("scard_init: Error setting PICC params : 0x%08X\n", lRet);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbRecv > 2 && pbRecv[0] != PICC_SUCCESS && pbRecv[1] != PARAM_POLLRATE)
|
||||||
|
{
|
||||||
|
printf("scard_init: PICC params not valid 0x%02X != 0x%02X\n", pbRecv[1], PARAM_POLLRATE);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect from reader
|
||||||
|
if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS)
|
||||||
|
printf("scard_init: Failed SCardDisconnect : 0x%08X\n", lRet);
|
||||||
|
|
||||||
|
// Extract the relevant names from the multi-string.
|
||||||
|
readerNameLen = lstrlen(reader_list);
|
||||||
|
reader_name = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1));
|
||||||
|
memcpy(reader_name, &reader_list, (size_t)(readerNameLen + 1));
|
||||||
|
|
||||||
|
if (reader_name)
|
||||||
|
printf("scard_init: Using reader : %s\n", reader_name);
|
||||||
|
|
||||||
|
memset(&reader_state, 0, sizeof(SCARD_READERSTATE));
|
||||||
|
reader_state.szReader = reader_name;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf("scard_init: Failed SCardListReaders: 0x%08X\n", lRet);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scard_poll(struct card_data *card_data)
|
||||||
|
{
|
||||||
|
lRet = SCardGetStatusChange(hContext, readCooldown, &reader_state, 1);
|
||||||
|
if (lRet == SCARD_E_TIMEOUT)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (lRet != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("scard_poll: Failed SCardGetStatusChange: 0x%08X\n", lRet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(reader_state.dwEventState & SCARD_STATE_CHANGED))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DWORD newState = reader_state.dwEventState ^ SCARD_STATE_CHANGED;
|
||||||
|
bool wasCardPresent = (reader_state.dwCurrentState & SCARD_STATE_PRESENT) > 0;
|
||||||
|
if (newState & SCARD_STATE_UNAVAILABLE)
|
||||||
|
{
|
||||||
|
printf("scard_poll: New card state: unavailable\n");
|
||||||
|
Sleep(readCooldown);
|
||||||
|
}
|
||||||
|
else if (newState & SCARD_STATE_EMPTY)
|
||||||
|
{
|
||||||
|
printf("scard_poll: New card state: empty\n");
|
||||||
|
// scard_clear(unit_no);
|
||||||
|
}
|
||||||
|
else if (newState & SCARD_STATE_PRESENT && !wasCardPresent)
|
||||||
|
{
|
||||||
|
printf("scard_poll: New card state: present\n");
|
||||||
|
scard_update(card_data, hContext, reader_state.szReader);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader_state.dwCurrentState = reader_state.dwEventState;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scard_update(struct card_data *card_data, SCARDCONTEXT _hContext, LPCTSTR _readerName)
|
||||||
|
{
|
||||||
|
printf("scard_update: Update on reader : %s\n", reader_state.szReader);
|
||||||
// Connect to the smart card.
|
// Connect to the smart card.
|
||||||
LONG lRet = 0;
|
|
||||||
SCARDHANDLE hCard;
|
SCARDHANDLE hCard;
|
||||||
DWORD dwActiveProtocol;
|
DWORD dwActiveProtocol;
|
||||||
for (int retry = 0; retry < 100; retry++) // retry times has to be increased since poll rate is set to 500ms
|
for (int retry = 0; retry < 100; retry++) // retry times has to be increased since poll rate is set to 500ms
|
||||||
@ -76,12 +180,11 @@ void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8
|
|||||||
|
|
||||||
if (lRet != SCARD_S_SUCCESS)
|
if (lRet != SCARD_S_SUCCESS)
|
||||||
{
|
{
|
||||||
printf("%s: Error connecting to the card: 0x%08X\n", module, lRet);
|
printf("scard_update: Error connecting to the card: 0x%08X\n", lRet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the reader params
|
// set the reader params
|
||||||
lRet = 0;
|
|
||||||
LPCSCARD_IO_REQUEST pci = dwActiveProtocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0;
|
LPCSCARD_IO_REQUEST pci = dwActiveProtocol == SCARD_PROTOCOL_T1 ? SCARD_PCI_T1 : SCARD_PCI_T0;
|
||||||
DWORD cbRecv = MAX_APDU_SIZE;
|
DWORD cbRecv = MAX_APDU_SIZE;
|
||||||
BYTE pbRecv[MAX_APDU_SIZE];
|
BYTE pbRecv[MAX_APDU_SIZE];
|
||||||
@ -94,263 +197,76 @@ void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8
|
|||||||
lRet = SCardStatus(hCard, szReader, &cchReader, NULL, NULL, atr, &cByteAtr);
|
lRet = SCardStatus(hCard, szReader, &cchReader, NULL, NULL, atr, &cByteAtr);
|
||||||
if (lRet != SCARD_S_SUCCESS)
|
if (lRet != SCARD_S_SUCCESS)
|
||||||
{
|
{
|
||||||
printf("%s: Error getting card status: 0x%08X\n", module, lRet);
|
printf("scard_update: Error getting card status: 0x%08X\n", lRet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only care about 20-byte ATRs returned by arcade-type smart cards
|
// Only care about 20-byte ATRs returned by arcade-type smart cards
|
||||||
if (cByteAtr != 20)
|
if (cByteAtr != 20)
|
||||||
{
|
{
|
||||||
printf("%s: Ignoring card with len(%d) = %02X (%08X)\n", module, cByteAtr, atr, cByteAtr);
|
printf("scard_update: Ignoring card with len(%zu) = %02x (%08X)\n", sizeof(cByteAtr), (unsigned int)atr, cByteAtr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: atr Return: len(%d) = %02X (%08X)\n", module, cByteAtr, atr, cByteAtr);
|
printf("scard_update: atr Return: len(%zu) = %02x (%08X)\n", sizeof(cByteAtr), (unsigned int)atr, cByteAtr);
|
||||||
|
|
||||||
// Figure out if we should reverse the UID returned by the card based on the ATR protocol
|
// Figure out if we should reverse the UID returned by the card based on the ATR protocol
|
||||||
BYTE cardProtocol = atr[12];
|
BYTE cardProtocol = atr[12];
|
||||||
BOOL shouldReverseUid = false;
|
|
||||||
if (cardProtocol == SCARD_ATR_PROTOCOL_ISO15693_PART3)
|
if (cardProtocol == SCARD_ATR_PROTOCOL_ISO14443_PART3)
|
||||||
{
|
{
|
||||||
printf("%s: Card protocol: ISO15693_PART3\n", module);
|
printf("scard_update: Card protocol: ISO14443_PART3\n");
|
||||||
shouldReverseUid = true;
|
card_data->card_type = Mifare;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (cardProtocol == SCARD_ATR_PROTOCOL_ISO14443_PART3)
|
else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_212K) // Handling FeliCa
|
||||||
printf("%s: Card protocol: ISO14443_PART3\n", module);
|
{
|
||||||
|
printf("scard_update: Card protocol: FELICA_212K\n");
|
||||||
|
card_data->card_type = FeliCa;
|
||||||
|
|
||||||
else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_212K)
|
// Read mID
|
||||||
printf("%s: Card protocol: FELICA_212K\n", module);
|
cbRecv = MAX_APDU_SIZE;
|
||||||
|
if ((lRet = SCardTransmit(hCard, pci, COMMAND_GET_UID, sizeof(COMMAND_GET_UID), NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
printf("scard_update: Error querying card UID: 0x%08X\n", lRet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (cardProtocol == SCARD_ATR_PROTOCOL_FELICA_424K)
|
if (cbRecv > 1 && pbRecv[0] == PICC_ERROR)
|
||||||
printf("%s: Card protocol: FELICA_424K\n", module);
|
{
|
||||||
|
printf("scard_update: UID query failed\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS)
|
||||||
|
printf("scard_update: Failed SCardDisconnect: 0x%08X\n", lRet);
|
||||||
|
|
||||||
|
if (cbRecv < 8)
|
||||||
|
{
|
||||||
|
printf("scard_update: Padding card uid to 8 bytes\n");
|
||||||
|
memset(&pbRecv[cbRecv], 0, 8 - cbRecv);
|
||||||
|
}
|
||||||
|
else if (cbRecv > 8)
|
||||||
|
printf("scard_update: taking first 8 bytes of len(uid) = %02X\n", cbRecv);
|
||||||
|
|
||||||
|
card_data->card_id_len = 8;
|
||||||
|
memcpy(card_data->card_id, pbRecv, 8);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("%s: Unknown NFC Protocol: 0x%02X\n", module, cardProtocol);
|
printf("scard_update: Unknown NFC Protocol: 0x%02X\n", cardProtocol);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read UID
|
|
||||||
cbRecv = MAX_APDU_SIZE;
|
|
||||||
if ((lRet = SCardTransmit(hCard, pci, UID_CMD, sizeof(UID_CMD), NULL, pbRecv, &cbRecv)) != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
printf("%s: Error querying card UID: 0x%08X\n", module, lRet);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbRecv > 1 && pbRecv[0] == PICC_ERROR)
|
|
||||||
{
|
|
||||||
printf("%s: UID query failed\n", module);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS)
|
|
||||||
printf("%s: Failed SCardDisconnect: 0x%08X\n", module, lRet);
|
|
||||||
|
|
||||||
if (cbRecv < 8)
|
|
||||||
{
|
|
||||||
printf("%s: Padding card uid to 8 bytes\n", module);
|
|
||||||
memset(&pbRecv[cbRecv], 0, 8 - cbRecv);
|
|
||||||
}
|
|
||||||
else if (cbRecv > 8)
|
|
||||||
printf("%s: taking first 8 bytes of len(uid) = %02X\n", module, cbRecv);
|
|
||||||
|
|
||||||
// Copy UID to struct, reversing if necessary
|
// Copy UID to struct, reversing if necessary
|
||||||
card_info_t card_info;
|
// card_info_t card_info;
|
||||||
if (shouldReverseUid)
|
// if (shouldReverseUid)
|
||||||
for (DWORD i = 0; i < 8; i++)
|
// for (DWORD i = 0; i < 8; i++)
|
||||||
card_info.uid[i] = pbRecv[7 - i];
|
// card_info.uid[i] = pbRecv[7 - i];
|
||||||
else
|
// else
|
||||||
memcpy(card_info.uid, pbRecv, 8);
|
// memcpy(card_info.uid, pbRecv, 8);
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
// for (int i = 0; i < 8; ++i)
|
||||||
buf[i] = card_info.uid[i];
|
// buf[i] = card_info.uid[i];
|
||||||
}
|
|
||||||
|
|
||||||
// void scard_clear(uint8_t unitNo)
|
|
||||||
// {
|
|
||||||
// card_info_t empty_cardinfo;
|
|
||||||
// }
|
|
||||||
|
|
||||||
void scard_update(uint8_t *buf)
|
|
||||||
{
|
|
||||||
if (reader_count < 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lRet = SCardGetStatusChange(hContext, readCooldown, reader_states, reader_count);
|
|
||||||
if (lRet == SCARD_E_TIMEOUT)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (lRet != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
printf("%s: Failed SCardGetStatusChange: 0x%08X\n", module, lRet);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t unit_no = 0; unit_no < reader_count; unit_no++)
|
|
||||||
{
|
|
||||||
if (!(reader_states[unit_no].dwEventState & SCARD_STATE_CHANGED))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
DWORD newState = reader_states[unit_no].dwEventState ^ SCARD_STATE_CHANGED;
|
|
||||||
bool wasCardPresent = (reader_states[unit_no].dwCurrentState & SCARD_STATE_PRESENT) > 0;
|
|
||||||
if (newState & SCARD_STATE_UNAVAILABLE)
|
|
||||||
{
|
|
||||||
printf("%s: New card state: unavailable\n", module);
|
|
||||||
Sleep(readCooldown);
|
|
||||||
}
|
|
||||||
else if (newState & SCARD_STATE_EMPTY)
|
|
||||||
{
|
|
||||||
printf("%s: New card state: empty\n", module);
|
|
||||||
// scard_clear(unit_no);
|
|
||||||
}
|
|
||||||
else if (newState & SCARD_STATE_PRESENT && !wasCardPresent)
|
|
||||||
{
|
|
||||||
printf("%s: New card state: present\n", module);
|
|
||||||
scard_poll(buf, hContext, reader_states[unit_no].szReader, unit_no);
|
|
||||||
}
|
|
||||||
|
|
||||||
reader_states[unit_no].dwCurrentState = reader_states[unit_no].dwEventState;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool scard_init()
|
|
||||||
{
|
|
||||||
if ((lRet = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext)) != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
// log_warning("scard", "failed to establish SCard context: {}", bin2hex(&lRet, sizeof(LONG)));
|
|
||||||
return lRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
LPCTSTR reader = NULL;
|
|
||||||
|
|
||||||
int readerNameLen = 0;
|
|
||||||
|
|
||||||
// get list of readers
|
|
||||||
LPTSTR reader_list = NULL;
|
|
||||||
auto pcchReaders = SCARD_AUTOALLOCATE;
|
|
||||||
lRet = SCardListReaders(hContext, NULL, (LPTSTR)&reader_list, &pcchReaders);
|
|
||||||
|
|
||||||
int slot0_idx = -1;
|
|
||||||
int slot1_idx = -1;
|
|
||||||
int readerCount = 0;
|
|
||||||
switch (lRet)
|
|
||||||
{
|
|
||||||
case SCARD_E_NO_READERS_AVAILABLE:
|
|
||||||
printf("%s: No readers available\n", module);
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
case SCARD_S_SUCCESS:
|
|
||||||
|
|
||||||
// So WinAPI has this terrible "multi-string" concept wherein you have a list
|
|
||||||
// of null-terminated strings, terminated by a double-null.
|
|
||||||
for (reader = reader_list; *reader; reader = reader + lstrlen(reader) + 1)
|
|
||||||
{
|
|
||||||
printf("%s: Found reader: %s\n", module, reader);
|
|
||||||
readerCount++;
|
|
||||||
|
|
||||||
// Connect to reader and send PICC operating params command
|
|
||||||
LONG lRet = 0;
|
|
||||||
SCARDHANDLE hCard;
|
|
||||||
DWORD dwActiveProtocol;
|
|
||||||
lRet = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard, &dwActiveProtocol);
|
|
||||||
if (lRet != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
printf("%s: Error connecting to the reader: 0x%08X\n", module, lRet);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
printf("%s: Connected to reader: %s, sending PICC operating params command\n", module, reader);
|
|
||||||
|
|
||||||
// set the reader params
|
|
||||||
lRet = 0;
|
|
||||||
DWORD cbRecv = MAX_APDU_SIZE;
|
|
||||||
BYTE pbRecv[MAX_APDU_SIZE];
|
|
||||||
lRet = SCardControl(hCard, SCARD_CTL_CODE(3500), PICC_OPERATING_PARAM_CMD, sizeof(PICC_OPERATING_PARAM_CMD), pbRecv, cbRecv, &cbRecv);
|
|
||||||
Sleep(100);
|
|
||||||
if (lRet != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
printf("%s: Error setting PICC params: 0x%08X\n", module, lRet);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbRecv > 2 && pbRecv[0] != PICC_SUCCESS && pbRecv[1] != PICC_OPERATING_PARAMS)
|
|
||||||
{
|
|
||||||
printf("%s: PICC params not valid 0x%02X != 0x%02X\n", module, pbRecv[1], PICC_OPERATING_PARAMS);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect from reader
|
|
||||||
if ((lRet = SCardDisconnect(hCard, SCARD_LEAVE_CARD)) != SCARD_S_SUCCESS)
|
|
||||||
{
|
|
||||||
printf("%s: Failed SCardDisconnect: 0x%08X\n", module, lRet);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("%s: Disconnected from reader: %s, this is expected behavior\n", module, reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have at least two readers, assign readers to slots as necessary.
|
|
||||||
if (readerCount >= 2)
|
|
||||||
{
|
|
||||||
if (slot1_idx != 0)
|
|
||||||
slot0_idx = 0;
|
|
||||||
if (slot0_idx != 1)
|
|
||||||
slot1_idx = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the reader count is 1 and no reader was set, set first reader
|
|
||||||
if (readerCount == 1 && slot0_idx < 0 && slot1_idx < 0)
|
|
||||||
slot0_idx = 0;
|
|
||||||
|
|
||||||
// If we somehow only found slot 1, promote slot 1 to slot 0.
|
|
||||||
if (slot0_idx < 0 && slot1_idx >= 0)
|
|
||||||
{
|
|
||||||
slot0_idx = slot1_idx;
|
|
||||||
slot1_idx = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the relevant names from the multi-string.
|
|
||||||
int i;
|
|
||||||
for (i = 0, reader = reader_list; *reader; reader = reader + lstrlen(reader) + 1, i++)
|
|
||||||
{
|
|
||||||
if (slot0_idx == i)
|
|
||||||
{
|
|
||||||
readerNameLen = lstrlen(reader);
|
|
||||||
reader_name_slots[0] = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1));
|
|
||||||
memcpy(reader_name_slots[0], &reader[0], (size_t)(readerNameLen + 1));
|
|
||||||
}
|
|
||||||
if (slot1_idx == i)
|
|
||||||
{
|
|
||||||
readerNameLen = lstrlen(reader);
|
|
||||||
reader_name_slots[1] = (LPTSTR)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(TCHAR) * (readerNameLen + 1));
|
|
||||||
memcpy(reader_name_slots[1], &reader[0], (size_t)(readerNameLen + 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reader_name_slots[0])
|
|
||||||
printf("%s: Using reader slot 0: %s\n", module, reader_name_slots[0]);
|
|
||||||
|
|
||||||
if (reader_name_slots[1])
|
|
||||||
printf("%s: Using reader slot 1: %s\n", module, reader_name_slots[1]);
|
|
||||||
|
|
||||||
reader_count = reader_name_slots[1] ? 2 : 1;
|
|
||||||
|
|
||||||
memset(&reader_states[0], 0, sizeof(SCARD_READERSTATE));
|
|
||||||
reader_states[0].szReader = reader_name_slots[0];
|
|
||||||
|
|
||||||
memset(&reader_states[1], 0, sizeof(SCARD_READERSTATE));
|
|
||||||
reader_states[1].szReader = reader_name_slots[1];
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf("%s: Failed SCardListReaders: 0x%08X\n", module, lRet);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -24,23 +24,35 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <winscard.h>
|
#include <winscard.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <src/aimeio.h>
|
||||||
|
|
||||||
// cardinfo_t is a description of a card that was presented to a reader
|
/* card types */
|
||||||
typedef struct card_info
|
enum AIME_CARDTYPE
|
||||||
{
|
{
|
||||||
int card_type;
|
Mifare = 0x01,
|
||||||
uint8_t uid[8];
|
FeliCa = 0x02,
|
||||||
} card_info_t;
|
};
|
||||||
|
|
||||||
void scard_update(uint8_t *buf);
|
// Structure containing card_type, card_id and card_id_len
|
||||||
|
struct card_data
|
||||||
|
{
|
||||||
|
/* CARDTYPE */
|
||||||
|
uint8_t card_type;
|
||||||
|
|
||||||
void scard_poll(uint8_t *buf, SCARDCONTEXT _hContext, LPCTSTR _readerName, uint8_t unit_no);
|
/* Card ID */
|
||||||
|
uint8_t card_id[32];
|
||||||
|
|
||||||
void scard_clear(uint8_t unitNo);
|
/* Card ID length */
|
||||||
|
uint8_t card_id_len;
|
||||||
|
};
|
||||||
|
|
||||||
bool scard_init();
|
bool scard_init(struct aime_io_config config);
|
||||||
|
|
||||||
|
void scard_poll(struct card_data *card_data);
|
||||||
|
|
||||||
|
void scard_update(struct card_data *card_data, SCARDCONTEXT _hContext, LPCTSTR _readerName);
|
||||||
|
Loading…
Reference in New Issue
Block a user