mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
Merge pull request #287 from jamisonderek/jamisonderek/lf-viking
Add LF Viking support
This commit is contained in:
@@ -36,6 +36,7 @@ SRC_FILES += \
|
||||
$(PROJ_DIR)/rfid/nfctag/lf/utils/manchester.c \
|
||||
$(PROJ_DIR)/rfid/nfctag/lf/protocols/em410x.c \
|
||||
$(PROJ_DIR)/rfid/nfctag/lf/protocols/hidprox.c \
|
||||
$(PROJ_DIR)/rfid/nfctag/lf/protocols/viking.c \
|
||||
$(PROJ_DIR)/rfid/nfctag/lf/protocols/wiegand.c \
|
||||
$(PROJ_DIR)/utils/dataframe.c \
|
||||
$(PROJ_DIR)/utils/delayed_reset.c \
|
||||
@@ -343,6 +344,7 @@ ifeq (${CURRENT_DEVICE_TYPE}, ${CHAMELEON_ULTRA})
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_reader_main.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_t55xx_data.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_hidprox_data.c \
|
||||
$(PROJ_DIR)/rfid/reader/lf/lf_viking_data.c \
|
||||
|
||||
INC_FOLDERS +=\
|
||||
${PROJ_DIR}/rfid/reader/ \
|
||||
|
||||
@@ -650,6 +650,30 @@ static data_frame_tx_t *cmd_processor_hidprox_scan(uint16_t cmd, uint16_t status
|
||||
}
|
||||
return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_data), card_data);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_viking_scan(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
uint8_t card_buffer[4] = {0x00};
|
||||
status = scan_viking(card_buffer);
|
||||
if (status != STATUS_LF_TAG_OK) {
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
return data_frame_make(cmd, STATUS_LF_TAG_OK, sizeof(card_buffer), card_buffer);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_viking_write_to_t55xx(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
typedef struct {
|
||||
uint8_t id[4];
|
||||
uint8_t new_key[4];
|
||||
uint8_t old_keys[4]; // we can have more than one... struct just to compute offsets with min 1 key
|
||||
} PACKED payload_t;
|
||||
payload_t *payload = (payload_t *)data;
|
||||
if (length < sizeof(payload_t) || (length - offsetof(payload_t, old_keys)) % sizeof(payload->old_keys) != 0) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
|
||||
status = write_viking_to_t55xx(payload->id, payload->new_key, payload->old_keys, (length - offsetof(payload_t, old_keys)) / sizeof(payload->old_keys));
|
||||
return data_frame_make(cmd, status, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -817,6 +841,26 @@ static data_frame_tx_t *cmd_processor_hidprox_get_emu_id(uint16_t cmd, uint16_t
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, LF_HIDPROX_TAG_ID_SIZE, buffer->buffer);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_viking_set_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
if (length != LF_VIKING_TAG_ID_SIZE) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_VIKING);
|
||||
memcpy(buffer->buffer, data, LF_VIKING_TAG_ID_SIZE);
|
||||
tag_emulation_load_by_buffer(TAG_TYPE_VIKING, false);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, 0, NULL);
|
||||
}
|
||||
|
||||
static data_frame_tx_t *cmd_processor_viking_get_emu_id(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
tag_slot_specific_type_t tag_types;
|
||||
tag_emulation_get_specific_types_by_slot(tag_emulation_get_slot(), &tag_types);
|
||||
if (tag_types.tag_lf != TAG_TYPE_VIKING) {
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, data); // no data in slot, don't send garbage
|
||||
}
|
||||
tag_data_buffer_t *buffer = get_buffer_by_tag_type(TAG_TYPE_VIKING);
|
||||
return data_frame_make(cmd, STATUS_SUCCESS, LF_VIKING_TAG_ID_SIZE, buffer->buffer);
|
||||
}
|
||||
|
||||
static nfc_tag_14a_coll_res_reference_t *get_coll_res_data(bool write) {
|
||||
nfc_tag_14a_coll_res_reference_t *info;
|
||||
tag_slot_specific_type_t tag_types;
|
||||
@@ -1531,6 +1575,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
|
||||
{ DATA_CMD_EM410X_WRITE_TO_T55XX, before_reader_run, cmd_processor_em410x_write_to_t55xx, NULL },
|
||||
{ DATA_CMD_HIDPROX_SCAN, before_reader_run, cmd_processor_hidprox_scan, NULL },
|
||||
{ DATA_CMD_HIDPROX_WRITE_TO_T55XX, before_reader_run, cmd_processor_hidprox_write_to_t55xx, NULL },
|
||||
{ DATA_CMD_VIKING_SCAN, before_reader_run, cmd_processor_viking_scan, NULL },
|
||||
{ DATA_CMD_VIKING_WRITE_TO_T55XX, before_reader_run, cmd_processor_viking_write_to_t55xx, NULL },
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1577,6 +1623,8 @@ static cmd_data_map_t m_data_cmd_map[] = {
|
||||
{ DATA_CMD_EM410X_GET_EMU_ID, NULL, cmd_processor_em410x_get_emu_id, NULL },
|
||||
{ DATA_CMD_HIDPROX_SET_EMU_ID, NULL, cmd_processor_hidprox_set_emu_id, NULL },
|
||||
{ DATA_CMD_HIDPROX_GET_EMU_ID, NULL, cmd_processor_hidprox_get_emu_id, NULL },
|
||||
{ DATA_CMD_VIKING_SET_EMU_ID, NULL, cmd_processor_viking_set_emu_id, NULL },
|
||||
{ DATA_CMD_VIKING_GET_EMU_ID, NULL, cmd_processor_viking_get_emu_id, NULL },
|
||||
};
|
||||
|
||||
data_frame_tx_t *cmd_processor_get_device_capabilities(uint16_t cmd, uint16_t status, uint16_t length, uint8_t *data) {
|
||||
|
||||
@@ -608,6 +608,11 @@ static void btn_fn_copy_lf(uint8_t slot, tag_specific_type_t type) {
|
||||
size = LF_EM410X_TAG_ID_SIZE;
|
||||
data = id_buffer + 2; // skip tag type
|
||||
break;
|
||||
case TAG_TYPE_VIKING:
|
||||
status = scan_viking(id_buffer);
|
||||
size = LF_VIKING_TAG_ID_SIZE;
|
||||
data = id_buffer;
|
||||
break;
|
||||
default:
|
||||
NRF_LOG_ERROR("Unsupported LF tag type")
|
||||
offline_status_error();
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
#define DATA_CMD_EM410X_WRITE_TO_T55XX (3001)
|
||||
#define DATA_CMD_HIDPROX_SCAN (3002)
|
||||
#define DATA_CMD_HIDPROX_WRITE_TO_T55XX (3003)
|
||||
#define DATA_CMD_VIKING_SCAN (3004)
|
||||
#define DATA_CMD_VIKING_WRITE_TO_T55XX (3005)
|
||||
|
||||
//
|
||||
// ******************************************************************
|
||||
|
||||
@@ -149,5 +152,7 @@
|
||||
#define DATA_CMD_EM410X_GET_EMU_ID (5001)
|
||||
#define DATA_CMD_HIDPROX_SET_EMU_ID (5002)
|
||||
#define DATA_CMD_HIDPROX_GET_EMU_ID (5003)
|
||||
#define DATA_CMD_VIKING_SET_EMU_ID (5004)
|
||||
#define DATA_CMD_VIKING_GET_EMU_ID (5005)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "nrfx_pwm.h"
|
||||
#include "protocols/em410x.h"
|
||||
#include "protocols/hidprox.h"
|
||||
#include "protocols/viking.h"
|
||||
#include "syssleep.h"
|
||||
#include "tag_emulation.h"
|
||||
#include "tag_persistence.h"
|
||||
@@ -198,6 +199,16 @@ int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
|
||||
NRF_LOG_INFO("load lf hidprox data finish.");
|
||||
return LF_HIDPROX_TAG_ID_SIZE;
|
||||
}
|
||||
|
||||
if (type == TAG_TYPE_VIKING && buffer->length >= LF_VIKING_TAG_ID_SIZE) {
|
||||
m_tag_type = type;
|
||||
void *codec = viking.alloc();
|
||||
m_pwm_seq = viking.modulator(codec, buffer->buffer);
|
||||
viking.free(codec);
|
||||
NRF_LOG_INFO("load lf viking data finish.");
|
||||
return LF_VIKING_TAG_ID_SIZE;
|
||||
}
|
||||
|
||||
NRF_LOG_ERROR("no valid data exists in buffer for tag type: %d.", type);
|
||||
return 0;
|
||||
}
|
||||
@@ -224,6 +235,17 @@ int lf_tag_hidprox_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buff
|
||||
return m_tag_type == TAG_TYPE_HID_PROX ? LF_HIDPROX_TAG_ID_SIZE : 0;
|
||||
}
|
||||
|
||||
/** @brief Id card deposit card number before callback
|
||||
* @param type Refined tag type
|
||||
* @param buffer Data buffer
|
||||
* @return The length of the data that needs to be saved is that it does not save when 0
|
||||
*/
|
||||
int lf_tag_viking_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer) {
|
||||
// Make sure to load this tag before allowing saving
|
||||
// Just save the original card package directly
|
||||
return m_tag_type == TAG_TYPE_VIKING ? LF_VIKING_TAG_ID_SIZE : 0;
|
||||
}
|
||||
|
||||
bool lf_tag_data_factory(uint8_t slot, tag_specific_type_t tag_type, uint8_t *tag_id, uint16_t length) {
|
||||
// write data to flash
|
||||
tag_sense_type_t sense_type = get_sense_type_from_tag_type(tag_type);
|
||||
@@ -260,3 +282,14 @@ bool lf_tag_hidprox_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
|
||||
uint8_t tag_id[13] = {0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x51, 0x45, 0x00, 0x00, 0x00};
|
||||
return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id));
|
||||
}
|
||||
|
||||
/** @brief Id card deposit card number before callback
|
||||
* @param slot Card slot number
|
||||
* @param tag_type Refined tag type
|
||||
* @return Whether the format is successful, if the formatting is successful, it will return to True, otherwise False will be returned
|
||||
*/
|
||||
bool lf_tag_viking_data_factory(uint8_t slot, tag_specific_type_t tag_type) {
|
||||
// default id
|
||||
uint8_t tag_id[4] = {0xDE, 0xAD, 0xBE, 0xEF};
|
||||
return lf_tag_data_factory(slot, tag_type, tag_id, sizeof(tag_id));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#define LF_EM410X_TAG_ID_SIZE 5
|
||||
#define LF_HIDPROX_TAG_ID_SIZE 13
|
||||
#define LF_VIKING_TAG_ID_SIZE 4
|
||||
|
||||
void lf_tag_125khz_sense_switch(bool enable);
|
||||
int lf_tag_data_loadcb(tag_specific_type_t type, tag_data_buffer_t *buffer);
|
||||
@@ -14,4 +15,6 @@ int lf_tag_em410x_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffe
|
||||
bool lf_tag_em410x_data_factory(uint8_t slot, tag_specific_type_t tag_type);
|
||||
int lf_tag_hidprox_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer);
|
||||
bool lf_tag_hidprox_data_factory(uint8_t slot, tag_specific_type_t tag_type);
|
||||
int lf_tag_viking_data_savecb(tag_specific_type_t type, tag_data_buffer_t *buffer);
|
||||
bool lf_tag_viking_data_factory(uint8_t slot, tag_specific_type_t tag_type);
|
||||
bool is_lf_field_exists(void);
|
||||
|
||||
@@ -57,6 +57,12 @@ extern "C" {
|
||||
T5577_PWD | \
|
||||
(3 << T5577_MAXBLOCK_SHIFT))
|
||||
|
||||
#define T5577_VIKING_CONFIG ( \
|
||||
T5577_BITRATE_RF_32 | \
|
||||
T5577_MODULATION_MANCHESTER | \
|
||||
T5577_PWD | \
|
||||
(2 << T5577_MAXBLOCK_SHIFT))
|
||||
|
||||
void t55xx_write_data(uint32_t passwd, uint32_t *blks, uint8_t blk_count);
|
||||
void t55xx_reset_passwd(uint32_t old_passwd, uint32_t new_passwd);
|
||||
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
#include "viking.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "em410x.h"
|
||||
#include "nordic_common.h"
|
||||
#include "nrf_pwm.h"
|
||||
#include "parity.h"
|
||||
#include "protocols.h"
|
||||
#include "t55xx.h"
|
||||
#include "tag_base_type.h"
|
||||
#include "utils/manchester.h"
|
||||
|
||||
#define EM_BITS_PER_ROW_COUNT (EM_COLUMN_COUNT + 1)
|
||||
|
||||
#define VIKING_RAW_SIZE (64) // Preamble (24) + data (32) + checksum (8)
|
||||
#define VIKING_DATA_SIZE (4) // Card data is 4 bytes
|
||||
#define VIKING_HEADER (0xf20000) // Preamble... 11110010 00000000 00000000
|
||||
|
||||
#define VIKING_T55XX_BLOCK_COUNT (3) // config + 2 data blocks
|
||||
|
||||
// Duration between falling edges is...
|
||||
#define VIKING_READ_TIME1_BASE (0x20) // on 16, off 16 cycles
|
||||
#define VIKING_READ_TIME2_BASE (0x30) // on 16, off 32 cycles (or on 32 cycles, off 16 cycles)
|
||||
#define VIKING_READ_TIME3_BASE (0x40) // on 32, off 32 cycles
|
||||
#define VIKING_READ_JITTER_TIME_BASE (0x07) // Jitter is just under half of 16 cycles.
|
||||
|
||||
#define NRF_LOG_MODULE_NAME viking_protocol
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
static nrf_pwm_values_wave_form_t m_viking_pwm_seq_vals[VIKING_RAW_SIZE] = {};
|
||||
|
||||
nrf_pwm_sequence_t const m_viking_pwm_seq = {
|
||||
.values.p_wave_form = m_viking_pwm_seq_vals,
|
||||
.length = NRF_PWM_VALUES_LENGTH(m_viking_pwm_seq_vals),
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[VIKING_DATA_SIZE];
|
||||
uint64_t raw;
|
||||
uint8_t raw_length;
|
||||
manchester *modem;
|
||||
} viking_codec;
|
||||
|
||||
static uint64_t viking_raw_data(uint8_t *uid) {
|
||||
uint64_t raw = VIKING_HEADER;
|
||||
uint8_t crc = 0x5A;
|
||||
for (int8_t i = 0; i < VIKING_DATA_SIZE; i++) {
|
||||
raw <<= 8;
|
||||
raw |= uid[i];
|
||||
crc ^= uid[i];
|
||||
}
|
||||
raw <<= 8;
|
||||
raw |= crc;
|
||||
return raw;
|
||||
}
|
||||
|
||||
static bool viking_get_time(uint8_t interval, uint8_t base) {
|
||||
return interval >= (base - VIKING_READ_JITTER_TIME_BASE) &&
|
||||
interval <= (base + VIKING_READ_JITTER_TIME_BASE);
|
||||
}
|
||||
|
||||
static uint8_t viking_period(uint8_t interval) {
|
||||
if (viking_get_time(interval, VIKING_READ_TIME1_BASE)) { // short/short
|
||||
return 0;
|
||||
}
|
||||
if (viking_get_time(interval, VIKING_READ_TIME2_BASE)) { // short/long or long/short
|
||||
return 1;
|
||||
}
|
||||
if (viking_get_time(interval, VIKING_READ_TIME3_BASE)) { // long/long
|
||||
return 2;
|
||||
}
|
||||
return 3; // Not manchester (or bad signal).
|
||||
}
|
||||
|
||||
static viking_codec *viking_alloc(void) {
|
||||
viking_codec *codec = malloc(sizeof(viking_codec));
|
||||
codec->modem = malloc(sizeof(manchester));
|
||||
codec->modem->rp = viking_period;
|
||||
return codec;
|
||||
};
|
||||
|
||||
static void viking_free(viking_codec *d) {
|
||||
if (d->modem) {
|
||||
free(d->modem);
|
||||
d->modem = NULL;
|
||||
}
|
||||
free(d);
|
||||
};
|
||||
|
||||
static uint8_t *viking_get_data(viking_codec *d) {
|
||||
return d->data;
|
||||
};
|
||||
|
||||
static void viking_decoder_start(viking_codec *d, uint8_t format) {
|
||||
memset(d->data, 0, VIKING_DATA_SIZE);
|
||||
d->raw = 0;
|
||||
d->raw_length = 0;
|
||||
manchester_reset(d->modem);
|
||||
};
|
||||
|
||||
static bool viking_decode_feed(viking_codec *d, bool bit) {
|
||||
d->raw <<= 1;
|
||||
d->raw_length++;
|
||||
if (bit) {
|
||||
d->raw |= 0x01;
|
||||
}
|
||||
if (d->raw_length < (VIKING_RAW_SIZE-2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check header
|
||||
uint8_t v = (d->raw >> (VIKING_RAW_SIZE - 24)) & 0xff; // Check LSB of header
|
||||
if (v != ((VIKING_HEADER & 0xFF))) {
|
||||
return false;
|
||||
}
|
||||
v = (d->raw >> (VIKING_RAW_SIZE - 16)) & 0xff; // Check mid of header
|
||||
if (v != ((VIKING_HEADER >> 8) & 0xFF)) {
|
||||
return false;
|
||||
}
|
||||
v = (d->raw >> (VIKING_RAW_SIZE - 8)) & 0xff; // Check MSB of header
|
||||
if ((v & 0xFF) != ((VIKING_HEADER >> 16) & 0xFF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate CRC
|
||||
uint8_t crc = 0x5A;
|
||||
for (int i = 0; i < VIKING_DATA_SIZE; i++) {
|
||||
uint8_t data = (d->raw >> ((i+1)*8)) & 0xff;
|
||||
crc ^= data;
|
||||
d->data[VIKING_DATA_SIZE - i - 1] |= data;
|
||||
}
|
||||
|
||||
return crc == (d->raw & 0xff);
|
||||
}
|
||||
|
||||
static bool viking_decoder_feed(viking_codec *d, uint16_t interval) {
|
||||
bool bits[2] = {0};
|
||||
int8_t bitlen = 0;
|
||||
|
||||
// Hack: due to hardware sometimes not detecting a time2 pulse. Rather than
|
||||
// reset when interval is really long, assume there was a time2 pulse.
|
||||
if (interval > VIKING_READ_TIME3_BASE + VIKING_READ_JITTER_TIME_BASE) {
|
||||
interval -= VIKING_READ_TIME2_BASE;
|
||||
manchester_feed(d->modem, (uint8_t)VIKING_READ_TIME2_BASE, bits, &bitlen);
|
||||
if (bitlen == -1) {
|
||||
d->raw = 0;
|
||||
d->raw_length = 0;
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bitlen; i++) {
|
||||
if (viking_decode_feed(d, bits[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
manchester_feed(d->modem, (uint8_t)interval, bits, &bitlen);
|
||||
if (bitlen == -1) {
|
||||
if (d->raw == 62) {
|
||||
if (viking_decode_feed(d, 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
d->raw = 0;
|
||||
d->raw_length = 0;
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bitlen; i++) {
|
||||
if (viking_decode_feed(d, bits[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
static const nrf_pwm_sequence_t *viking_modulator(viking_codec *d, uint8_t *buf) {
|
||||
uint64_t lo = viking_raw_data(buf);
|
||||
for (int i = 0; i < VIKING_RAW_SIZE; i++) {
|
||||
uint16_t msb = 0x00;
|
||||
if (IS_SET(lo, VIKING_RAW_SIZE - i - 1)) {
|
||||
msb = (1 << 15);
|
||||
}
|
||||
m_viking_pwm_seq_vals[i].channel_0 = msb | 16;
|
||||
m_viking_pwm_seq_vals[i].counter_top = 32;
|
||||
|
||||
}
|
||||
return &m_viking_pwm_seq;
|
||||
};
|
||||
|
||||
// Viking card
|
||||
const protocol viking = {
|
||||
.tag_type = TAG_TYPE_VIKING,
|
||||
.data_size = VIKING_DATA_SIZE,
|
||||
.alloc = (codec_alloc)viking_alloc,
|
||||
.free = (codec_free)viking_free,
|
||||
.get_data = (codec_get_data)viking_get_data,
|
||||
.modulator = (modulator)viking_modulator,
|
||||
.decoder =
|
||||
{
|
||||
.start = (decoder_start)viking_decoder_start,
|
||||
.feed = (decoder_feed)viking_decoder_feed,
|
||||
},
|
||||
};
|
||||
|
||||
// Encode viking card number to T55xx blocks.
|
||||
uint8_t viking_t55xx_writer(uint8_t *uid, uint32_t *blks) {
|
||||
uint64_t raw = viking_raw_data(uid);
|
||||
blks[0] = T5577_VIKING_CONFIG;
|
||||
blks[1] = raw >> 32;
|
||||
blks[2] = raw & 0xffffffff;
|
||||
return VIKING_T55XX_BLOCK_COUNT;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "protocols.h"
|
||||
|
||||
extern const protocol viking;
|
||||
|
||||
uint8_t viking_t55xx_writer(uint8_t* uid, uint32_t* blks);
|
||||
@@ -45,6 +45,7 @@ typedef enum {
|
||||
// Presco
|
||||
// Visa2000
|
||||
// Viking
|
||||
TAG_TYPE_VIKING = 170,
|
||||
// Noralsy
|
||||
// Jablotron
|
||||
|
||||
@@ -105,7 +106,7 @@ typedef enum {
|
||||
}
|
||||
|
||||
#define TAG_SPECIFIC_TYPE_LF_VALUES \
|
||||
TAG_TYPE_EM410X, TAG_TYPE_HID_PROX
|
||||
TAG_TYPE_EM410X, TAG_TYPE_HID_PROX, TAG_TYPE_VIKING
|
||||
|
||||
#define TAG_SPECIFIC_TYPE_HF_VALUES \
|
||||
TAG_TYPE_MIFARE_Mini, TAG_TYPE_MIFARE_1024, TAG_TYPE_MIFARE_2048, \
|
||||
|
||||
@@ -91,6 +91,7 @@ static tag_base_handler_map_t tag_base_map[] = {
|
||||
// LF tag emulation
|
||||
{TAG_SENSE_LF, TAG_TYPE_EM410X, lf_tag_data_loadcb, lf_tag_em410x_data_savecb, lf_tag_em410x_data_factory, &m_tag_data_lf},
|
||||
{TAG_SENSE_LF, TAG_TYPE_HID_PROX, lf_tag_data_loadcb, lf_tag_hidprox_data_savecb, lf_tag_hidprox_data_factory, &m_tag_data_lf},
|
||||
{TAG_SENSE_LF, TAG_TYPE_VIKING, lf_tag_data_loadcb, lf_tag_viking_data_savecb, lf_tag_viking_data_factory, &m_tag_data_lf},
|
||||
// MF1 tag emulation
|
||||
{TAG_SENSE_HF, TAG_TYPE_MIFARE_Mini, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf},
|
||||
{TAG_SENSE_HF, TAG_TYPE_MIFARE_1024, nfc_tag_mf1_data_loadcb, nfc_tag_mf1_data_savecb, nfc_tag_mf1_data_factory, &m_tag_data_hf},
|
||||
|
||||
@@ -20,6 +20,7 @@ void clear_lf_counter_value(void);
|
||||
|
||||
bool em410x_read(uint8_t *data, uint32_t timeout_ms);
|
||||
bool hidprox_read(uint8_t *data, uint8_t format_hint, uint32_t timeout_ms);
|
||||
bool viking_read(uint8_t *data, uint32_t timeout_ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "protocols/em410x.h"
|
||||
#include "protocols/hidprox.h"
|
||||
#include "protocols/t55xx.h"
|
||||
#include "protocols/viking.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME lf_main
|
||||
#include "nrf_log.h"
|
||||
@@ -38,6 +39,16 @@ uint8_t scan_hidprox(uint8_t *data, uint8_t format_hint) {
|
||||
return STATUS_LF_TAG_NO_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search Viking tag
|
||||
*/
|
||||
uint8_t scan_viking(uint8_t *uid) {
|
||||
if (viking_read(uid, g_timeout_readem_ms)) {
|
||||
return STATUS_LF_TAG_OK;
|
||||
}
|
||||
return STATUS_LF_TAG_NO_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try reset t55XX tag passwords by enumerating old passwords.
|
||||
*/
|
||||
@@ -98,6 +109,18 @@ uint8_t write_hidprox_to_t55xx(uint8_t format, uint32_t fc, uint64_t cn, uint32_
|
||||
return write_t55xx(blks, blk_count, new_passwd, old_passwds, old_passwd_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write viking card data to t55xx
|
||||
*/
|
||||
uint8_t write_viking_to_t55xx(uint8_t *uid, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count) {
|
||||
uint32_t blks[7] = {0x00};
|
||||
uint8_t blk_count = viking_t55xx_writer(uid, blks);
|
||||
if (blk_count == 0) {
|
||||
return STATUS_PAR_ERR;
|
||||
}
|
||||
return write_t55xx(blks, blk_count, new_passwd, old_passwds, old_passwd_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the LF card scanning timeout value (in milliseconds).
|
||||
*/
|
||||
|
||||
@@ -10,5 +10,7 @@
|
||||
void set_scan_tag_timeout(uint32_t ms);
|
||||
uint8_t scan_em410x(uint8_t *uid);
|
||||
uint8_t scan_hidprox(uint8_t *uid, uint8_t format_hint);
|
||||
uint8_t scan_viking(uint8_t *uid);
|
||||
uint8_t write_em410x_to_t55xx(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count);
|
||||
uint8_t write_hidprox_to_t55xx(uint8_t format, uint32_t fc, uint64_t cn, uint32_t il, uint32_t oem, uint8_t *new_passwd, uint8_t *old_passwds, uint8_t old_passwd_count);
|
||||
uint8_t write_viking_to_t55xx(uint8_t *uid, uint8_t *newkey, uint8_t *old_keys, uint8_t old_key_count);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "lf_reader_data.h"
|
||||
|
||||
#include "bsp_delay.h"
|
||||
#include "bsp_time.h"
|
||||
#include "circular_buffer.h"
|
||||
#include "lf_125khz_radio.h"
|
||||
#include "lf_reader_data.h"
|
||||
#include "protocols/viking.h"
|
||||
#include "protocols/protocols.h"
|
||||
|
||||
#define NRF_LOG_MODULE_NAME viking_reader
|
||||
#include "nrf_log.h"
|
||||
#include "nrf_log_ctrl.h"
|
||||
#include "nrf_log_default_backends.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define VIKING_BUFFER_SIZE (128)
|
||||
|
||||
static circular_buffer cb;
|
||||
|
||||
// GPIO interrupt recovery function is used to detect the descending edge
|
||||
static void viking_gpio_int0_cb(void) {
|
||||
uint32_t cntr = get_lf_counter_value();
|
||||
uint16_t val = 0;
|
||||
if (cntr > 0xff) {
|
||||
val = 0xff;
|
||||
} else {
|
||||
val = cntr & 0xff;
|
||||
}
|
||||
cb_push_back(&cb, &val);
|
||||
clear_lf_counter_value();
|
||||
}
|
||||
|
||||
static void init_viking_hw(void) {
|
||||
register_rio_callback(viking_gpio_int0_cb);
|
||||
lf_125khz_radio_gpiote_enable();
|
||||
}
|
||||
|
||||
static void uninit_viking_hw(void) {
|
||||
lf_125khz_radio_gpiote_disable();
|
||||
unregister_rio_callback();
|
||||
}
|
||||
|
||||
bool viking_read(uint8_t *data, uint32_t timeout_ms) {
|
||||
void *codec = viking.alloc();
|
||||
viking.decoder.start(codec, 0);
|
||||
|
||||
cb_init(&cb, VIKING_BUFFER_SIZE, sizeof(uint16_t));
|
||||
init_viking_hw();
|
||||
start_lf_125khz_radio();
|
||||
|
||||
bool ok = false;
|
||||
autotimer *p_at = bsp_obtain_timer(0);
|
||||
while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms)) {
|
||||
uint16_t val = 0;
|
||||
while (!ok && NO_TIMEOUT_1MS(p_at, timeout_ms) && cb_pop_front(&cb, &val)) {
|
||||
if (viking.decoder.feed(codec, val)) {
|
||||
memcpy(data, viking.get_data(codec), viking.data_size);
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bsp_return_timer(p_at);
|
||||
stop_lf_125khz_radio();
|
||||
uninit_viking_hw();
|
||||
cb_free(&cb);
|
||||
|
||||
viking.free(codec);
|
||||
return ok;
|
||||
}
|
||||
@@ -494,6 +494,25 @@ class LFHIDIdReadArgsUnit(DeviceRequiredUnit):
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
raise NotImplementedError()
|
||||
|
||||
class LFVikingIdArgsUnit(DeviceRequiredUnit):
|
||||
@staticmethod
|
||||
def add_card_arg(parser: ArgumentParserNoExit, required=False):
|
||||
parser.add_argument("--id", type=str, required=required, help="Viking tag id", metavar="<hex>")
|
||||
return parser
|
||||
|
||||
def before_exec(self, args: argparse.Namespace):
|
||||
if not super().before_exec(args):
|
||||
return False
|
||||
if args.id is None or not re.match(r"^[a-fA-F0-9]{8}$", args.id):
|
||||
raise ArgsParserError("ID must include 8 HEX symbols")
|
||||
return True
|
||||
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
raise NotImplementedError("Please implement this")
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
raise NotImplementedError("Please implement this")
|
||||
|
||||
class TagTypeArgsUnit(DeviceRequiredUnit):
|
||||
@staticmethod
|
||||
def add_type_args(parser: ArgumentParserNoExit):
|
||||
@@ -525,7 +544,7 @@ lf_em = lf.subgroup('em', 'EM commands')
|
||||
lf_em_410x = lf_em.subgroup('410x', 'EM410x commands')
|
||||
lf_hid = lf.subgroup('hid', 'HID commands')
|
||||
lf_hid_prox = lf_hid.subgroup('prox', 'HID Prox commands')
|
||||
|
||||
lf_viking = lf.subgroup('viking', 'Viking commands')
|
||||
|
||||
@root.command('clear')
|
||||
class RootClear(BaseCLIUnit):
|
||||
@@ -3206,6 +3225,30 @@ class LFHIDProxEconfig(SlotIndexArgsAndGoUnit, LFHIDIdArgsUnit):
|
||||
print(f" OEM: {CG}{oem}{C0}")
|
||||
print(f" CN: {CG}{cn}{C0}")
|
||||
|
||||
@lf_viking.command('read')
|
||||
class LFVikingRead(ReaderRequiredUnit):
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.description = 'Scan Viking tag and print id'
|
||||
return parser
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
id = self.cmd.viking_scan()
|
||||
print(f"Viking: {CG}{id.hex()}{C0}")
|
||||
|
||||
|
||||
@lf_viking.command('write')
|
||||
class LFVikingWriteT55xx(LFVikingIdArgsUnit, ReaderRequiredUnit):
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.description = 'Write Viking id to t55xx'
|
||||
return self.add_card_arg(parser, required=True)
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
id_hex = args.id
|
||||
id_bytes = bytes.fromhex(id_hex)
|
||||
self.cmd.viking_write_to_t55xx(id_bytes)
|
||||
print(f" - Viking ID(8H): {id_hex} write done.")
|
||||
|
||||
@hw_slot.command('list')
|
||||
class HWSlotList(DeviceRequiredUnit):
|
||||
@@ -3327,6 +3370,9 @@ class HWSlotList(DeviceRequiredUnit):
|
||||
if oem > 0:
|
||||
print(f' {"OEM:":40}{CY}{oem}{C0}')
|
||||
print(f' {"CN:":40}{CY}{cn}{C0}')
|
||||
if lf_tag_type == TagSpecificType.Viking:
|
||||
id = self.cmd.viking_get_emu_id()
|
||||
print(f' {"ID:":40}{CY}{id.hex().upper()}{C0}')
|
||||
if current != selected:
|
||||
self.cmd.set_active_slot(selected)
|
||||
|
||||
@@ -3463,6 +3509,28 @@ class LFEM410xEconfig(SlotIndexArgsAndGoUnit, LFEMIdArgsUnit):
|
||||
print(' - Get em410x tag id success.')
|
||||
print(f'ID: {response.hex()}')
|
||||
|
||||
@lf_viking.command('econfig')
|
||||
class LFVikingEconfig(SlotIndexArgsAndGoUnit, LFVikingIdArgsUnit):
|
||||
def args_parser(self) -> ArgumentParserNoExit:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.description = 'Set emulated Viking card id'
|
||||
self.add_slot_args(parser)
|
||||
self.add_card_arg(parser)
|
||||
return parser
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
if args.id is not None:
|
||||
slotinfo = self.cmd.get_slot_info()
|
||||
selected = SlotNumber.from_fw(self.cmd.get_active_slot())
|
||||
lf_tag_type = TagSpecificType(slotinfo[selected - 1]['lf'])
|
||||
if lf_tag_type != TagSpecificType.Viking:
|
||||
print(f"{CR}WARNING{C0}: Slot type not set to Viking.")
|
||||
self.cmd.viking_set_emu_id(bytes.fromhex(args.id))
|
||||
print(' - Set Viking tag id success.')
|
||||
else:
|
||||
response = self.cmd.viking_get_emu_id()
|
||||
print(' - Get Viking tag id success.')
|
||||
print(f'ID: {response.hex().upper()}')
|
||||
|
||||
@hw_slot.command('nick')
|
||||
class HWSlotNick(SlotIndexArgsUnit, SenseTypeArgsUnit):
|
||||
|
||||
@@ -475,6 +475,31 @@ class ChameleonCMD:
|
||||
data = struct.pack(f'!13s4s{4*len(old_keys)}s', id_bytes, new_key, b''.join(old_keys))
|
||||
return self.device.send_cmd_sync(Command.HIDPROX_WRITE_TO_T55XX, data)
|
||||
|
||||
@expect_response(Status.LF_TAG_OK)
|
||||
def viking_scan(self):
|
||||
"""
|
||||
Read the card number of Viking.
|
||||
|
||||
:return:
|
||||
"""
|
||||
resp = self.device.send_cmd_sync(Command.VIKING_SCAN)
|
||||
if resp.status == Status.LF_TAG_OK:
|
||||
resp.parsed = resp.data # uid
|
||||
return resp
|
||||
|
||||
@expect_response(Status.LF_TAG_OK)
|
||||
def viking_write_to_t55xx(self, id_bytes: bytes):
|
||||
"""
|
||||
Write Viking card number into T55XX.
|
||||
|
||||
:param id_bytes: ID card number
|
||||
:return:
|
||||
"""
|
||||
if len(id_bytes) != 4:
|
||||
raise ValueError("The id bytes length must equal 4")
|
||||
data = struct.pack(f'!4s4s{4*len(old_keys)}s', id_bytes, new_key, b''.join(old_keys))
|
||||
return self.device.send_cmd_sync(Command.VIKING_WRITE_TO_T55XX, data)
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def get_slot_info(self):
|
||||
"""
|
||||
@@ -610,6 +635,28 @@ class ChameleonCMD:
|
||||
resp.parsed = struct.unpack('>BIBIBH', resp.data[:13])
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def viking_set_emu_id(self, id: bytes):
|
||||
"""
|
||||
Set the card number emulated by Viking.
|
||||
|
||||
:param id_bytes: byte of the card number
|
||||
:return:
|
||||
"""
|
||||
if len(id) != 4:
|
||||
raise ValueError("The id bytes length must equal 4")
|
||||
data = struct.pack('4s', id)
|
||||
return self.device.send_cmd_sync(Command.VIKING_SET_EMU_ID, data)
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def viking_get_emu_id(self):
|
||||
"""
|
||||
Get the emulated Viking card id
|
||||
"""
|
||||
resp = self.device.send_cmd_sync(Command.VIKING_GET_EMU_ID)
|
||||
resp.parsed = resp.data
|
||||
return resp
|
||||
|
||||
@expect_response(Status.SUCCESS)
|
||||
def mf1_set_detection_enable(self, enabled: bool):
|
||||
"""
|
||||
|
||||
@@ -78,6 +78,8 @@ class Command(enum.IntEnum):
|
||||
EM410X_WRITE_TO_T55XX = 3001
|
||||
HIDPROX_SCAN = 3002
|
||||
HIDPROX_WRITE_TO_T55XX = 3003
|
||||
VIKING_SCAN = 3004
|
||||
VIKING_WRITE_TO_T55XX = 3005
|
||||
|
||||
MF1_WRITE_EMU_BLOCK_DATA = 4000
|
||||
HF14A_SET_ANTI_COLL_DATA = 4001
|
||||
@@ -126,6 +128,8 @@ class Command(enum.IntEnum):
|
||||
EM410X_GET_EMU_ID = 5001
|
||||
HIDPROX_SET_EMU_ID = 5002
|
||||
HIDPROX_GET_EMU_ID = 5003
|
||||
VIKING_SET_EMU_ID = 5004
|
||||
VIKING_GET_EMU_ID = 5005
|
||||
|
||||
|
||||
@enum.unique
|
||||
@@ -260,7 +264,7 @@ class TagSpecificType(enum.IntEnum):
|
||||
# PAC/Stanley
|
||||
# Presco
|
||||
# Visa2000
|
||||
# Viking
|
||||
Viking = 170
|
||||
# Noralsy
|
||||
# Jablotron
|
||||
|
||||
@@ -347,6 +351,8 @@ class TagSpecificType(enum.IntEnum):
|
||||
return "EM410X/64"
|
||||
elif self == TagSpecificType.HIDProx:
|
||||
return "HIDProx"
|
||||
elif self == TagSpecificType.Viking:
|
||||
return "Viking"
|
||||
elif self == TagSpecificType.MIFARE_Mini:
|
||||
return "Mifare Mini"
|
||||
elif self == TagSpecificType.MIFARE_1024:
|
||||
|
||||
Reference in New Issue
Block a user