mirror of
https://github.com/RfidResearchGroup/ChameleonUltra.git
synced 2026-05-12 11:22:59 -07:00
hw 14a raw: closer to pm3 syntax, removed bit_frame,...
Now data length is always in bits Option -o => -a and only needed to turn field on without select or data Reorganize pcd_14a_reader_raw_cmd Some more checks
This commit is contained in:
@@ -251,6 +251,17 @@ Notes:
|
||||
* Command: 24 bytes: `type|block|key[6]|block_data[16]`. Key as 6 bytes.
|
||||
* Response: no data
|
||||
* CLI: cf `hf mf wrbl`
|
||||
### 2010: HF14A_RAW
|
||||
* Command: : 5+N bytes: `options|resp_timeout_ms[2]|bitlen[2]` followed by data to be transmitted, with `options` a 1-byte BigEndian bitfield, so starting from MSB:
|
||||
* `activate_rf_field`:1
|
||||
* `wait_response`:1
|
||||
* `append_crc`:1
|
||||
* `auto_select`:1
|
||||
* `keep_rf_field`:1
|
||||
* `check_response_crc`:1
|
||||
* `reserved`:2
|
||||
* Response: data sent by the card
|
||||
* CLI: cf `hf 14a raw`
|
||||
### 3000: EM410X_SCAN
|
||||
* Command: no data
|
||||
* Response: 5 bytes. `id[5]`. ID as 5 bytes.
|
||||
@@ -356,6 +367,7 @@ Be verbose, explicit and reuse conventions, in order to enhance code maintainabi
|
||||
### Guideline: Structs
|
||||
- Define C `struct` for cmd/resp data greater than a single byte, use and abuse of `struct.pack`/`struct.unpack` in Python. So one can understand the payload format at a simple glimpse. Exceptions to `C` struct are when the formats are of variable length (but Python `struct` is still flexible enough to cope with such formats!)
|
||||
- Avoid hardcoding offsets, use `sizeof()`, `offsetof(struct, field)` in C and `struct.calcsize()` in Python
|
||||
- For complex bitfield structs, exceptionally you can use ctypes in Python. Beware ctypes.BigEndianStructure bitfield will be parsed in the firmware in the reverse order, from LSB to MSB.
|
||||
### Guideline: Status
|
||||
If single byte of data to return, still use a 1-byte `data`, not `status`. Standard response status is `STATUS_DEVICE_SUCCESS` for general commands, `HF_TAG_OK` for HF commands and `LF_TAG_OK` for LF commands. If the response status is different than those, the response data is empty. Response status are generic and cover things like tag disappearance or tag non-conformities with the ISO standard. If a command needs more specific response status, it is added in the first byte of the data, to avoid cluttering the 1-byte general status enum with command-specific statuses. See e.g. [MF1_DARKSIDE_ACQUIRE](#2004-mf1_darkside_acquire).
|
||||
### Guideline: unambiguous types
|
||||
|
||||
@@ -404,21 +404,20 @@ static data_frame_tx_t *cmd_processor_hf14a_raw(uint16_t cmd, uint16_t status, u
|
||||
uint16_t resp_length = 0;
|
||||
|
||||
typedef struct {
|
||||
struct { // MSB -> LSB
|
||||
uint8_t reserved : 1;
|
||||
struct { // LSB -> MSB
|
||||
uint8_t reserved : 2;
|
||||
|
||||
uint8_t check_response_crc : 1;
|
||||
uint8_t keep_rf_field : 1;
|
||||
uint8_t auto_select : 1;
|
||||
uint8_t bit_frame : 1;
|
||||
uint8_t append_crc : 1;
|
||||
uint8_t wait_response : 1;
|
||||
uint8_t open_rf_field : 1;
|
||||
uint8_t activate_rf_field : 1;
|
||||
} options;
|
||||
|
||||
// U16NTOHS
|
||||
uint16_t resp_timeout;
|
||||
uint16_t data_length;
|
||||
uint16_t data_bitlength;
|
||||
|
||||
uint8_t data_buffer[0]; // We can have a lot of data or no data. struct just to compute offsets with min options.
|
||||
} PACKED payload_t;
|
||||
@@ -427,27 +426,25 @@ static data_frame_tx_t *cmd_processor_hf14a_raw(uint16_t cmd, uint16_t status, u
|
||||
return data_frame_make(cmd, STATUS_PAR_ERR, 0, NULL);
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("open_rf_field = %d", payload->options.open_rf_field);
|
||||
NRF_LOG_INFO("activate_rf_field = %d", payload->options.activate_rf_field);
|
||||
NRF_LOG_INFO("wait_response = %d", payload->options.wait_response);
|
||||
NRF_LOG_INFO("append_crc = %d", payload->options.append_crc);
|
||||
NRF_LOG_INFO("bit_frame = %d", payload->options.bit_frame);
|
||||
NRF_LOG_INFO("auto_select = %d", payload->options.auto_select);
|
||||
NRF_LOG_INFO("keep_rf_field = %d", payload->options.keep_rf_field);
|
||||
NRF_LOG_INFO("check_response_crc = %d", payload->options.check_response_crc);
|
||||
NRF_LOG_INFO("reserved = %d", payload->options.reserved);
|
||||
|
||||
status = pcd_14a_reader_raw_cmd(
|
||||
payload->options.open_rf_field,
|
||||
payload->options.activate_rf_field,
|
||||
payload->options.wait_response,
|
||||
payload->options.append_crc,
|
||||
payload->options.bit_frame,
|
||||
payload->options.auto_select,
|
||||
payload->options.keep_rf_field,
|
||||
payload->options.check_response_crc,
|
||||
|
||||
U16NTOHS(payload->resp_timeout),
|
||||
|
||||
U16NTOHS(payload->data_length),
|
||||
U16NTOHS(payload->data_bitlength),
|
||||
payload->data_buffer,
|
||||
|
||||
resp,
|
||||
|
||||
@@ -1132,7 +1132,6 @@ inline void pcd_14a_reader_crc_computer(uint8_t use522CalcCRC) {
|
||||
* @brief : The hf 14a raw command implementation function can be used to send the 14A command with the specified configuration parameters.
|
||||
* @param :waitResp : Wait for tag response
|
||||
* @param :appendCrc : Do you want to add CRC before sending
|
||||
* @param :bitsFrame : Is it necessary to send bit frames, which are mutually exclusive with the appendCrc parameter.
|
||||
* @param :autoSelect : Automatically select card before sending data
|
||||
* @param :keepField : Do you want to keep the RF field on after sending
|
||||
* @param :checkCrc : Is CRC verified after receiving data? If CRC verification is enabled, CRC bytes will be automatically removed after verification is completed.
|
||||
@@ -1143,122 +1142,125 @@ inline void pcd_14a_reader_crc_computer(uint8_t use522CalcCRC) {
|
||||
* @retval : Execution Status
|
||||
*
|
||||
*/
|
||||
uint8_t pcd_14a_reader_raw_cmd(bool openRFField, bool waitResp, bool appendCrc, bool bitsFrame, bool autoSelect, bool keepField, bool checkCrc, uint16_t waitRespTimeout,
|
||||
uint16_t szDataSend, uint8_t *pDataSend, uint8_t *pDataRecv, uint16_t *pszDataRecv, uint16_t szDataRecvBitMax) {
|
||||
// Status code, default is OK.
|
||||
uint8_t status = HF_TAG_OK;
|
||||
// Reset recv length.
|
||||
*pszDataRecv = 0;
|
||||
// Old response timeout.
|
||||
uint16_t oldWaitRespTimeout;
|
||||
uint8_t pcd_14a_reader_raw_cmd(bool openRFField, bool waitResp, bool appendCrc, bool autoSelect, bool keepField, bool checkCrc, uint16_t waitRespTimeout,
|
||||
uint16_t szDataSendBits, uint8_t *pDataSend, uint8_t *pDataRecv, uint16_t *pszDataRecv, uint16_t szDataRecvBitMax) {
|
||||
// Status code, default is OK.
|
||||
uint8_t status = HF_TAG_OK;
|
||||
// Reset recv length.
|
||||
*pszDataRecv = 0;
|
||||
|
||||
if (openRFField) { // Open rf filed?
|
||||
// If additional CRC is required, first add the CRC to the tail.
|
||||
if (appendCrc) {
|
||||
if (szDataSendBits == 0) {
|
||||
NRF_LOG_INFO("Adding CRC but missing data");
|
||||
return STATUS_PAR_ERR;
|
||||
}
|
||||
if (szDataSendBits % 8) {
|
||||
NRF_LOG_INFO("Adding CRC incompatible with partial bytes");
|
||||
return STATUS_PAR_ERR;
|
||||
}
|
||||
if (szDataSendBits > ((DEF_FIFO_LENGTH - DEF_CRC_LENGTH) * 8)) {
|
||||
// Note: Adding CRC requires at least two bytes of free space. If the transmitted data is already greater than or equal to 64, an error needs to be returned
|
||||
NRF_LOG_INFO("Adding CRC requires data length less than or equal to 62.");
|
||||
return STATUS_PAR_ERR;
|
||||
}
|
||||
// Calculate and append CRC byte data to the buffer
|
||||
crc_14a_append(pDataSend, szDataSendBits / 8);
|
||||
// CRC is also sent as part of the data, so the total length needs to be added to the CRC length here
|
||||
szDataSendBits += DEF_CRC_LENGTH * 8;
|
||||
}
|
||||
|
||||
if (autoSelect || szDataSendBits) {
|
||||
// override openRFField if we need to select or to send data
|
||||
openRFField = true;
|
||||
}
|
||||
if (openRFField && ! g_is_reader_antenna_on) { // Open rf field?
|
||||
pcd_14a_reader_reset();
|
||||
pcd_14a_reader_antenna_on();
|
||||
bsp_delay_ms(8);
|
||||
}
|
||||
|
||||
// Is there any data that needs to be sent
|
||||
if (szDataSend > 0) {
|
||||
// If additional CRC is required, first add the CRC to the tail.
|
||||
if (appendCrc) {
|
||||
// Note: Adding CRC requires at least two bytes of free space. If the transmitted data is already greater than or equal to 64, an error needs to be returned
|
||||
if (szDataSend > (DEF_FIFO_LENGTH - DEF_CRC_LENGTH)) {
|
||||
NRF_LOG_INFO("Adding CRC requires data length less than or equal to 62.");
|
||||
status = STATUS_PAR_ERR;
|
||||
} else {
|
||||
// Calculate and append CRC byte data to the buffer
|
||||
crc_14a_append(pDataSend, szDataSend);
|
||||
// CRC is also sent as part of the data, so the total length needs to be added to the CRC length here
|
||||
szDataSend += DEF_CRC_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the previous operation is normal
|
||||
if (status == HF_TAG_OK) {
|
||||
// Determine if card selection is necessary first based on needs
|
||||
if (autoSelect) {
|
||||
picc_14a_tag_t ti;
|
||||
status = pcd_14a_reader_scan_once(&ti);
|
||||
// Determine whether the card search was successful
|
||||
if (status != HF_TAG_OK) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no need to receive data, the data receiving cache needs to be empty, otherwise a specified timeout value needs to be set
|
||||
if (waitResp) {
|
||||
// Caching old timeout values
|
||||
oldWaitRespTimeout = g_com_timeout_ms;
|
||||
// Then set the new values in
|
||||
g_com_timeout_ms = waitRespTimeout;
|
||||
} else {
|
||||
pDataRecv = NULL;
|
||||
}
|
||||
|
||||
// Ensure that the previous operation is normal
|
||||
if (status == HF_TAG_OK) {
|
||||
if (bitsFrame) {
|
||||
status = pcd_14a_reader_bits_transfer(
|
||||
pDataSend,
|
||||
szDataSend,
|
||||
NULL,
|
||||
pDataRecv,
|
||||
NULL,
|
||||
pszDataRecv,
|
||||
szDataRecvBitMax
|
||||
);
|
||||
} else {
|
||||
status = pcd_14a_reader_bytes_transfer(
|
||||
PCD_TRANSCEIVE,
|
||||
pDataSend,
|
||||
szDataSend,
|
||||
pDataRecv,
|
||||
pszDataRecv,
|
||||
szDataRecvBitMax
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we need to receive data, we need to perform further operations on the data based on the remaining configuration after receiving it
|
||||
if (waitResp) {
|
||||
// Number of bits to bytes
|
||||
uint8_t finalRecvBytes = (*pszDataRecv / 8) + (*pszDataRecv % 8 > 0 ? 1 : 0);
|
||||
// If CRC verification is required, we need to perform CRC calculation
|
||||
if (checkCrc) {
|
||||
if (finalRecvBytes >= 3) { // Ensure at least three bytes (one byte of data+two bytes of CRC)
|
||||
// Calculate and store CRC
|
||||
uint8_t crc_buff[DEF_CRC_LENGTH] = { 0x00 };
|
||||
crc_14a_calculate(pDataRecv, finalRecvBytes - DEF_CRC_LENGTH, crc_buff);
|
||||
// Verify CRC
|
||||
if (pDataRecv[finalRecvBytes - 2] != crc_buff[0] || pDataRecv[finalRecvBytes - 1] != crc_buff[1]) {
|
||||
// We have found an error in CRC verification and need to inform the upper computer!
|
||||
*pszDataRecv = 0;
|
||||
status = HF_ERR_CRC;
|
||||
} else {
|
||||
// If the CRC needs to be verified by the device and the device determines that the CRC is normal,
|
||||
// we will return the data without CRC
|
||||
*pszDataRecv = finalRecvBytes - DEF_CRC_LENGTH;
|
||||
}
|
||||
} else {
|
||||
// The data is insufficient to support the length of the CRC, so it is returned as is
|
||||
*pszDataRecv = 0;
|
||||
}
|
||||
} else {
|
||||
// Do not verify CRC, all data is returned as is
|
||||
*pszDataRecv = finalRecvBytes;
|
||||
}
|
||||
// We need to recover the timeout value
|
||||
g_com_timeout_ms = oldWaitRespTimeout;
|
||||
} else {
|
||||
*pszDataRecv = 0;
|
||||
}
|
||||
if (autoSelect) {
|
||||
picc_14a_tag_t ti;
|
||||
status = pcd_14a_reader_scan_once(&ti);
|
||||
// Determine whether the card search was successful
|
||||
if (status != HF_TAG_OK) {
|
||||
pcd_14a_reader_antenna_off();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, keep the field open as needed
|
||||
if (!keepField) {
|
||||
pcd_14a_reader_antenna_off();
|
||||
}
|
||||
|
||||
return status;
|
||||
// Is there any data that needs to be sent
|
||||
if (szDataSendBits) {
|
||||
// If there is no need to receive data, the data receiving cache needs to be empty, otherwise a specified timeout value needs to be set
|
||||
// Caching old timeout values
|
||||
uint16_t oldWaitRespTimeout = g_com_timeout_ms;
|
||||
if (waitResp) {
|
||||
// Then set the new values in
|
||||
g_com_timeout_ms = waitRespTimeout;
|
||||
} else {
|
||||
pDataRecv = NULL;
|
||||
}
|
||||
if (szDataSendBits % 8) {
|
||||
status = pcd_14a_reader_bits_transfer(
|
||||
pDataSend,
|
||||
szDataSendBits,
|
||||
NULL,
|
||||
pDataRecv,
|
||||
NULL,
|
||||
pszDataRecv,
|
||||
szDataRecvBitMax
|
||||
);
|
||||
} else {
|
||||
status = pcd_14a_reader_bytes_transfer(
|
||||
PCD_TRANSCEIVE,
|
||||
pDataSend,
|
||||
szDataSendBits / 8,
|
||||
pDataRecv,
|
||||
pszDataRecv,
|
||||
szDataRecvBitMax
|
||||
);
|
||||
}
|
||||
|
||||
// If we need to receive data, we need to perform further operations on the data based on the remaining configuration after receiving it
|
||||
if (waitResp) {
|
||||
// Number of bits to bytes
|
||||
uint8_t finalRecvBytes = (*pszDataRecv / 8) + (*pszDataRecv % 8 > 0 ? 1 : 0);
|
||||
// If CRC verification is required, we need to perform CRC calculation
|
||||
if (checkCrc) {
|
||||
if (finalRecvBytes >= 3) { // Ensure at least three bytes (one byte of data+two bytes of CRC)
|
||||
// Calculate and store CRC
|
||||
uint8_t crc_buff[DEF_CRC_LENGTH] = { 0x00 };
|
||||
crc_14a_calculate(pDataRecv, finalRecvBytes - DEF_CRC_LENGTH, crc_buff);
|
||||
// Verify CRC
|
||||
if (pDataRecv[finalRecvBytes - 2] != crc_buff[0] || pDataRecv[finalRecvBytes - 1] != crc_buff[1]) {
|
||||
// We have found an error in CRC verification and need to inform the upper computer!
|
||||
*pszDataRecv = 0;
|
||||
status = HF_ERR_CRC;
|
||||
} else {
|
||||
// If the CRC needs to be verified by the device and the device determines that the CRC is normal,
|
||||
// we will return the data without CRC
|
||||
*pszDataRecv = finalRecvBytes - DEF_CRC_LENGTH;
|
||||
}
|
||||
} else {
|
||||
// The data is insufficient to support the length of the CRC, so it is returned as is
|
||||
*pszDataRecv = 0;
|
||||
}
|
||||
} else {
|
||||
// Do not verify CRC, all data is returned as is
|
||||
*pszDataRecv = finalRecvBytes;
|
||||
}
|
||||
// We need to recover the timeout value
|
||||
g_com_timeout_ms = oldWaitRespTimeout;
|
||||
} else {
|
||||
*pszDataRecv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, keep the field open as needed
|
||||
if (!keepField) {
|
||||
pcd_14a_reader_antenna_off();
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -220,8 +220,8 @@ uint8_t pcd_14a_reader_mf1_read(uint8_t addr, uint8_t *pData);
|
||||
uint8_t pcd_14a_reader_halt_tag(void);
|
||||
void pcd_14a_reader_fast_halt_tag(void);
|
||||
|
||||
uint8_t pcd_14a_reader_raw_cmd(bool openRFField, bool waitResp, bool appendCrc, bool bitsFrame, bool autoSelect, bool keepField, bool checkCrc, uint16_t waitRespTimeout,
|
||||
uint16_t szDataSend, uint8_t* pDataSend, uint8_t* pDataRecv, uint16_t* pszDataRecv, uint16_t szDataRecvBitMax);
|
||||
uint8_t pcd_14a_reader_raw_cmd(bool openRFField, bool waitResp, bool appendCrc, bool autoSelect, bool keepField, bool checkCrc, uint16_t waitRespTimeout,
|
||||
uint16_t szDataSendBits, uint8_t* pDataSend, uint8_t* pDataRecv, uint16_t* pszDataRecv, uint16_t szDataRecvBitMax);
|
||||
|
||||
// UID & UFUID tag operation
|
||||
uint8_t pcd_14a_reader_gen1a_unlock(void);
|
||||
|
||||
@@ -1589,26 +1589,34 @@ class HF14ARaw(ReaderRequiredUnit):
|
||||
|
||||
def args_parser(self) -> ArgumentParserNoExit or None:
|
||||
parser = ArgumentParserNoExit()
|
||||
parser.add_argument('-r', '--response', help="do not read response", action='store_true', default=False,)
|
||||
parser.add_argument('-c', '--crc', help="calculate and append CRC", action='store_true', default=False,)
|
||||
parser.add_argument('-cc', '--crc-clear', help="Verify and clear CRC of received data", action='store_true', default=False,)
|
||||
parser.add_argument('-k', '--keep-rf', help="keep signal field ON after receive", action='store_true', default=False,)
|
||||
parser.add_argument('-o', '--open-rf', help="active signal field ON", action='store_true', default=False,)
|
||||
parser.add_argument('-s', '--select-tag', help="Select the tag before executing the command", action='store_true', default=False,)
|
||||
parser.add_argument('-b', '--bits', type=int, help="number of bits to send. Useful for send partial byte")
|
||||
parser.add_argument('-t', '--timeout', type=int, help="timeout in ms", default=100)
|
||||
parser.add_argument('-a', '--activate-rf', help="Active signal field ON without select", action='store_true', default=False,)
|
||||
parser.add_argument('-s', '--select-tag', help="Active signal field ON with select", action='store_true', default=False,)
|
||||
# TODO: parser.add_argument('-3', '--type3-select-tag', help="Active signal field ON with ISO14443-3 select (no RATS)", action='store_true', default=False,)
|
||||
parser.add_argument('-d', '--data', type=str, help="Data to be sent")
|
||||
parser.add_argument('-b', '--bits', type=int, help="Number of bits to send. Useful for send partial byte")
|
||||
parser.add_argument('-c', '--crc', help="Calculate and append CRC", action='store_true', default=False,)
|
||||
parser.add_argument('-r', '--response', help="Do not read response", action='store_true', default=False,)
|
||||
parser.add_argument('-cc', '--crc-clear', help="Verify and clear CRC of received data", action='store_true', default=False,)
|
||||
parser.add_argument('-k', '--keep-rf', help="Keep signal field ON after receive", action='store_true', default=False,)
|
||||
parser.add_argument('-t', '--timeout', type=int, help="Timeout in ms", default=100)
|
||||
# TODO: need support for carriage returns in parser, why are they mangled?
|
||||
# parser.description = 'Examples:\n' \
|
||||
# ' hf 14a raw -b 7 -d 40 -k\n' \
|
||||
# ' hf 14a raw -d 43 -k\n' \
|
||||
# ' hf 14a raw -d 3000 -c\n' \
|
||||
# ' hf 14a raw -sc -d 6000\n'
|
||||
return parser
|
||||
|
||||
|
||||
def on_exec(self, args: argparse.Namespace):
|
||||
options = {
|
||||
'open_rf_field': self.bool_to_bit(args.open_rf),
|
||||
'wait_response': self.bool_to_bit(args.response == False),
|
||||
'activate_rf_field': self.bool_to_bit(args.activate_rf),
|
||||
'wait_response': self.bool_to_bit(not args.response),
|
||||
'append_crc': self.bool_to_bit(args.crc),
|
||||
'bit_frame': self.bool_to_bit(args.bits is not None),
|
||||
'auto_select': self.bool_to_bit(args.select_tag),
|
||||
'keep_rf_field': self.bool_to_bit(args.keep_rf),
|
||||
'check_response_crc': self.bool_to_bit(args.crc_clear),
|
||||
#'auto_type3_select': self.bool_to_bit(args.type3-select-tag),
|
||||
}
|
||||
data: str = args.data
|
||||
if data is not None:
|
||||
@@ -1624,6 +1632,10 @@ class HF14ARaw(ReaderRequiredUnit):
|
||||
return
|
||||
else:
|
||||
data_bytes = []
|
||||
if args.bits is not None and args.crc:
|
||||
print(f" [!] {CR}--bits and --crc are mutually exclusive{C0}")
|
||||
return
|
||||
|
||||
# Exec 14a raw cmd.
|
||||
resp = self.cmd.hf14a_raw(options, args.timeout, data_bytes, args.bits)
|
||||
if resp.status == chameleon_status.Device.HF_TAG_OK:
|
||||
@@ -1632,9 +1644,9 @@ class HF14ARaw(ReaderRequiredUnit):
|
||||
# print head
|
||||
" - " +
|
||||
# print data
|
||||
' '.join([ hex(byte).replace('0x', '').rjust(2, '0') for byte in resp.data ])
|
||||
' '.join([hex(byte).replace('0x', '').rjust(2, '0') for byte in resp.data])
|
||||
)
|
||||
else:
|
||||
print(F" [*] {CY}No data response{C0}")
|
||||
print(F" [*] {CY}No response{C0}")
|
||||
else:
|
||||
print(f" [!] {CR}{chameleon_status.message[resp.status]}{C0} ")
|
||||
|
||||
@@ -617,7 +617,7 @@ class ChameleonCMD:
|
||||
resp.data = resp.status == chameleon_status.Device.HF_TAG_OK
|
||||
return resp
|
||||
|
||||
def hf14a_raw(self, options, resp_timeout_ms=100, data=[], bit_owned_by_the_last_byte=None):
|
||||
def hf14a_raw(self, options, resp_timeout_ms=100, data=[], bitlen=None):
|
||||
"""
|
||||
Send raw cmd to 14a tag
|
||||
:param options:
|
||||
@@ -629,40 +629,35 @@ class ChameleonCMD:
|
||||
|
||||
class CStruct(ctypes.BigEndianStructure):
|
||||
_fields_ = [
|
||||
("open_rf_field", ctypes.c_uint8, 1),
|
||||
("activate_rf_field", ctypes.c_uint8, 1),
|
||||
("wait_response", ctypes.c_uint8, 1),
|
||||
("append_crc", ctypes.c_uint8, 1),
|
||||
("bit_frame", ctypes.c_uint8, 1),
|
||||
("auto_select", ctypes.c_uint8, 1),
|
||||
("keep_rf_field", ctypes.c_uint8, 1),
|
||||
("check_response_crc", ctypes.c_uint8, 1),
|
||||
("reserved", ctypes.c_uint8, 1),
|
||||
("reserved", ctypes.c_uint8, 2),
|
||||
]
|
||||
|
||||
cs = CStruct()
|
||||
cs.open_rf_field = options['open_rf_field']
|
||||
cs.activate_rf_field = options['activate_rf_field']
|
||||
cs.wait_response = options['wait_response']
|
||||
cs.append_crc = options['append_crc']
|
||||
cs.bit_frame = options['bit_frame']
|
||||
cs.auto_select = options['auto_select']
|
||||
cs.keep_rf_field = options['keep_rf_field']
|
||||
cs.check_response_crc = options['check_response_crc']
|
||||
|
||||
if options['bit_frame'] == 1:
|
||||
bits_or_bytes = len(data) * 8 # bits = bytes * 8(bit)
|
||||
if bit_owned_by_the_last_byte is not None and bit_owned_by_the_last_byte != 8:
|
||||
bits_or_bytes = bits_or_bytes - (8 - bit_owned_by_the_last_byte)
|
||||
if bitlen is None:
|
||||
bitlen = len(data) * 8 # bits = bytes * 8(bit)
|
||||
else:
|
||||
bits_or_bytes = len(data) # bytes length
|
||||
|
||||
if len(data) > 0:
|
||||
data = struct.pack(f'!BHH{len(data)}s', bytes(cs)[0], resp_timeout_ms, bits_or_bytes, bytearray(data))
|
||||
else:
|
||||
data = struct.pack(f'!BHH', bytes(cs)[0], resp_timeout_ms, 0)
|
||||
if len(data) == 0:
|
||||
raise ValueError(f'bitlen={bitlen} but missing data')
|
||||
if not ((len(data) - 1) * 8 < bitlen <= len(data) * 8):
|
||||
raise ValueError(f'bitlen={bitlen} incompatible with provided data ({len(data)} bytes), '
|
||||
f'must be between {((len(data) - 1) * 8 )+1} and {len(data) * 8} included')
|
||||
|
||||
data = bytes(cs)+struct.pack(f'!HH{len(data)}s', resp_timeout_ms, bitlen, bytearray(data))
|
||||
return self.device.send_cmd_sync(DATA_CMD_HF14A_RAW, data, timeout=(resp_timeout_ms / 1000) + 1)
|
||||
|
||||
|
||||
@expect_response(chameleon_status.Device.HF_TAG_OK)
|
||||
def mf1_static_nested_acquire(self, block_known, type_known, key_known, block_target, type_target):
|
||||
"""
|
||||
@@ -1228,26 +1223,24 @@ def test_fn():
|
||||
cml.set_device_reader_mode()
|
||||
|
||||
options = {
|
||||
'open_rf_field': 1,
|
||||
'activate_rf_field': 1,
|
||||
'wait_response': 1,
|
||||
'append_crc': 0,
|
||||
'bit_frame': 1,
|
||||
'auto_select': 0,
|
||||
'keep_rf_field': 1,
|
||||
'check_response_crc': 0,
|
||||
}
|
||||
|
||||
# unlock 1
|
||||
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x40], bit_owned_by_the_last_byte=7)
|
||||
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x40], bitlen=7)
|
||||
|
||||
if resp.status == 0x00 and resp.data[0] == 0x0a:
|
||||
print("Gen1A unlock 1 success")
|
||||
# unlock 2
|
||||
options['bit_frame'] = 0
|
||||
resp = cml.hf14a_raw(options=options, resp_timeout_ms=1000, data=[0x43])
|
||||
if resp.status == 0x00 and resp.data[0] == 0x0a:
|
||||
print("Gen1A unlock 2 success")
|
||||
print("Start dump gen1a memeory...")
|
||||
print("Start dump gen1a memory...")
|
||||
block = 0
|
||||
while block < 64:
|
||||
# Tag read block cmd
|
||||
|
||||
Reference in New Issue
Block a user