mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
fix decoding of info in view command and turning off at select card
This commit is contained in:
parent
c880b613d6
commit
61573a014e
2 changed files with 74 additions and 56 deletions
|
@ -382,20 +382,21 @@ static int switch_off_field(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findXerox(iso14b_card_select_t *card, bool disconnect) {
|
static int xerox_select_card(iso14b_card_select_t *card) {
|
||||||
|
|
||||||
if (card == NULL) {
|
if (card == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t retry = 3;
|
int8_t retry = 2;
|
||||||
while (retry--) {
|
while (retry--) {
|
||||||
|
|
||||||
iso14b_raw_cmd_t packet = {
|
iso14b_raw_cmd_t packet = {
|
||||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | (disconnect ? ISO14B_DISCONNECT : 0)),
|
.flags = (ISO14B_CONNECT | ISO14B_SELECT_XRX | ISO14B_DISCONNECT),
|
||||||
.timeout = 0,
|
.timeout = 0,
|
||||||
.rawlen = 0,
|
.rawlen = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)&packet, sizeof(iso14b_raw_cmd_t));
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
@ -404,11 +405,12 @@ static int findXerox(iso14b_card_select_t *card, bool disconnect) {
|
||||||
if (resp.status == PM3_SUCCESS) {
|
if (resp.status == PM3_SUCCESS) {
|
||||||
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
memcpy(card, (iso14b_card_select_t *)resp.data.asBytes, sizeof(iso14b_card_select_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetISODEPState(ISODEP_NFCB);
|
||||||
return resp.length;
|
return resp.length;
|
||||||
}
|
}
|
||||||
} // retry
|
} // retry
|
||||||
|
|
||||||
// switch_off_field();
|
|
||||||
PrintAndLogEx(FAILED, "command execution timeout");
|
PrintAndLogEx(FAILED, "command execution timeout");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -420,7 +422,7 @@ static inline char dec_digit(uint8_t dig) {
|
||||||
return (dig <= 9) ? dig + '0' : '?';
|
return (dig <= 9) ? dig + '0' : '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gen_pn(const uint8_t *data, char *pn) {
|
static void xerox_generate_partno(const uint8_t *data, char *pn) {
|
||||||
pn[0] = dec_digit(data[0] >> 4);
|
pn[0] = dec_digit(data[0] >> 4);
|
||||||
pn[1] = dec_digit(data[0] & 0xF);
|
pn[1] = dec_digit(data[0] & 0xF);
|
||||||
pn[2] = dec_digit(data[1] >> 4);
|
pn[2] = dec_digit(data[1] >> 4);
|
||||||
|
@ -514,7 +516,7 @@ static const xerox_part_t xerox_part_mappings[] = {
|
||||||
// returns description of the best match
|
// returns description of the best match
|
||||||
static const xerox_part_t *get_xerox_part_info(const char* pn) {
|
static const xerox_part_t *get_xerox_part_info(const char* pn) {
|
||||||
for (int i = 0; i < ARRAYLEN(xerox_part_mappings); ++i) {
|
for (int i = 0; i < ARRAYLEN(xerox_part_mappings); ++i) {
|
||||||
if (strcmp(pn, xerox_part_mappings[i].partnumber) == 0) {
|
if (str_startswith(pn, xerox_part_mappings[i].partnumber) == 0) {
|
||||||
return &xerox_part_mappings[i];
|
return &xerox_part_mappings[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -526,7 +528,7 @@ int read_xerox_uid(bool loop, bool verbose) {
|
||||||
|
|
||||||
do {
|
do {
|
||||||
iso14b_card_select_t card;
|
iso14b_card_select_t card;
|
||||||
int status = findXerox(&card, true);
|
int status = xerox_select_card(&card);
|
||||||
|
|
||||||
if (loop) {
|
if (loop) {
|
||||||
if (status != PM3_SUCCESS) {
|
if (status != PM3_SUCCESS) {
|
||||||
|
@ -536,8 +538,8 @@ int read_xerox_uid(bool loop, bool verbose) {
|
||||||
|
|
||||||
if (status == PM3_SUCCESS) {
|
if (status == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||||
} else {
|
} else {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
|
@ -594,9 +596,8 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
iso14b_card_select_t card;
|
iso14b_card_select_t card;
|
||||||
int status = findXerox(&card, false);
|
int status = xerox_select_card(&card);
|
||||||
if (status != PM3_SUCCESS) {
|
if (status != PM3_SUCCESS) {
|
||||||
switch_off_field();
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed");
|
PrintAndLogEx(FAILED, "Fuji/Xerox tag select failed");
|
||||||
}
|
}
|
||||||
|
@ -604,32 +605,36 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(SUCCESS, " UID..... %s", sprint_hex(card.uid, card.uidlen));
|
||||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
PrintAndLogEx(SUCCESS, " ATQB.... %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||||
|
|
||||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
|
uint8_t approx_len = (2 + 8 + 1);
|
||||||
|
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len);
|
||||||
if (packet == NULL) {
|
if (packet == NULL) {
|
||||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockno = 0;
|
int blockno = 0;
|
||||||
uint8_t data[sizeof(info_blocks) * 4] = {0};
|
uint8_t data[sizeof(info_blocks) * XEROX_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
// set up the read command
|
// set up the read command
|
||||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
packet->flags = (ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW);
|
||||||
packet->rawlen = 11;
|
packet->raw[packet->rawlen++] = 0x02;
|
||||||
packet->raw[0] = 0x02;
|
packet->raw[packet->rawlen++] = XEROX_READ_MEM; // set command: read mem
|
||||||
packet->raw[1] = 0x20; // set command: read mem
|
memcpy(packet->raw + packet->rawlen, card.uid, 8); // store uid
|
||||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
packet->rawlen += 8;
|
||||||
|
|
||||||
|
packet->rawlen++;
|
||||||
|
|
||||||
for (int retry = 0; (retry < 3 && blockno < sizeof(info_blocks)); retry++) {
|
for (int retry = 0; (retry < 3 && blockno < sizeof(info_blocks)); retry++) {
|
||||||
|
|
||||||
|
// block to read
|
||||||
packet->raw[10] = info_blocks[blockno];
|
packet->raw[10] = info_blocks[blockno];
|
||||||
|
|
||||||
PacketResponseNG resp;
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
SendCommandNG(CMD_HF_ISO14443B_COMMAND, (uint8_t *)packet, sizeof(iso14b_raw_cmd_t) + packet->rawlen);
|
||||||
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, 2000)) {
|
||||||
/*
|
/*
|
||||||
PrintAndLogEx(INFO, "%X %X %X %X %X %I64X %I64X %I64X %X %X %X %c",
|
PrintAndLogEx(INFO, "%X %X %X %X %X %I64X %I64X %I64X %X %X %X %c",
|
||||||
|
@ -639,14 +644,14 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
||||||
|
|
||||||
// 14b raw command send data_len instead of status
|
// 14b raw command send data_len instead of status
|
||||||
if (resp.length < 7) {
|
if (resp.length < 7) {
|
||||||
PrintAndLogEx(FAILED, "retrying one more time");
|
PrintAndLogEx(FAILED, "retrying one more time, wrong length");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *d = resp.data.asBytes;
|
uint8_t *d = resp.data.asBytes;
|
||||||
|
|
||||||
if (check_crc(CRC_14443_B, d, 7) == false) {
|
if (check_crc(CRC_14443_B, d, 7) == false) {
|
||||||
PrintAndLogEx(FAILED, "crc fail, retrying one more time");
|
PrintAndLogEx(FAILED, "retrying one more time, CRC ( " _RED_("fail") " )");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,7 +660,7 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(data + (blockno * 4), d + 1, 4);
|
memcpy(data + (blockno * XEROX_BLOCK_SIZE), d + 1, XEROX_BLOCK_SIZE);
|
||||||
|
|
||||||
retry = 0;
|
retry = 0;
|
||||||
blockno++;
|
blockno++;
|
||||||
|
@ -671,7 +676,7 @@ static int CmdHFXeroxInfo(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
char pn[13];
|
char pn[13];
|
||||||
gen_pn(data, pn);
|
xerox_generate_partno(data, pn);
|
||||||
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
||||||
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
||||||
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", data[8], data[9], data[10]);
|
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", data[8], data[9], data[10]);
|
||||||
|
@ -712,34 +717,38 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
||||||
bool nosave = arg_get_lit(ctx, 3);
|
bool nosave = arg_get_lit(ctx, 3);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + 11);
|
|
||||||
if (packet == NULL) {
|
|
||||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
iso14b_card_select_t card;
|
iso14b_card_select_t card;
|
||||||
int status = findXerox(&card, false); // remain RF on
|
int status = xerox_select_card(&card);
|
||||||
if (status != PM3_SUCCESS) {
|
if (status != PM3_SUCCESS) {
|
||||||
free(packet);
|
|
||||||
switch_off_field();
|
|
||||||
return PM3_ERFTRANS;
|
return PM3_ERFTRANS;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
PrintAndLogEx(INFO, "Reading memory from tag UID " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||||
|
|
||||||
|
uint8_t approx_len = (2 + 8 + 1);
|
||||||
|
iso14b_raw_cmd_t *packet = (iso14b_raw_cmd_t *)calloc(1, sizeof(iso14b_raw_cmd_t) + approx_len);
|
||||||
|
if (packet == NULL) {
|
||||||
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
int blockno = 1; // block 0 all zeros
|
int blockno = 1; // block 0 all zeros
|
||||||
uint8_t data[256 * 4] = {0};
|
uint8_t data[256 * XEROX_BLOCK_SIZE] = {0};
|
||||||
|
|
||||||
// set up the read command
|
// set up the read command
|
||||||
packet->flags = (ISO14B_APPEND_CRC | ISO14B_RAW);
|
packet->flags = ( ISO14B_CONNECT | ISO14B_APPEND_CRC | ISO14B_RAW );
|
||||||
packet->rawlen = 11;
|
packet->raw[packet->rawlen++] = 0x02;
|
||||||
packet->raw[0] = 0x02;
|
|
||||||
memcpy(packet->raw + 2, card.uid, 8); // store uid
|
// add one for command byte
|
||||||
|
packet->rawlen++;
|
||||||
|
|
||||||
|
// store uid
|
||||||
|
memcpy(packet->raw + packet->rawlen, card.uid, 8);
|
||||||
|
packet->rawlen += 8;
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "." NOLF);
|
PrintAndLogEx(INFO, "." NOLF);
|
||||||
|
|
||||||
for (int retry = 0; (retry < 3 && blockno < 0x100); retry++) {
|
for (int retry = 0; (retry < 2 && blockno < 0x100); retry++) {
|
||||||
|
|
||||||
packet->raw[1] = (blockno < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
packet->raw[1] = (blockno < 12) ? 0x30 : 0x20; // set command: read ext mem or read mem
|
||||||
packet->raw[10] = blockno & 0xFF;
|
packet->raw[10] = blockno & 0xFF;
|
||||||
|
@ -759,20 +768,20 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *recv = resp.data.asBytes;
|
uint8_t *d = resp.data.asBytes;
|
||||||
|
|
||||||
if (check_crc(CRC_14443_B, recv, 7) == false) {
|
if (check_crc(CRC_14443_B, d, 7) == false) {
|
||||||
PrintAndLogEx(FAILED, "crc fail, retrying one more time");
|
PrintAndLogEx(FAILED, "crc fail, retrying one more time");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv[0] != 2) {
|
if (d[0] != 2) {
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(FAILED, "Tag returned Error %x %x", recv[0], recv[1]);
|
PrintAndLogEx(FAILED, "Tag returned Error %x %x", d[0], d[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(data + (blockno * 4), resp.data.asBytes + 1, 4);
|
memcpy(data + (blockno * XEROX_BLOCK_SIZE), resp.data.asBytes + 1, XEROX_BLOCK_SIZE);
|
||||||
|
|
||||||
retry = 0;
|
retry = 0;
|
||||||
blockno++;
|
blockno++;
|
||||||
|
@ -802,9 +811,9 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
||||||
k1[1] = data[5];
|
k1[1] = data[5];
|
||||||
k1[2] = data[6];
|
k1[2] = data[6];
|
||||||
k1[3] = data[7];
|
k1[3] = data[7];
|
||||||
k1[4] = data[0x18 * 4 + 0];
|
k1[4] = data[(0x18 * XEROX_BLOCK_SIZE) + 0];
|
||||||
k1[5] = data[0x18 * 4 + 1];
|
k1[5] = data[(0x18 * XEROX_BLOCK_SIZE) + 1];
|
||||||
k1[6] = data[0x22 * 4 + 0];
|
k1[6] = data[(0x22 * XEROX_BLOCK_SIZE) + 0];
|
||||||
k1[7] = 0;
|
k1[7] = 0;
|
||||||
|
|
||||||
RC2_set_key(&exp_key, 8, k1, 64);
|
RC2_set_key(&exp_key, 8, k1, 64);
|
||||||
|
@ -818,8 +827,8 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
||||||
|
|
||||||
memcpy(k1, k2, sizeof(k1));
|
memcpy(k1, k2, sizeof(k1));
|
||||||
|
|
||||||
k1[2] = k2[3] ^ data[0x22 * 4 + 0];
|
k1[2] = k2[3] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 0];
|
||||||
k1[3] = k2[4] ^ data[0x22 * 4 + 1]; // first_key[7];
|
k1[3] = k2[4] ^ data[(0x22 * XEROX_BLOCK_SIZE) + 1]; // first_key[7];
|
||||||
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
|
k1[5] = k2[1] ^ 0x01; // 01 = crypto method? rfid[23][2]
|
||||||
|
|
||||||
RC2_set_key(&exp_key, 8, k1, 64);
|
RC2_set_key(&exp_key, 8, k1, 64);
|
||||||
|
@ -836,9 +845,9 @@ static int CmdHFXeroxDump(const char *Cmd) {
|
||||||
memset(iv, 0, sizeof(iv));
|
memset(iv, 0, sizeof(iv));
|
||||||
iv[0] = dadr;
|
iv[0] = dadr;
|
||||||
|
|
||||||
RC2_cbc_encrypt(&data[dadr * 4], decr, 8, &exp_key, iv, RC2_DECRYPT);
|
RC2_cbc_encrypt(&data[dadr * XEROX_BLOCK_SIZE], decr, 8, &exp_key, iv, RC2_DECRYPT);
|
||||||
|
|
||||||
memcpy(&data[dadr * 4], decr, 8);
|
memcpy(&data[dadr * XEROX_BLOCK_SIZE], decr, 8);
|
||||||
|
|
||||||
int b;
|
int b;
|
||||||
uint16_t cs, csd;
|
uint16_t cs, csd;
|
||||||
|
@ -919,14 +928,20 @@ static int CmdHFXeroxView(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, blockno, blockno);
|
PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, blockno, blockno);
|
||||||
}
|
}
|
||||||
|
|
||||||
char pn[13];
|
uint8_t tmp[5 * XEROX_BLOCK_SIZE] = {0};
|
||||||
gen_pn(dump, pn);
|
for (uint8_t i = 0; i < ARRAYLEN(info_blocks); i++) {
|
||||||
|
memcpy(tmp + (i * XEROX_BLOCK_SIZE), dump + (info_blocks[i] * XEROX_BLOCK_SIZE), XEROX_BLOCK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
char pn[13];
|
||||||
|
xerox_generate_partno(tmp, pn);
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "");
|
||||||
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
PrintAndLogEx(INFO, "-------- " _CYAN_("tag memory") " ---------");
|
||||||
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
PrintAndLogEx(SUCCESS, " PartNo... %s", pn);
|
||||||
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", dump[8], dump[9], dump[10]);
|
PrintAndLogEx(SUCCESS, " Date..... %02d.%02d.%02d", tmp[8], tmp[9], tmp[10]);
|
||||||
PrintAndLogEx(SUCCESS, " Serial... %d", (dump[14] << 16) | (dump[13] << 8) | dump[12]);
|
PrintAndLogEx(SUCCESS, " Serial... %d", (tmp[14] << 16) | (tmp[13] << 8) | tmp[12]);
|
||||||
PrintAndLogEx(SUCCESS, " Type..... %s", (dump[18] <= 4) ? xerox_c_type[dump[18]] : "Unknown");
|
PrintAndLogEx(SUCCESS, " Type..... %s", (tmp[18] <= 4) ? xerox_c_type[tmp[18]] : "Unknown");
|
||||||
|
|
||||||
const xerox_part_t *item = get_xerox_part_info(pn);
|
const xerox_part_t *item = get_xerox_part_info(pn);
|
||||||
if (strlen(item->partnumber) > 0) {
|
if (strlen(item->partnumber) > 0) {
|
||||||
|
|
|
@ -926,5 +926,8 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||||
// 0x0A = ACK
|
// 0x0A = ACK
|
||||||
// 0x05 = NACK
|
// 0x05 = NACK
|
||||||
|
|
||||||
|
// XEROX Commands
|
||||||
|
#define XEROX_READ_MEM 0x20
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// PROTOCOLS_H
|
// PROTOCOLS_H
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue