From: pwpiwi Date: Thu, 6 Feb 2020 20:49:15 +0000 (+0100) Subject: Merge pull request #910 from pwpiwi/small_USB_response X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/d6e1d482844d6979533250dedc3724ce14f80294?hp=d00a30d56fc4200a9a921d37ab7dc9e18e092bc0 Merge pull request #910 from pwpiwi/small_USB_response Improve USB communications --- diff --git a/armsrc/Makefile b/armsrc/Makefile index 3d1ba79e..7b9e1356 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -50,8 +50,7 @@ THUMBSRC = start.c \ printf.c \ util.c \ string.c \ - usb_cdc.c \ - cmd.c + usb_cdc.c # Compile these in thumb mode optimized for speed (still smaller than ARM mode) THUMBOPTSRC = $(SRC_ISO15693) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 70cabd2e..4f0a19b9 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -13,7 +13,6 @@ #include #include "usb_cdc.h" -#include "cmd.h" #include "proxmark3.h" #include "apps.h" #include "fpga.h" @@ -312,6 +311,7 @@ void set_hw_capabilities(void) { void SendVersion(void) { + LED_A_ON(); set_hw_capabilities(); char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ @@ -347,7 +347,8 @@ void SendVersion(void) { // Send Chip ID and used flash memory uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; uint32_t compressed_data_section_size = common_area.arg1; - cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString)); + cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString) + 1); + LED_A_OFF(); } // measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. @@ -363,13 +364,11 @@ void printUSBSpeed(void) { uint32_t start_time = end_time = GetTickCount(); uint32_t bytes_transferred = 0; - LED_B_ON(); - while(end_time < start_time + USB_SPEED_TEST_MIN_TIME) { + while (end_time < start_time + USB_SPEED_TEST_MIN_TIME) { cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE); end_time = GetTickCount(); bytes_transferred += USB_CMD_DATA_SIZE; } - LED_B_OFF(); Dbprintf(" Time elapsed: %dms", end_time - start_time); Dbprintf(" Bytes transferred: %d", bytes_transferred); @@ -382,6 +381,7 @@ void printUSBSpeed(void) { * Prints runtime information about the PM3. **/ void SendStatus(void) { + LED_A_ON(); BigBuf_print_status(); Fpga_print_status(); #ifdef WITH_SMARTCARD @@ -394,7 +394,8 @@ void SendStatus(void) { Dbprintf(" ToSendMax..........%d", ToSendMax); Dbprintf(" ToSendBit..........%d", ToSendBit); - cmd_send(CMD_ACK,1,0,0,0,0); + cmd_send(CMD_ACK, 1, 0, 0, 0, 0); + LED_A_OFF(); } #if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone) @@ -936,9 +937,7 @@ void ListenReaderField(int limit) { } -void UsbPacketReceived(uint8_t *packet, int len) { - - UsbCommand *c = (UsbCommand *)packet; +void UsbPacketReceived(UsbCommand *c) { // Dbprintf("received %d bytes, with command: 0x%04x and args: %d %d %d",len,c->cmd,c->arg[0],c->arg[1],c->arg[2]); @@ -1337,9 +1336,11 @@ void UsbPacketReceived(uint8_t *packet, int len) { break; case CMD_FPGA_MAJOR_MODE_OFF: // ## FPGA Control + LED_A_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); LED_D_OFF(); // LED D indicates field ON or OFF + LED_A_OFF(); break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: @@ -1428,7 +1429,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { case CMD_DEVICE_INFO: { uint32_t dev_info = DEVICE_INFO_FLAG_OSIMAGE_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_OS; if(common_area.flags.bootrom_present) dev_info |= DEVICE_INFO_FLAG_BOOTROM_PRESENT; - cmd_send(CMD_DEVICE_INFO,dev_info,0,0,0,0); + cmd_send_old(CMD_DEVICE_INFO,dev_info,0,0,0,0); break; } default: @@ -1479,13 +1480,12 @@ void __attribute__((noreturn)) AppMain(void) { LCDInit(); #endif - uint8_t rx[sizeof(UsbCommand)]; - size_t rx_len; - + UsbCommand rx; + for(;;) { WDT_HIT(); - if (usb_poll() && (rx_len = usb_read(rx, sizeof(rx)))) { - UsbPacketReceived(rx, rx_len); + if (cmd_receive(&rx)) { + UsbPacketReceived(&rx); } else { #if defined(WITH_LF_StandAlone) && !defined(WITH_ISO14443a_StandAlone) if (BUTTON_HELD(1000) > 0) diff --git a/armsrc/apps.h b/armsrc/apps.h index 5d3e3e59..0431d2ee 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -112,8 +112,4 @@ void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -// cmd.h -bool cmd_receive(UsbCommand* cmd); -bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); - #endif diff --git a/armsrc/epa.c b/armsrc/epa.c index 0e999e1e..fe32e497 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -15,7 +15,7 @@ #include "iso14443a.h" #include "iso14443b.h" #include "epa.h" -#include "cmd.h" +#include "usb_cdc.h" #include "fpgaloader.h" #include "string.h" #include "util.h" @@ -453,20 +453,17 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) //----------------------------------------------------------------------------- // Perform the PACE protocol by replaying given APDUs //----------------------------------------------------------------------------- -void EPA_PACE_Replay(UsbCommand *c) -{ +void EPA_PACE_Replay(UsbCommand *c) { uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0}; - // if an APDU has been passed, save it + // if an APDU has been passed, just save it if (c->arg[0] != 0) { // make sure it's not too big - if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) - { + if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) { cmd_send(CMD_ACK, 1, 0, 0, NULL, 0); + return; } - memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1], - c->d.asBytes, - c->arg[2]); + memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1], c->d.asBytes, c->arg[2]); // save/update APDU length if (c->arg[1] == 0) { apdu_lengths_replay[c->arg[0] - 1] = c->arg[2]; diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index 755ac0cc..3a0ac65f 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -14,7 +14,7 @@ #include "BigBuf.h" #include "util.h" #include "apps.h" -#include "usb_cdc.h" // for usb_poll_validate_length +#include "usb_cdc.h" #include "fpga.h" #include "fpgaloader.h" diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 7cdabefa..688805be 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -19,7 +19,7 @@ #include "hitag2.h" #include "proxmark3.h" -#include "cmd.h" +#include "usb_cdc.h" #include "apps.h" #include "util.h" #include "hitag.h" diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 5da170bb..8f40146a 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -17,6 +17,7 @@ #include #include "proxmark3.h" #include "apps.h" +#include "usb_cdc.h" #include "util.h" #include "hitag.h" #include "string.h" diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 51513114..3d16b42c 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -18,6 +18,7 @@ #include "mifareutil.h" // for MF_DBGLEVEL #include "BigBuf.h" #include "apps.h" +#include "usb_cdc.h" #ifdef WITH_SMARTCARD #include "smartcard.h" diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 28cfcaa6..afe1a607 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -24,7 +24,7 @@ #include "string.h" #include "printf.h" #include "common.h" -#include "cmd.h" +#include "usb_cdc.h" #include "iso14443a.h" #include "iso15693.h" // Needed for CRC in emulation mode; @@ -34,7 +34,6 @@ #include "iso15693tools.h" #include "protocols.h" #include "optimized_cipher.h" -#include "usb_cdc.h" // for usb_poll_validate_length #include "fpgaloader.h" // iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after @@ -675,14 +674,14 @@ static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { // Send act_all ReaderTransmitIClass(act_all, 1, &start_time); // Card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false;//Fail + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false; //Fail //Send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; ReaderTransmitIClass(identify, 1, &start_time); //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return false;//Fail + if (len != 10) return false; //Fail //Copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); @@ -691,7 +690,7 @@ static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { ReaderTransmitIClass(select, sizeof(select), &start_time); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return false;//Fail + if (len != 10) return false; //Fail //Success - we got CSN //Save CSN in response data @@ -734,42 +733,42 @@ void ReaderIClass(uint8_t flags) { if (selectIclassTag(resp, &eof_time)) { result_status = FLAG_ICLASS_READER_CSN; memcpy(card_data, resp, 8); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - //Read block 1, config - if (flags & FLAG_ICLASS_READER_CONF) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - Dbprintf("Failed to read config block"); + //Read block 1, config + if (flags & FLAG_ICLASS_READER_CONF) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CONF; + memcpy(card_data+8, resp, 8); + } else { + Dbprintf("Failed to read config block"); + } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } - //Read block 2, e-purse - if (flags & FLAG_ICLASS_READER_CC) { - if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CC; - memcpy(card_data + (8*2), resp, 8); - } else { - Dbprintf("Failed to read e-purse"); + //Read block 2, e-purse + if (flags & FLAG_ICLASS_READER_CC) { + if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CC; + memcpy(card_data + (8*2), resp, 8); + } else { + Dbprintf("Failed to read e-purse"); + } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } - //Read block 5, AA - if (flags & FLAG_ICLASS_READER_AA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data + (8*5), resp, 8); - } else { - Dbprintf("Failed to read AA block"); + //Read block 5, AA + if (flags & FLAG_ICLASS_READER_AA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time)) { + result_status |= FLAG_ICLASS_READER_AA; + memcpy(card_data + (8*5), resp, 8); + } else { + Dbprintf("Failed to read AA block"); + } } } - + cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); LED_A_OFF(); @@ -820,9 +819,9 @@ void iClass_ReadBlk(uint8_t blockno) { uint8_t readblockdata[10]; bool isOK = iClass_ReadBlock(blockno, readblockdata); - cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); + cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); LED_A_OFF(); } @@ -900,11 +899,10 @@ void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { } else { Dbprintf("Write block [%02x] failed", blockNo); } - cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); + cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); LED_A_OFF(); } @@ -935,6 +933,5 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { LED_D_OFF(); cmd_send(CMD_ACK, 1, 0, 0, 0, 0); - LED_A_OFF(); } diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 31a3e4cc..0de5ea6f 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -17,7 +17,7 @@ #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "cmd.h" +#include "usb_cdc.h" #include "iso14443crc.h" #include "crapto1/crapto1.h" #include "mifareutil.h" @@ -942,7 +942,7 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_ // Main loop of simulated tag: receive commands from reader, decide what // response to send, and send it. //----------------------------------------------------------------------------- -void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) { +void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t* data) { uint8_t sak; @@ -1701,13 +1701,13 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) { // if anticollision is false, then the UID must be provided in uid_ptr[] // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) // requests ATS unless no_rats is true -int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { +int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { uint8_t sel_all[] = { 0x93,0x20 }; uint8_t sel_uid[] = { 0x93,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 uint8_t resp[MAX_FRAME_SIZE]; // theoretically. A usual RATS will be much smaller uint8_t resp_par[MAX_PARITY_SIZE]; - byte_t uid_resp[4]; + uint8_t uid_resp[4]; size_t uid_resp_len; uint8_t sak = 0x04; // cascade uid @@ -2020,21 +2020,21 @@ void ReaderIso14443a(UsbCommand *c) { size_t lenbits = c->arg[1] >> 16; uint32_t timeout = c->arg[2]; uint32_t arg0 = 0; - byte_t buf[USB_CMD_DATA_SIZE] = {0}; + uint8_t buf[USB_CMD_DATA_SIZE] = {0}; uint8_t par[MAX_PARITY_SIZE]; bool cantSELECT = false; set_tracing(true); - if(param & ISO14A_CLEAR_TRACE) { + if (param & ISO14A_CLEAR_TRACE) { clear_trace(); } - if(param & ISO14A_REQUEST_TRIGGER) { + if (param & ISO14A_REQUEST_TRIGGER) { iso14a_set_trigger(true); } - if(param & ISO14A_CONNECT) { + if (param & ISO14A_CONNECT) { LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); if(!(param & ISO14A_NO_SELECT)) { @@ -2048,16 +2048,16 @@ void ReaderIso14443a(UsbCommand *c) { } FpgaDisableTracing(); LED_B_ON(); - cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); + cmd_send(CMD_NACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); LED_B_OFF(); } } - if(param & ISO14A_SET_TIMEOUT) { + if (param & ISO14A_SET_TIMEOUT) { iso14a_set_timeout(timeout); } - if(param & ISO14A_APDU && !cantSELECT) { + if (param & ISO14A_APDU && !cantSELECT) { uint8_t res; arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); FpgaDisableTracing(); @@ -2066,8 +2066,8 @@ void ReaderIso14443a(UsbCommand *c) { LED_B_OFF(); } - if(param & ISO14A_RAW && !cantSELECT) { - if(param & ISO14A_APPEND_CRC) { + if (param & ISO14A_RAW && !cantSELECT) { + if (param & ISO14A_APPEND_CRC) { if(param & ISO14A_TOPAZMODE) { AppendCrc14443b(cmd,len); } else { @@ -2076,8 +2076,8 @@ void ReaderIso14443a(UsbCommand *c) { len += 2; if (lenbits) lenbits += 16; } - if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) - if(param & ISO14A_TOPAZMODE) { + if (lenbits > 0) { // want to send a specific number of bits (e.g. short commands) + if (param & ISO14A_TOPAZMODE) { int bits_to_send = lenbits; uint16_t i = 0; ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity @@ -2091,7 +2091,7 @@ void ReaderIso14443a(UsbCommand *c) { ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity } } else { // want to send complete bytes only - if(param & ISO14A_TOPAZMODE) { + if (param & ISO14A_TOPAZMODE) { uint16_t i = 0; ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy while (i < len) { @@ -2105,15 +2105,15 @@ void ReaderIso14443a(UsbCommand *c) { FpgaDisableTracing(); LED_B_ON(); - cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); + cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); LED_B_OFF(); } - if(param & ISO14A_REQUEST_TRIGGER) { + if (param & ISO14A_REQUEST_TRIGGER) { iso14a_set_trigger(false); } - if(param & ISO14A_NO_DISCONNECT) { + if (param & ISO14A_NO_DISCONNECT) { return; } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index d2a94a78..32bf3971 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -13,6 +13,7 @@ #ifndef __ISO14443A_H #define __ISO14443A_H +#include #include #include #include "usb_cmd.h" @@ -31,7 +32,7 @@ extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); extern void AppendCrc14443a(uint8_t *data, int len); extern void RAMFUNC SnoopIso14443a(uint8_t param); -extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t *data); +extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, uint8_t *data); extern void ReaderIso14443a(UsbCommand *c); extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 6434409d..0f36c7c7 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -14,6 +14,7 @@ #include "proxmark3.h" #include "apps.h" +#include "usb_cdc.h" #include "util.h" #include "string.h" #include "iso14443crc.h" diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 351b0184..9f6516aa 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -58,7 +58,7 @@ #include "string.h" #include "iso15693tools.h" #include "protocols.h" -#include "cmd.h" +#include "usb_cdc.h" #include "BigBuf.h" #include "fpgaloader.h" diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 97af8843..71ff0321 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -14,6 +14,7 @@ #include "proxmark3.h" #include "apps.h" +#include "usb_cdc.h" #include "util.h" #include "string.h" #include "legic_prng.h" diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 12f9de08..995a8810 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -17,7 +17,7 @@ #include "lfdemod.h" #include "lfsampling.h" #include "protocols.h" -#include "usb_cdc.h" // for usb_poll_validate_length +#include "usb_cdc.h" #include "fpgaloader.h" /** diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index b9032c5f..27b1cf19 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -18,7 +18,7 @@ #include #include "proxmark3.h" -#include "cmd.h" +#include "usb_cdc.h" #include "crapto1/crapto1.h" #include "iso14443a.h" #include "BigBuf.h" @@ -111,11 +111,12 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); LED_B_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -202,9 +203,10 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) return; } - cmd_send(CMD_ACK,1,0,0,dataout,16); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); + + cmd_send(CMD_ACK,1,0,0,dataout,16); LED_A_OFF(); } @@ -266,12 +268,13 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo)); LED_B_OFF(); - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -362,10 +365,11 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks); - cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); + + cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); + BigBuf_free(); LED_A_OFF(); } @@ -431,13 +435,14 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); LED_B_OFF(); - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -475,8 +480,9 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); LEDsoff(); } */ @@ -544,8 +550,9 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); LEDsoff(); } @@ -613,8 +620,9 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){ return; }; - cmd_send(CMD_ACK,1,0,0,0,0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + cmd_send(CMD_ACK,1,0,0,0,0); LEDsoff(); } @@ -743,16 +751,17 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, crypto1_destroy(pcs); + if (field_off) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + } + LED_B_ON(); cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); LED_B_OFF(); if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); - if (field_off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - } } @@ -978,13 +987,14 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat memcpy(buf+16, &target_ks[1], 4); memcpy(buf+20, &authentication_timeout, 4); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); + LED_B_ON(); cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); LED_B_OFF(); - if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1352,13 +1362,14 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ break; } + // reset fpga + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + // send USB response LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,NULL,0); LED_B_OFF(); - // reset fpga - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); return; @@ -1490,14 +1501,15 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai break; } + if ((workFlags & 0x10) || (!isOK)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,uid,4); LED_B_OFF(); - if ((workFlags & 0x10) || (!isOK)) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - } + LEDsoff(); } @@ -1574,6 +1586,10 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai break; } + if ((workFlags & 0x10) || (!isOK)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + } + LED_B_ON(); if (workFlags & 0x20) { if (isOK) @@ -1583,10 +1599,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai cmd_send(CMD_ACK,isOK,0,0,data,18); LED_B_OFF(); - if ((workFlags & 0x10) || (!isOK)) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - } + LEDsoff(); } void MifareCIdent(){ @@ -1622,11 +1635,12 @@ void MifareCIdent(){ // From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it. mifare_classic_halt(NULL, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); LED_B_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1657,7 +1671,8 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ } if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED"); - cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout)); + + cmd_send(CMD_ACK, 1, cuid, 0, dataout, sizeof(dataout)); } void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ @@ -1671,16 +1686,17 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ isOK = mifare_desfire_des_auth2(cuid, key, dataout); - if( isOK) { + if (isOK) { if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Authentication part2: Failed"); OnError(4); return; } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 2 FINISHED"); cmd_send(CMD_ACK, isOK, 0, 0, dataout, sizeof(dataout)); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 891e0daf..b63160c9 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -20,7 +20,6 @@ #include "fpgaloader.h" #include "proxmark3.h" #include "usb_cdc.h" -#include "cmd.h" #include "protocols.h" #include "apps.h" diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index 4dbcd904..f3ee4a3f 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -18,7 +18,7 @@ #include "crapto1/crapto1.h" #include "mifareutil.h" #include "common.h" -#include "cmd.h" +#include "usb_cdc.h" #include "BigBuf.h" #include "fpgaloader.h" @@ -152,7 +152,7 @@ bool intMfSniffSend() { while (pckLen > 0) { pckSize = MIN(USB_CMD_DATA_SIZE, pckLen); LED_B_ON(); - cmd_send(CMD_ACK, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize); + cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 1, BigBuf_get_traceLen(), pckSize, trace + BigBuf_get_traceLen() - pckLen, pckSize); LED_B_OFF(); pckLen -= pckSize; @@ -160,7 +160,7 @@ bool intMfSniffSend() { } LED_B_ON(); - cmd_send(CMD_ACK,2,0,0,0,0); + cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K,2,0,0,0,0); LED_B_OFF(); clear_trace(); diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 147f6fb8..2fae74cc 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -1,5 +1,6 @@ #include "proxmark3.h" #include "apps.h" +#include "usb_cdc.h" #include "lfsampling.h" #include "pcf7931.h" #include "util.h" diff --git a/armsrc/util.h b/armsrc/util.h index 14ac5e10..bdb7fafd 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -8,12 +8,13 @@ // Utility functions used in many places, not specific to any piece of code. //----------------------------------------------------------------------------- -#ifndef __UTIL_H -#define __UTIL_H +#ifndef UTIL_H__ +#define UTIL_H__ #include #include #include "common.h" +#include "at91sam7s512.h" #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -33,40 +34,40 @@ #define REV32(x) (REV16(x) | (REV16(x >> 16) << 16)) #define REV64(x) (REV32(x) | (REV32(x >> 32) << 32)) -void print_result(char *name, uint8_t *buf, size_t len); -size_t nbytes(size_t nbits); -uint32_t SwapBits(uint32_t value, int nrbits); -void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); -uint64_t bytes_to_num(uint8_t* src, size_t len); -void rol(uint8_t *data, const size_t len); -void lsl (uint8_t *data, size_t len); - -void LED(int led, int ms); -void LEDsoff(); -void LEDson(); -void LEDsinvert(); -int BUTTON_CLICKED(int ms); -int BUTTON_HELD(int ms); -void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); +extern void print_result(char *name, uint8_t *buf, size_t len); +extern size_t nbytes(size_t nbits); +extern uint32_t SwapBits(uint32_t value, int nrbits); +extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); +extern uint64_t bytes_to_num(uint8_t* src, size_t len); +extern void rol(uint8_t *data, const size_t len); +extern void lsl (uint8_t *data, size_t len); + +extern void LED(int led, int ms); +extern void LEDsoff(); +extern void LEDson(); +extern void LEDsinvert(); +extern int BUTTON_CLICKED(int ms); +extern int BUTTON_HELD(int ms); +extern void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); //iceman's ticks.h #ifndef GET_TICKS # define GET_TICKS GetTicks() #endif -void SpinDelay(int ms); -void SpinDelayUs(int us); +extern void SpinDelay(int ms); +extern void SpinDelayUs(int us); -void StartTickCount(); -uint32_t RAMFUNC GetTickCount(); +extern void StartTickCount(); +extern uint32_t RAMFUNC GetTickCount(); -void StartCountUS(); -uint32_t RAMFUNC GetCountUS(); -uint32_t RAMFUNC GetDeltaCountUS(); +extern void StartCountUS(); +extern uint32_t RAMFUNC GetCountUS(); +extern uint32_t RAMFUNC GetDeltaCountUS(); -void StartCountSspClk(); -void ResetSspClk(void); -uint32_t GetCountSspClk(); +extern void StartCountSspClk(); +extern void ResetSspClk(void); +extern uint32_t GetCountSspClk(); extern void StartTicks(void); extern uint32_t GetTicks(void); @@ -78,6 +79,6 @@ extern void ResetTimer(AT91PS_TC timer); extern void StopTicks(void); // end iceman's ticks.h -uint32_t prand(); +extern uint32_t prand(); #endif diff --git a/bootrom/Makefile b/bootrom/Makefile index dd1e7e08..b1e2e6cd 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -8,7 +8,7 @@ # DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code ARMSRC = -THUMBSRC = cmd.c usb_cdc.c bootrom.c +THUMBSRC = usb_cdc.c bootrom.c ASMSRC = ram-reset.s flash-reset.s VERSIONSRC = version.c diff --git a/bootrom/bootrom.c b/bootrom/bootrom.c index bbea07b5..81742176 100644 --- a/bootrom/bootrom.c +++ b/bootrom/bootrom.c @@ -6,17 +6,15 @@ // Main code for the bootloader //----------------------------------------------------------------------------- -#include +#include "proxmark3.h" #include "usb_cdc.h" -#include "cmd.h" -//#include "usb_hid.h" void DbpString(char *str) { - byte_t len = 0; + uint8_t len = 0; while (str[len] != 0x00) { len++; } - cmd_send(CMD_DEBUG_PRINT_STRING,len,0,0,(byte_t*)str,len); + cmd_send_old(CMD_DEBUG_PRINT_STRING,len,0,0,(uint8_t*)str,len); } struct common_area common_area __attribute__((section(".commonarea"))); @@ -89,26 +87,22 @@ static void Fatal(void) for(;;); } -void UsbPacketReceived(uint8_t *packet, int len) { +void UsbPacketReceived(UsbCommand *c) { int i, dont_ack=0; - UsbCommand* c = (UsbCommand *)packet; volatile uint32_t *p; - if(len != sizeof(UsbCommand)) { - Fatal(); - } - uint32_t arg0 = (uint32_t)c->arg[0]; switch(c->cmd) { case CMD_DEVICE_INFO: { dont_ack = 1; - arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM | - DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH; + arg0 = DEVICE_INFO_FLAG_BOOTROM_PRESENT + | DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM + | DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH; if(common_area.flags.osimage_present) { arg0 |= DEVICE_INFO_FLAG_OSIMAGE_PRESENT; } - cmd_send(CMD_DEVICE_INFO,arg0,1,2,0,0); + cmd_send_old(CMD_DEVICE_INFO,arg0,1,2,0,0); } break; case CMD_SETUP_WRITE: { @@ -134,7 +128,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { if( ((flash_address+AT91C_IFLASH_PAGE_SIZE-1) >= end_addr) || (flash_address < start_addr) ) { /* Disallow write */ dont_ack = 1; - cmd_send(CMD_NACK,0,0,0,0,0); + cmd_send_old(CMD_NACK,0,0,0,0,0); } else { uint32_t page_n = (flash_address - ((uint32_t)flash_mem)) / AT91C_IFLASH_PAGE_SIZE; /* Translate address to flash page and do flash, update here for the 512k part */ @@ -148,7 +142,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { while(!((sr = AT91C_BASE_EFC0->EFC_FSR) & AT91C_MC_FRDY)); if(sr & (AT91C_MC_LOCKE | AT91C_MC_PROGE)) { dont_ack = 1; - cmd_send(CMD_NACK,0,0,0,0,0); + cmd_send_old(CMD_NACK,0,0,0,0,0); } } } break; @@ -179,7 +173,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { } else { start_addr = end_addr = 0; dont_ack = 1; - cmd_send(CMD_NACK,0,0,0,0,0); + cmd_send_old(CMD_NACK,0,0,0,0,0); } } } break; @@ -190,7 +184,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { } if(!dont_ack) { - cmd_send(CMD_ACK,arg0,0,0,0,0); + cmd_send_old(CMD_ACK,arg0,0,0,0,0); } } @@ -199,21 +193,17 @@ static void flash_mode(int externally_entered) start_addr = 0; end_addr = 0; bootrom_unlocked = 0; - byte_t rx[sizeof(UsbCommand)]; - size_t rx_len; + UsbCommand rx; - usb_enable(); - for (volatile size_t i=0; i<0x100000; i++) {}; + usb_enable(); + for (volatile size_t i=0; i<0x100000; i++) {}; for(;;) { WDT_HIT(); - if (usb_poll()) { - rx_len = usb_read(rx,sizeof(UsbCommand)); - if (rx_len) { - UsbPacketReceived(rx,rx_len); - } - } + if (cmd_receive(&rx)) { + UsbPacketReceived(&rx); + } if(!externally_entered && !BUTTON_PRESS()) { /* Perform a reset to leave flash mode */ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index eba33947..58315582 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -46,28 +46,28 @@ int CmdHF14AList(const char *Cmd) return 0; } -int Hf14443_4aGetCardData(iso14a_card_select_t * card) { +int Hf14443_4aGetCardData(iso14a_card_select_t *card) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + WaitForResponse(CMD_NACK, &resp); memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - if(select_status == 0) { + if (select_status == 0) { PrintAndLog("E->iso14443a card select failed"); return 1; } - if(select_status == 2) { + if (select_status == 2) { PrintAndLog("E->Card doesn't support iso14443-4 mode"); return 1; } - if(select_status == 3) { + if (select_status == 3) { PrintAndLog("E->Card doesn't support standard iso14443-3 anticollision"); PrintAndLog("\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); return 1; @@ -156,20 +156,24 @@ int CmdHF14AReader(const char *Cmd) { return 0; } -int CmdHF14AInfo(const char *Cmd) -{ + +int CmdHF14AInfo(const char *Cmd) { + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - + if (!WaitForResponseTimeout(CMD_NACK, &resp, 500)) { + if (Cmd[0] != 's') PrintAndLog("Error: No response from Proxmark.\n"); + return 0; + } + iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - if(select_status == 0) { + if (select_status == 0) { if (Cmd[0] != 's') PrintAndLog("iso14443a card select failed"); // disconnect c.arg[0] = 0; @@ -217,13 +221,13 @@ int CmdHF14AInfo(const char *Cmd) SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + WaitForResponse(CMD_NACK,&resp); memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - if(select_status == 0) { + if (select_status == 0) { //PrintAndLog("iso14443a card select failed"); // disconnect c.arg[0] = 0; @@ -272,7 +276,7 @@ int CmdHF14AInfo(const char *Cmd) // Double & triple sized UID, can be mapped to a manufacturer. // HACK: does this apply for Ultralight cards? - if ( card.uidlen > 4 ) { + if (card.uidlen > 4) { PrintAndLog("MANUFACTURER : %s", getManufacturerName(card.uid[0])); } @@ -430,7 +434,7 @@ int CmdHF14AInfo(const char *Cmd) (void)mfCIdentify(); if (isMifareClassic) { - switch(DetectClassicPrng()) { + switch (DetectClassicPrng()) { case 0: PrintAndLog("Prng detection: HARDENED (hardnested)"); break; @@ -462,7 +466,7 @@ int CmdHF14ACUIDs(const char *Cmd) SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + WaitForResponse(CMD_NACK,&resp); iso14a_card_select_t *card = (iso14a_card_select_t *) resp.d.asBytes; diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 1400395a..93e46b67 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -333,7 +333,7 @@ int HFiClassReader(bool loop, bool verbose) { while (!ukbhit()) { SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { uint8_t readStatus = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; @@ -368,7 +368,8 @@ int HFiClassReader(bool loop, bool verbose) { if (tagFound && !loop) return 1; } else { - if (verbose) PrintAndLog("Command execute timeout"); + if (verbose) PrintAndLog("Error: No response from Proxmark."); + break; } if (!loop) break; } diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 93c3ea65..33790230 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -2672,7 +2672,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } UsbCommand resp; - if (WaitForResponseTimeoutW(CMD_ACK, &resp, 2000, false)) { + if (WaitForResponseTimeoutW(CMD_UNKNOWN, &resp, 2000, false)) { res = resp.arg[0] & 0xff; uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 39a00d63..d53620ad 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -12,6 +12,7 @@ #include #include +#include #include "comms.h" #include "usb_cmd.h" #include "cmdmain.h" diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index b0d96f13..caf33db6 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -10,6 +10,7 @@ #include "cmdsmartcard.h" #include +#include #include "ui.h" #include "cmdparser.h" diff --git a/client/comms.c b/client/comms.c index 5af53715..b3b85fd2 100644 --- a/client/comms.c +++ b/client/comms.c @@ -11,10 +11,13 @@ #include "comms.h" +#include +#include +#include #include -#if defined(__linux__) && !defined(NO_UNLINK) -#include // for unlink() -#endif +#include +#include + #include "uart.h" #include "ui.h" #include "common.h" @@ -31,7 +34,6 @@ static bool offline; typedef struct { bool run; // If TRUE, continue running the uart_communication thread - bool block_after_ACK; // if true, block after receiving an ACK package } communication_arg_t; static communication_arg_t conn; @@ -45,6 +47,9 @@ static pthread_cond_t txBufferSig = PTHREAD_COND_INITIALIZER; // Used by UsbReceiveCommand as a ring buffer for messages that are yet to be // processed by a command handler (WaitForResponse{,Timeout}) +#define CMD_BUFFER_SIZE 50 +#define CMD_BUFFER_CHECK_TIME 10 // maximum time (in ms) to wait in getCommand() + static UsbCommand rxBuffer[CMD_BUFFER_SIZE]; // Points to the next empty position to write to @@ -55,6 +60,7 @@ static int cmd_tail = 0; // to lock rxBuffer operations from different threads static pthread_mutex_t rxBufferMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t rxBufferSig = PTHREAD_COND_INITIALIZER; // These wrappers are required because it is not possible to access a static // global variable outside of the context of a single file. @@ -69,17 +75,17 @@ bool IsOffline() { void SendCommand(UsbCommand *c) { #ifdef COMMS_DEBUG - printf("Sending %04x cmd\n", c->cmd); + printf("Sending %04" PRIx64 " cmd\n", c->cmd); #endif if (offline) { PrintAndLog("Sending bytes to proxmark failed - offline"); return; - } + } pthread_mutex_lock(&txBufferMutex); /** - This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive, + This causes hangups at times, when the pm3 unit is unresponsive or disconnected. The main console thread is alive, but comm thread just spins here. Not good.../holiman **/ while (txBuffer_pending) { @@ -101,8 +107,7 @@ void SendCommand(UsbCommand *c) { * A better method could have been to have explicit command-ACKS, so we can know which ACK goes to which * operation. Right now we'll just have to live with this. */ -void clearCommandBuffer() -{ +void clearCommandBuffer() { //This is a very simple operation pthread_mutex_lock(&rxBufferMutex); cmd_tail = cmd_head; @@ -113,11 +118,9 @@ void clearCommandBuffer() * @brief storeCommand stores a USB command in a circular buffer * @param UC */ -static void storeCommand(UsbCommand *command) -{ +static void storeCommand(UsbCommand *command) { pthread_mutex_lock(&rxBufferMutex); - if( (cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail) - { + if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) { // If these two are equal, we're about to overwrite in the // circular buffer. PrintAndLog("WARNING: Command buffer about to overwrite command! This needs to be fixed!"); @@ -127,7 +130,8 @@ static void storeCommand(UsbCommand *command) UsbCommand* destination = &rxBuffer[cmd_head]; memcpy(destination, command, sizeof(UsbCommand)); - cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap + cmd_head = (cmd_head + 1) % CMD_BUFFER_SIZE; //increment head and wrap + pthread_cond_signal(&rxBufferSig); // tell main thread that a new command can be retreived pthread_mutex_unlock(&rxBufferMutex); } @@ -135,21 +139,32 @@ static void storeCommand(UsbCommand *command) /** * @brief getCommand gets a command from an internal circular buffer. * @param response location to write command - * @return 1 if response was returned, 0 if nothing has been received + * @return 1 if response was returned, 0 if nothing has been received in time */ -static int getCommand(UsbCommand* response) -{ +static int getCommand(UsbCommand* response, uint32_t ms_timeout) { + + struct timespec end_time; + clock_gettime(CLOCK_REALTIME, &end_time); + end_time.tv_sec += ms_timeout / 1000; + end_time.tv_nsec += (ms_timeout % 1000) * 1000000; + if (end_time.tv_nsec > 1000000000) { + end_time.tv_nsec -= 1000000000; + end_time.tv_sec += 1; + } pthread_mutex_lock(&rxBufferMutex); - //If head == tail, there's nothing to read, or if we just got initialized - if (cmd_head == cmd_tail){ + int res = 0; + while (cmd_head == cmd_tail && !res) { + res = pthread_cond_timedwait(&rxBufferSig, &rxBufferMutex, &end_time); + } + if (res) { // timeout pthread_mutex_unlock(&rxBufferMutex); return 0; } - //Pick out the next unread command + // Pick out the next unread command UsbCommand* last_unread = &rxBuffer[cmd_tail]; memcpy(response, last_unread, sizeof(UsbCommand)); - //Increment tail - this is a circular buffer, so modulo buffer size + // Increment tail - this is a circular buffer, so modulo buffer size cmd_tail = (cmd_tail + 1) % CMD_BUFFER_SIZE; pthread_mutex_unlock(&rxBufferMutex); @@ -161,15 +176,14 @@ static int getCommand(UsbCommand* response) // Entry point into our code: called whenever we received a packet over USB. // Handle debug commands directly, store all other commands in circular buffer. //---------------------------------------------------------------------------------- -static void UsbCommandReceived(UsbCommand *UC) -{ - switch(UC->cmd) { +static void UsbCommandReceived(UsbCommand *UC) { + switch (UC->cmd) { // First check if we are handling a debug message case CMD_DEBUG_PRINT_STRING: { char s[USB_CMD_DATA_SIZE+1]; memset(s, 0x00, sizeof(s)); - size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE); - memcpy(s,UC->d.asBytes,len); + size_t len = MIN(UC->arg[0], USB_CMD_DATA_SIZE); + memcpy(s, UC->d.asBytes,len); PrintAndLog("#db# %s", s); return; } break; @@ -180,64 +194,103 @@ static void UsbCommandReceived(UsbCommand *UC) } break; default: - storeCommand(UC); + storeCommand(UC); break; } } +static bool receive_from_serial(serial_port sp, uint8_t *rx_buf, size_t len, size_t *received_len) { + size_t bytes_read = 0; + *received_len = 0; + // we eventually need to call uart_receive several times because it may timeout in the middle of a transfer + while (uart_receive(sp, rx_buf + *received_len, len - *received_len, &bytes_read) && bytes_read && *received_len < len) { + #ifdef COMMS_DEBUG + if (bytes_read != len - *received_len) { + printf("uart_receive() returned true but not enough bytes could be received. received: %zd, wanted to receive: %zd, already received before: %zd\n", + bytes_read, len - *received_len, *received_len); + } + #endif + *received_len += bytes_read; + bytes_read = 0; + } + return (*received_len == len); +} + + static void #ifdef __has_attribute #if __has_attribute(force_align_arg_pointer) -__attribute__((force_align_arg_pointer)) +__attribute__((force_align_arg_pointer)) #endif #endif *uart_communication(void *targ) { communication_arg_t *conn = (communication_arg_t*)targ; - size_t rxlen; - UsbCommand rx; - UsbCommand *prx = ℞ + uint8_t rx[sizeof(UsbCommand)]; + size_t rxlen = 0; + uint8_t *prx = rx; + UsbCommand *command = (UsbCommand*)rx; + UsbResponse *response = (UsbResponse*)rx; #if defined(__MACH__) && defined(__APPLE__) disableAppNap("Proxmark3 polling UART"); #endif while (conn->run) { - rxlen = 0; bool ACK_received = false; - if (uart_receive(sp, (uint8_t *)prx, sizeof(UsbCommand) - (prx-&rx), &rxlen) && rxlen) { + prx = rx; + size_t bytes_to_read = offsetof(UsbResponse, d); // the fixed part of a new style UsbResponse. Otherwise this will be cmd and arg[0] (64 bit each) + if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { prx += rxlen; - if (prx-&rx < sizeof(UsbCommand)) { - continue; - } - UsbCommandReceived(&rx); - if (rx.cmd == CMD_ACK) { - ACK_received = true; + if (response->cmd & CMD_VARIABLE_SIZE_FLAG) { // new style response with variable size +#ifdef COMMS_DEBUG + PrintAndLog("received new style response %04" PRIx16 ", datalen = %zd, arg[0] = %08" PRIx32 ", arg[1] = %08" PRIx32 ", arg[2] = %08" PRIx32, + response->cmd, response->datalen, response->arg[0], response->arg[1], response->arg[2]); +#endif + bytes_to_read = response->datalen; + if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { + UsbCommand resp; + resp.cmd = response->cmd & ~CMD_VARIABLE_SIZE_FLAG; // remove the flag + resp.arg[0] = response->arg[0]; + resp.arg[1] = response->arg[1]; + resp.arg[2] = response->arg[2]; + memcpy(&resp.d.asBytes, &response->d.asBytes, response->datalen); + UsbCommandReceived(&resp); + if (resp.cmd == CMD_ACK) { + ACK_received = true; + } + } + } else { // old style response uses same data structure as commands. Fixed size. +#ifdef COMMS_DEBUG + PrintAndLog("received old style response %016" PRIx64 ", arg[0] = %016" PRIx64, command->cmd, command->arg[0]); +#endif + bytes_to_read = sizeof(UsbCommand) - bytes_to_read; + if (receive_from_serial(sp, prx, bytes_to_read, &rxlen)) { + UsbCommandReceived(command); + if (command->cmd == CMD_ACK) { + ACK_received = true; + } + } } } - prx = ℞ - pthread_mutex_lock(&txBufferMutex); - - if (conn->block_after_ACK) { - // if we just received an ACK, wait here until a new command is to be transmitted - if (ACK_received) { - while (!txBuffer_pending) { - pthread_cond_wait(&txBufferSig, &txBufferMutex); - } + // if we received an ACK the PM has done its job and waits for another command. + // We therefore can wait here as well until a new command is to be transmitted. + // The advantage is that the next command will be transmitted immediately without the need to wait for a receive timeout + if (ACK_received) { + while (!txBuffer_pending) { + pthread_cond_wait(&txBufferSig, &txBufferMutex); } } - - if(txBuffer_pending) { + if (txBuffer_pending) { if (!uart_send(sp, (uint8_t*) &txBuffer, sizeof(UsbCommand))) { PrintAndLog("Sending bytes to proxmark failed"); } txBuffer_pending = false; - pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty } - + pthread_cond_signal(&txBufferSig); // tell main thread that txBuffer is empty pthread_mutex_unlock(&txBufferMutex); } @@ -262,21 +315,30 @@ __attribute__((force_align_arg_pointer)) * @param show_warning display message after 2 seconds * @return true if command was returned, otherwise false */ -bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) -{ - UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; - SendCommand(&c); +bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning) { uint64_t start_time = msclock(); + UsbCommand c = {CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K, {start_index, bytes, 0}}; + SendCommand(&c); + UsbCommand resp; - if (response == NULL) { + if (response == NULL) { response = &resp; } int bytes_completed = 0; - while(true) { - if (getCommand(response)) { + while (true) { + if (msclock() - start_time > ms_timeout) { + break; // timeout + } + if (msclock() - start_time > 2000 && show_warning) { + // 2 seconds elapsed (but this doesn't mean the timeout was exceeded) + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("You can cancel this operation by pressing the pm3 button"); + show_warning = false; + } + if (getCommand(response, CMD_BUFFER_CHECK_TIME)) { if (response->cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { int copy_bytes = MIN(bytes - bytes_completed, response->arg[1]); memcpy(dest + response->arg[0], response->d.asBytes, copy_bytes); @@ -285,35 +347,30 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon return true; } } - - if (msclock() - start_time > ms_timeout) { - break; - } - - if (msclock() - start_time > 2000 && show_warning) { - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("You can cancel this operation by pressing the pm3 button"); - show_warning = false; - } } return false; } - -bool GetFromFpgaRAM(uint8_t *dest, int bytes) -{ - UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}}; - SendCommand(&c); + +bool GetFromFpgaRAM(uint8_t *dest, int bytes) { uint64_t start_time = msclock(); + UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}}; + SendCommand(&c); + UsbCommand response; - + int bytes_completed = 0; bool show_warning = true; - while(true) { - if (getCommand(&response)) { + while (true) { + if (msclock() - start_time > 2000 && show_warning) { + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("You can cancel this operation by pressing the pm3 button"); + show_warning = false; + } + if (getCommand(&response, CMD_BUFFER_CHECK_TIME)) { if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]); memcpy(dest + response.arg[0], response.d.asBytes, copy_bytes); @@ -322,19 +379,13 @@ bool GetFromFpgaRAM(uint8_t *dest, int bytes) return true; } } - - if (msclock() - start_time > 2000 && show_warning) { - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("You can cancel this operation by pressing the pm3 button"); - show_warning = false; - } } return false; } -bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) { +bool OpenProxmark(void *port, bool wait_for_port, int timeout) { char *portname = (char *)port; if (!wait_for_port) { sp = uart_open(portname); @@ -347,7 +398,7 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) msleep(1000); printf("."); fflush(stdout); - } while(++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); + } while (++openCount < timeout && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT)); printf("\n"); } @@ -366,7 +417,6 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) // start the USB communication thread serial_port_name = portname; conn.run = true; - conn.block_after_ACK = flash_mode; pthread_create(&USB_communication_thread, NULL, &uart_communication, &conn); return true; } @@ -394,15 +444,6 @@ void CloseProxmark(void) { uart_close(sp); } -#if defined(__linux__) && !defined(NO_UNLINK) - // Fix for linux, it seems that it is extremely slow to release the serial port file descriptor /dev/* - // - // This may be disabled at compile-time with -DNO_UNLINK (used for a JNI-based serial port on Android). - if (serial_port_name) { - unlink(serial_port_name); - } -#endif - // Clean up our state sp = NULL; serial_port_name = NULL; @@ -430,30 +471,28 @@ bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeo printf("Waiting for %04x cmd\n", cmd); #endif + uint64_t start_time = msclock(); + if (response == NULL) { response = &resp; } - uint64_t start_time = msclock(); - // Wait until the command is received while (true) { - while(getCommand(response)) { - if (cmd == CMD_UNKNOWN || response->cmd == cmd) { - return true; - } - } - - if (msclock() - start_time > ms_timeout) { - break; + if (ms_timeout != -1 && msclock() > start_time + ms_timeout) { + break; // timeout } - if (msclock() - start_time > 2000 && show_warning) { // 2 seconds elapsed (but this doesn't mean the timeout was exceeded) PrintAndLog("Waiting for a response from the proxmark..."); PrintAndLog("You can cancel this operation by pressing the pm3 button"); show_warning = false; } + if (getCommand(response, CMD_BUFFER_CHECK_TIME)) { + if (cmd == CMD_UNKNOWN || response->cmd == cmd) { + return true; + } + } } return false; } diff --git a/client/comms.h b/client/comms.h index 65294695..64957604 100644 --- a/client/comms.h +++ b/client/comms.h @@ -9,32 +9,24 @@ // Code for communicating with the proxmark3 hardware. //----------------------------------------------------------------------------- -#ifndef COMMS_H_ -#define COMMS_H_ +#ifndef COMMS_H__ +#define COMMS_H__ +#include +#include #include -#include - #include "usb_cmd.h" -#include "uart.h" - -#ifndef CMD_BUFFER_SIZE -#define CMD_BUFFER_SIZE 50 -#endif - -void SetOffline(bool new_offline); -bool IsOffline(); - -bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode); -void CloseProxmark(void); - -void SendCommand(UsbCommand *c); - -void clearCommandBuffer(); -bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning); -bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout); -bool WaitForResponse(uint32_t cmd, UsbCommand* response); -bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning); -bool GetFromFpgaRAM(uint8_t *dest, int bytes); -#endif // COMMS_H_ +extern void SetOffline(bool new_offline); +extern bool IsOffline(); +extern bool OpenProxmark(void *port, bool wait_for_port, int timeout); +extern void CloseProxmark(void); +extern void SendCommand(UsbCommand *c); +extern void clearCommandBuffer(); +extern bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning); +extern bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout); +extern bool WaitForResponse(uint32_t cmd, UsbCommand* response); +extern bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning); +extern bool GetFromFpgaRAM(uint8_t *dest, int bytes); + +#endif // COMMS_H__ diff --git a/client/flash.c b/client/flash.c index 9a443cb8..f3d2f420 100644 --- a/client/flash.c +++ b/client/flash.c @@ -185,9 +185,9 @@ static int check_segs(flash_file_t *ctx, int can_write_bl) { return 0; } + // Load an ELF file and prepare it for flashing -int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl) -{ +int flash_load(flash_file_t *ctx, const char *name, bool can_write_bl) { FILE *fd = NULL; Elf32_Ehdr ehdr; Elf32_Phdr *phdrs = NULL; @@ -267,9 +267,9 @@ fail: return -1; } + // Get the state of the proxmark, backwards compatible -static int get_proxmark_state(uint32_t *state) -{ +static int get_proxmark_state(uint32_t *state) { UsbCommand c = {0}; c.cmd = CMD_DEVICE_INFO; SendCommand(&c); @@ -300,9 +300,9 @@ static int get_proxmark_state(uint32_t *state) return 0; } + // Enter the bootloader to be able to start flashing -static int enter_bootloader(char *serial_port_name) -{ +static int enter_bootloader(char *serial_port_name) { uint32_t state; if (get_proxmark_state(&state) < 0) @@ -314,7 +314,7 @@ static int enter_bootloader(char *serial_port_name) } if (state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) { - fprintf(stderr,"Entering bootloader...\n"); + fprintf(stderr, "Entering bootloader...\n"); UsbCommand c; memset(&c, 0, sizeof (c)); @@ -336,7 +336,9 @@ static int enter_bootloader(char *serial_port_name) msleep(100); CloseProxmark(); - bool opened = OpenProxmark(serial_port_name, true, 120, true); // wait for 2 minutes + msleep(1000); // wait for OS to detect device disconnect. + + bool opened = OpenProxmark(serial_port_name, true, 120); // wait for 2 minutes if (opened) { fprintf(stderr," Found.\n"); return 0; @@ -350,6 +352,7 @@ static int enter_bootloader(char *serial_port_name) return -1; } + static int wait_for_ack(void) { UsbCommand ack; @@ -361,11 +364,11 @@ static int wait_for_ack(void) return 0; } + // Go into flashing mode int flash_start_flashing(int enable_bl_writes,char *serial_port_name) { uint32_t state; - if (enter_bootloader(serial_port_name) < 0) return -1; diff --git a/client/flasher.c b/client/flasher.c index a008f7bc..d7fa0b5e 100644 --- a/client/flasher.c +++ b/client/flasher.c @@ -17,7 +17,7 @@ #include "flash.h" #include "comms.h" #include "usb_cmd.h" - +#include "uart.h" void cmd_debug(UsbCommand* UC) { // Debug @@ -83,7 +83,7 @@ int main(int argc, char **argv) char* serial_port_name = argv[1]; - if (!OpenProxmark(serial_port_name, true, 120, true)) { // wait for 2 minutes + if (!OpenProxmark(serial_port_name, true, 120)) { // wait for 2 minutes fprintf(stderr, "Could not find Proxmark on %s.\n\n", serial_port_name); return -1; } else { diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 7b710710..bc53e1fe 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -1164,7 +1164,7 @@ int DetectClassicPrng(void){ clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (!WaitForResponseTimeout(CMD_NACK, &resp, 2000)) { PrintAndLog("PRNG UID: Reply timeout."); return -1; } diff --git a/client/proxmark3.c b/client/proxmark3.c index fda9f313..fb17d13d 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -28,7 +28,7 @@ #include "cmdhw.h" #include "whereami.h" #include "comms.h" - +#include "uart.h" void #ifdef __has_attribute @@ -286,7 +286,7 @@ int main(int argc, char* argv[]) { set_my_executable_path(); // try to open USB connection to Proxmark - usb_present = OpenProxmark(argv[1], waitCOMPort, 20, false); + usb_present = OpenProxmark(argv[1], waitCOMPort, 20); #ifdef HAVE_GUI #ifdef _WIN32 @@ -309,8 +309,10 @@ int main(int argc, char* argv[]) { main_loop(script_cmds_file, script_cmd, usb_present); #endif - // Clean up the port + // Switch off field and clean up the port if (usb_present) { + UsbCommand c = {CMD_FPGA_MAJOR_MODE_OFF}; + SendCommand(&c); CloseProxmark(); } diff --git a/client/scripting.c b/client/scripting.c index 85a788e9..1ad5d214 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "proxmark3.h" #include "comms.h" #include "usb_cmd.h" diff --git a/common/cmd.c b/common/cmd.c deleted file mode 100644 index 0c3ecc1f..00000000 --- a/common/cmd.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Proxmark send and receive commands - * - * Copyright (c) 2012, Roel Verdult - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @file cmd.c - * @brief - */ - -#include "cmd.h" -#include "string.h" -#include "proxmark3.h" - -bool cmd_receive(UsbCommand* cmd) { - - // Check if there is a usb packet available - if (!usb_poll()) return false; - - // Try to retrieve the available command frame - size_t rxlen = usb_read((byte_t*)cmd,sizeof(UsbCommand)); - - // Check if the transfer was complete - if (rxlen != sizeof(UsbCommand)) return false; - - // Received command successfully - return true; -} - -bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len) { - UsbCommand txcmd; - - for (size_t i=0; i +#include +#include + +#include "common.h" #include "at91sam7s512.h" #include "config_gpio.h" - #define AT91C_EP_CONTROL 0 #define AT91C_EP_OUT 1 #define AT91C_EP_IN 2 @@ -49,6 +54,7 @@ #define STR_MANUFACTURER 0x01 #define STR_PRODUCT 0x02 + static const char devDescriptor[] = { /* Device descriptor */ 0x12, // bLength @@ -67,6 +73,7 @@ static const char devDescriptor[] = { 0x01 // bNumConfigs }; + static const char cfgDescriptor[] = { /* ============== CONFIGURATION 1 =========== */ /* Configuration 1 descriptor */ @@ -157,47 +164,50 @@ static const char cfgDescriptor[] = { 0x00 // bInterval }; + static const char StrDescLanguageCodes[] = { - 4, // Length - 0x03, // Type is string - 0x09, 0x04 // supported language Code 0 = 0x0409 (English) + 4, // Length + 0x03, // Type is string + 0x09, 0x04 // supported language Code 0 = 0x0409 (English) }; + // Note: ModemManager (Linux) ignores Proxmark3 devices by matching the // manufacturer string "proxmark.org". Don't change this. static const char StrDescManufacturer[] = { - 26, // Length - 0x03, // Type is string - 'p', 0x00, - 'r', 0x00, - 'o', 0x00, - 'x', 0x00, - 'm', 0x00, - 'a', 0x00, - 'r', 0x00, - 'k', 0x00, - '.', 0x00, - 'o', 0x00, - 'r', 0x00, - 'g', 0x00 + 26, // Length + 0x03, // Type is string + 'p', 0x00, + 'r', 0x00, + 'o', 0x00, + 'x', 0x00, + 'm', 0x00, + 'a', 0x00, + 'r', 0x00, + 'k', 0x00, + '.', 0x00, + 'o', 0x00, + 'r', 0x00, + 'g', 0x00 }; + static const char StrDescProduct[] = { - 20, // Length - 0x03, // Type is string - 'p', 0x00, - 'r', 0x00, - 'o', 0x00, - 'x', 0x00, - 'm', 0x00, - 'a', 0x00, - 'r', 0x00, - 'k', 0x00, - '3', 0x00 + 20, // Length + 0x03, // Type is string + 'p', 0x00, + 'r', 0x00, + 'o', 0x00, + 'x', 0x00, + 'm', 0x00, + 'a', 0x00, + 'r', 0x00, + 'k', 0x00, + '3', 0x00 }; -const char* getStringDescriptor(uint8_t idx) -{ + +static const char* getStringDescriptor(uint8_t idx) { switch (idx) { case STR_LANGUAGE_CODES: return StrDescLanguageCodes; @@ -210,29 +220,31 @@ const char* getStringDescriptor(uint8_t idx) } } + // Bitmap for all status bits in CSR which must be written as 1 to cause no effect -#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \ - |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \ - |AT91C_UDP_TXCOMP +#define REG_NO_EFFECT_1_ALL (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP | AT91C_UDP_TXCOMP) + // Clear flags in the UDP_CSR register #define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \ volatile unsigned int reg; \ - reg = pUdp->UDP_CSR[(endpoint)]; \ + reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \ reg |= REG_NO_EFFECT_1_ALL; \ reg &= ~(flags); \ - pUdp->UDP_CSR[(endpoint)] = reg; \ -} + AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \ +} + // Set flags in the UDP_CSR register #define UDP_SET_EP_FLAGS(endpoint, flags) { \ volatile unsigned int reg; \ - reg = pUdp->UDP_CSR[(endpoint)]; \ + reg = AT91C_BASE_UDP->UDP_CSR[(endpoint)]; \ reg |= REG_NO_EFFECT_1_ALL; \ reg |= (flags); \ - pUdp->UDP_CSR[(endpoint)] = reg; \ + AT91C_BASE_UDP->UDP_CSR[(endpoint)] = reg; \ } + /* USB standard request codes */ #define STD_GET_STATUS_ZERO 0x0080 #define STD_GET_STATUS_INTERFACE 0x0081 @@ -260,6 +272,7 @@ const char* getStringDescriptor(uint8_t idx) #define SET_LINE_CODING 0x2021 #define SET_CONTROL_LINE_STATE 0x2221 + typedef struct { unsigned int dwDTERRate; char bCharFormat; @@ -267,19 +280,17 @@ typedef struct { char bDataBits; } AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING; -AT91S_CDC_LINE_CODING line = { + +static AT91S_CDC_LINE_CODING line = { 115200, // baudrate 0, // 1 Stop Bit 0, // None Parity 8}; // 8 Data bits -void AT91F_CDC_Enumerate(); - -AT91PS_UDP pUdp = AT91C_BASE_UDP; -byte_t btConfiguration = 0; -byte_t btConnection = 0; -byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; +static uint8_t btConfiguration = 0; +static uint8_t btConnection = 0; +static uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0; //*---------------------------------------------------------------------------- @@ -291,8 +302,8 @@ void usb_disable() { AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU; // Clear all lingering interrupts - if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) { - pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES; + if (AT91C_BASE_UDP->UDP_ISR & AT91C_UDP_ENDBUSRES) { + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES; } } @@ -322,7 +333,7 @@ void usb_enable() { usb_disable(); // Wait for a short while - for (volatile size_t i=0; i<0x100000; i++); + for (volatile size_t i = 0; i < 0x100000; i++); // Reconnect USB reconnect AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU; @@ -331,127 +342,16 @@ void usb_enable() { //*---------------------------------------------------------------------------- -//* \fn usb_check -//* \brief Test if the device is configured and handle enumeration -//*---------------------------------------------------------------------------- -bool usb_check() { - AT91_REG isr = pUdp->UDP_ISR; - - if (isr & AT91C_UDP_ENDBUSRES) { - pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES; - // reset all endpoints - pUdp->UDP_RSTEP = (unsigned int)-1; - pUdp->UDP_RSTEP = 0; - // Enable the function - pUdp->UDP_FADDR = AT91C_UDP_FEN; - // Configure endpoint 0 - pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); - } else if (isr & AT91C_UDP_EPINT0) { - pUdp->UDP_ICR = AT91C_UDP_EPINT0; - AT91F_CDC_Enumerate(); - } - return (btConfiguration) ? true : false; -} - - -bool usb_poll() -{ - if (!usb_check()) return false; - return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank); -} - - -/** - In github PR #129, some users appears to get a false positive from - usb_poll, which returns true, but the usb_read operation - still returns 0. - This check is basically the same as above, but also checks - that the length available to read is non-zero, thus hopefully fixes the - bug. -**/ -bool usb_poll_validate_length() -{ - if (!usb_check()) return false; - if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false; - return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0; -} - -//*---------------------------------------------------------------------------- -//* \fn usb_read -//* \brief Read available data from Endpoint OUT -//*---------------------------------------------------------------------------- -uint32_t usb_read(byte_t* data, size_t len) { - byte_t bank = btReceiveBank; - uint32_t packetSize, nbBytesRcv = 0; - uint32_t time_out = 0; - - while (len) { - if (!usb_check()) break; - - if ( pUdp->UDP_CSR[AT91C_EP_OUT] & bank ) { - packetSize = MIN(pUdp->UDP_CSR[AT91C_EP_OUT] >> 16, len); - len -= packetSize; - while(packetSize--) - data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT]; - UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank); - if (bank == AT91C_UDP_RX_DATA_BK0) { - bank = AT91C_UDP_RX_DATA_BK1; - } else { - bank = AT91C_UDP_RX_DATA_BK0; - } - } - if (time_out++ == 0x1fff) break; - } - - btReceiveBank = bank; - return nbBytesRcv; -} - - -//*---------------------------------------------------------------------------- -//* \fn usb_write -//* \brief Send through endpoint 2 +//* \fn AT91F_USB_SendZlp +//* \brief Send zero length packet through an endpoint //*---------------------------------------------------------------------------- -uint32_t usb_write(const byte_t* data, const size_t len) { - size_t length = len; - uint32_t cpt = 0; - - if (!length) return 0; - if (!usb_check()) return 0; - - // Send the first packet - cpt = MIN(length, AT91C_EP_IN_SIZE); - length -= cpt; - while (cpt--) { - pUdp->UDP_FDR[AT91C_EP_IN] = *data++; - } - UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); - - while (length) { - // Fill the next bank - cpt = MIN(length, AT91C_EP_IN_SIZE); - length -= cpt; - while (cpt--) { - pUdp->UDP_FDR[AT91C_EP_IN] = *data++; - } - // Wait for the previous bank to be sent - while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { - if (!usb_check()) return length; - } - UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); - UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); - } - - // Wait for the end of transfer - while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { - if (!usb_check()) return length; - } - - UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP); - - return length; +static void AT91F_USB_SendZlp(uint8_t endpoint) { + UDP_SET_EP_FLAGS(endpoint, AT91C_UDP_TXPKTRDY); + while (!(AT91C_BASE_UDP->UDP_CSR[endpoint] & AT91C_UDP_TXCOMP)) + /* wait */; + UDP_CLEAR_EP_FLAGS(endpoint, AT91C_UDP_TXCOMP); + while (AT91C_BASE_UDP->UDP_CSR[endpoint] & AT91C_UDP_TXCOMP) + /* wait */; } @@ -459,10 +359,7 @@ uint32_t usb_write(const byte_t* data, const size_t len) { //* \fn AT91F_USB_SendData //* \brief Send Data through the control endpoint //*---------------------------------------------------------------------------- -unsigned int csrTab[100] = {0x00}; -unsigned char csrIdx = 0; - -static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t length) { +static void AT91F_USB_SendData(const char *pData, uint32_t length) { uint32_t cpt = 0; AT91_REG csr; @@ -471,54 +368,46 @@ static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t leng length -= cpt; while (cpt--) - pUdp->UDP_FDR[0] = *pData++; + AT91C_BASE_UDP->UDP_FDR[0] = *pData++; - if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { + if (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) + /* wait */; } UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY); do { - csr = pUdp->UDP_CSR[AT91C_EP_CONTROL]; + csr = AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL]; // Data IN stage has been stopped by a status OUT if (csr & AT91C_UDP_RX_DATA_BK0) { UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0); return; } - } while ( !(csr & AT91C_UDP_TXCOMP) ); + } while (!(csr & AT91C_UDP_TXCOMP)); } while (length); - if (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { + if (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) { UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) + /* wait */; } } -//*---------------------------------------------------------------------------- -//* \fn AT91F_USB_SendZlp -//* \brief Send zero length packet through the control endpoint -//*---------------------------------------------------------------------------- -void AT91F_USB_SendZlp(AT91PS_UDP pUdp) { - UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXPKTRDY); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP) ); - UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_TXCOMP); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP); -} - - //*---------------------------------------------------------------------------- //* \fn AT91F_USB_SendStall //* \brief Stall the control endpoint //*---------------------------------------------------------------------------- -void AT91F_USB_SendStall(AT91PS_UDP pUdp) { +static void AT91F_USB_SendStall(void) { UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR) ); + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_ISOERROR)) + /* wait */; UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR); - while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) + /* wait */; } @@ -526,136 +415,349 @@ void AT91F_USB_SendStall(AT91PS_UDP pUdp) { //* \fn AT91F_CDC_Enumerate //* \brief This function is a callback invoked when a SETUP packet is received //*---------------------------------------------------------------------------- -void AT91F_CDC_Enumerate() { - byte_t bmRequestType, bRequest; +static void AT91F_CDC_Enumerate() { + uint8_t bmRequestType, bRequest; uint16_t wValue, wIndex, wLength, wStatus; - if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) ) + if (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP)) return; - bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL]; - bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL]; - wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); - wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8); - wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); - wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8); - wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); - wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8); + bmRequestType = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL]; + bRequest = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL]; + wValue = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); + wValue |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8); + wIndex = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); + wIndex |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8); + wLength = (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] & 0xFF); + wLength |= (AT91C_BASE_UDP->UDP_FDR[AT91C_EP_CONTROL] << 8); - if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host + if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR); - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) ); + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR)) + /* wait */; } UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RXSETUP); - while ( (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) ); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) + /* wait */; // Handle supported standard device request Cf Table 9-3 in USB specification Rev 1.1 switch ((bRequest << 8) | bmRequestType) { case STD_GET_DESCRIPTOR: if (wValue == 0x100) // Return Device Descriptor - AT91F_USB_SendData(pUdp, devDescriptor, MIN(sizeof(devDescriptor), wLength)); + AT91F_USB_SendData(devDescriptor, MIN(sizeof(devDescriptor), wLength)); else if (wValue == 0x200) // Return Configuration Descriptor - AT91F_USB_SendData(pUdp, cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength)); + AT91F_USB_SendData(cfgDescriptor, MIN(sizeof(cfgDescriptor), wLength)); else if ((wValue & 0xF00) == 0x300) { // Return String Descriptor const char *strDescriptor = getStringDescriptor(wValue & 0xff); if (strDescriptor != NULL) { - AT91F_USB_SendData(pUdp, strDescriptor, MIN(strDescriptor[0], wLength)); + AT91F_USB_SendData(strDescriptor, MIN(strDescriptor[0], wLength)); } else { - AT91F_USB_SendStall(pUdp); + AT91F_USB_SendStall(); } } else - AT91F_USB_SendStall(pUdp); + AT91F_USB_SendStall(); break; case STD_SET_ADDRESS: - AT91F_USB_SendZlp(pUdp); - pUdp->UDP_FADDR = (AT91C_UDP_FEN | wValue); - pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; + AT91F_USB_SendZlp(AT91C_EP_CONTROL); + AT91C_BASE_UDP->UDP_FADDR = (AT91C_UDP_FEN | wValue); + AT91C_BASE_UDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0; break; case STD_SET_CONFIGURATION: btConfiguration = wValue; - AT91F_USB_SendZlp(pUdp); - pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; - pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0; - pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; - pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; + AT91F_USB_SendZlp(AT91C_EP_CONTROL); + AT91C_BASE_UDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN; + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0; + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0; + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0; break; case STD_GET_CONFIGURATION: - AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration)); + AT91F_USB_SendData((char *) &(btConfiguration), sizeof(btConfiguration)); break; case STD_GET_STATUS_ZERO: - wStatus = 0; // Device is Bus powered, remote wakeup disabled - AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); + wStatus = 0; // Device is Bus powered, remote wakeup disabled + AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus)); break; case STD_GET_STATUS_INTERFACE: - wStatus = 0; // reserved for future use - AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); + wStatus = 0; // reserved for future use + AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus)); break; case STD_GET_STATUS_ENDPOINT: wStatus = 0; wIndex &= 0x0F; - if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) { - wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); - } - else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) { - wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; - AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus)); - } - else - AT91F_USB_SendStall(pUdp); + if ((AT91C_BASE_UDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) { + wStatus = (AT91C_BASE_UDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus)); + } else if ((AT91C_BASE_UDP->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) { + wStatus = (AT91C_BASE_UDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1; + AT91F_USB_SendData((char *) &wStatus, sizeof(wStatus)); + } else + AT91F_USB_SendStall(); break; case STD_SET_FEATURE_ZERO: - AT91F_USB_SendStall(pUdp); - break; + AT91F_USB_SendStall(); + break; case STD_SET_FEATURE_INTERFACE: - AT91F_USB_SendZlp(pUdp); + AT91F_USB_SendZlp(AT91C_EP_CONTROL); break; case STD_SET_FEATURE_ENDPOINT: wIndex &= 0x0F; if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) { - pUdp->UDP_CSR[wIndex] = 0; - AT91F_USB_SendZlp(pUdp); - } - else - AT91F_USB_SendStall(pUdp); + AT91C_BASE_UDP->UDP_CSR[wIndex] = 0; + AT91F_USB_SendZlp(AT91C_EP_CONTROL); + } else + AT91F_USB_SendStall(); break; case STD_CLEAR_FEATURE_ZERO: - AT91F_USB_SendStall(pUdp); - break; + AT91F_USB_SendStall(); + break; case STD_CLEAR_FEATURE_INTERFACE: - AT91F_USB_SendZlp(pUdp); + AT91F_USB_SendZlp(AT91C_EP_CONTROL); break; case STD_CLEAR_FEATURE_ENDPOINT: wIndex &= 0x0F; if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) { if (wIndex == AT91C_EP_OUT) - pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT); else if (wIndex == AT91C_EP_IN) - pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN); else if (wIndex == AT91C_EP_NOTIFY) - pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); - AT91F_USB_SendZlp(pUdp); + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN); + AT91F_USB_SendZlp(AT91C_EP_CONTROL); } else - AT91F_USB_SendStall(pUdp); + AT91F_USB_SendStall(); break; // handle CDC class requests case SET_LINE_CODING: - while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0) ); + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RX_DATA_BK0)) + /* wait */; UDP_CLEAR_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_RX_DATA_BK0); - AT91F_USB_SendZlp(pUdp); + AT91F_USB_SendZlp(AT91C_EP_CONTROL); break; case GET_LINE_CODING: - AT91F_USB_SendData(pUdp, (char *) &line, MIN(sizeof(line), wLength)); + AT91F_USB_SendData((char *) &line, MIN(sizeof(line), wLength)); break; case SET_CONTROL_LINE_STATE: btConnection = wValue; - AT91F_USB_SendZlp(pUdp); + AT91F_USB_SendZlp(AT91C_EP_CONTROL); break; default: - AT91F_USB_SendStall(pUdp); - break; + AT91F_USB_SendStall(); + break; + } +} + + +//*---------------------------------------------------------------------------- +//* \fn usb_check +//* \brief Test if the device is configured and handle enumeration +//*---------------------------------------------------------------------------- +static bool usb_check() { + AT91_REG isr = AT91C_BASE_UDP->UDP_ISR; + + if (isr & AT91C_UDP_ENDBUSRES) { + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES; + // reset all endpoints + AT91C_BASE_UDP->UDP_RSTEP = (unsigned int)-1; + AT91C_BASE_UDP->UDP_RSTEP = 0; + // Enable the function + AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN; + // Configure endpoint 0 + AT91C_BASE_UDP->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL); + } else if (isr & AT91C_UDP_EPINT0) { + AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_EPINT0; + AT91F_CDC_Enumerate(); + } + return (btConfiguration) ? true : false; +} + + +bool usb_poll() { + if (!usb_check()) return false; + return (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & btReceiveBank); +} + + +/** + In github PR #129, some users appears to get a false positive from + usb_poll, which returns true, but the usb_read operation + still returns 0. + This check is basically the same as above, but also checks + that the length available to read is non-zero, thus hopefully fixes the + bug. +**/ +bool usb_poll_validate_length() { + if (!usb_check()) return false; + if (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false; + return (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] >> 16) > 0; +} + + +//*---------------------------------------------------------------------------- +//* \fn usb_read +//* \brief Read available data from Endpoint OUT +//*---------------------------------------------------------------------------- +static uint32_t usb_read(uint8_t* data, size_t len) { + uint8_t bank = btReceiveBank; + uint32_t packetSize, nbBytesRcv = 0; + uint32_t time_out = 0; + + while (len) { + if (!usb_check()) break; + + if ( AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & bank ) { + packetSize = MIN(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] >> 16, len); + len -= packetSize; + while (packetSize--) + data[nbBytesRcv++] = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_OUT]; + UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank); + if (bank == AT91C_UDP_RX_DATA_BK0) { + bank = AT91C_UDP_RX_DATA_BK1; + } else { + bank = AT91C_UDP_RX_DATA_BK0; + } + } + if (time_out++ == 0x1fff) break; + } + + btReceiveBank = bank; + return nbBytesRcv; +} + + +//*---------------------------------------------------------------------------- +//* \fn usb_write +//* \brief Send through endpoint 2 +//*---------------------------------------------------------------------------- +static uint32_t usb_write(const uint8_t* data, const size_t len) { + size_t length = len; + uint32_t cpt = 0; + + if (!length) return 0; + if (!usb_check()) return 0; + + // Send the first packet + cpt = MIN(length, AT91C_EP_IN_SIZE); + length -= cpt; + while (cpt--) { + AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *data++; + } + UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) + /* wait */; + + while (length) { + // Fill the next bank + cpt = MIN(length, AT91C_EP_IN_SIZE); + length -= cpt; + while (cpt--) { + AT91C_BASE_UDP->UDP_FDR[AT91C_EP_IN] = *data++; + } + // Wait for the previous bank to be sent + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { + if (!usb_check()) return length; + } + UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY); + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) + /* wait */; + UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) + /* wait */; + } + + // Wait for the end of transfer + while (!(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) { + if (!usb_check()) return length; + } + UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP); + while (AT91C_BASE_UDP->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) + /* wait */; + + if (len % AT91C_EP_IN_SIZE == 0) { // need to send a zero length packet to complete the transfer + AT91F_USB_SendZlp(AT91C_EP_IN); } + + return length; +} + + +//*************************************************************************** +// Interface to the main program +//*************************************************************************** + +// The function to receive a command from the client via USB +bool cmd_receive(UsbCommand* cmd) { + + // Check if there is a usb packet available + if (!usb_poll()) + return false; + + // Try to retrieve the available command frame + size_t rxlen = usb_read((uint8_t*)cmd, sizeof(UsbCommand)); + + // Check if the transfer was complete + if (rxlen != sizeof(UsbCommand)) + return false; + + // Received command successfully + return true; } + + +// The function to send a response to the client via USB +bool cmd_send(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) { + + UsbResponse txcmd; + + // Compose the outgoing response frame + txcmd.cmd = cmd | CMD_VARIABLE_SIZE_FLAG; + txcmd.arg[0] = arg0; + txcmd.arg[1] = arg1; + txcmd.arg[2] = arg2; + + // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE + if (data) { + datalen = MIN(datalen, USB_CMD_DATA_SIZE); + for (uint16_t i = 0; i < datalen; i++) { + txcmd.d.asBytes[i] = ((uint8_t*)data)[i]; + } + txcmd.datalen = datalen; + } else { + txcmd.datalen = 0; + } + + // Send frame and make sure all bytes are transmitted + size_t tx_size = offsetof(UsbResponse, d) + datalen; + if (usb_write((uint8_t*)&txcmd, tx_size) != 0) return false; + + return true; +} + + +// For compatibility only: legacy function to send a response with fixed size to the client via USB +bool cmd_send_old(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen) { + + UsbCommand txcmd; + + // Compose the outgoing response frame + txcmd.cmd = cmd; + txcmd.arg[0] = arg0; + txcmd.arg[1] = arg1; + txcmd.arg[2] = arg2; + + // Add the (optional) content to the frame, with a maximum size of USB_CMD_DATA_SIZE + if (data) { + datalen = MIN(datalen, USB_CMD_DATA_SIZE); + for (uint16_t i = 0; i < datalen; i++) { + txcmd.d.asBytes[i] = ((uint8_t*)data)[i]; + } + } + + // Send frame and make sure all bytes are transmitted + if (usb_write((uint8_t*)&txcmd, sizeof(UsbCommand)) != 0) return false; + + return true; +} + diff --git a/common/usb_cdc.h b/common/usb_cdc.h index c42da8db..3fff154d 100644 --- a/common/usb_cdc.h +++ b/common/usb_cdc.h @@ -32,18 +32,20 @@ * @brief */ -#ifndef _USB_CDC_H_ -#define _USB_CDC_H_ +#ifndef USB_CDC_H__ +#define USB_CDC_H__ -#include "common.h" +#include +#include +#include +#include "usb_cmd.h" -void usb_disable(); -void usb_enable(); -bool usb_check(); -bool usb_poll(); -bool usb_poll_validate_length(); -uint32_t usb_read(byte_t* data, size_t len); -uint32_t usb_write(const byte_t* data, const size_t len); - -#endif // _USB_CDC_H_ +extern void usb_disable(); +extern void usb_enable(); +extern bool usb_poll(); +extern bool usb_poll_validate_length(); +extern bool cmd_receive(UsbCommand* cmd); +extern bool cmd_send(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen); // new variable sized response +extern bool cmd_send_old(uint16_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, uint16_t datalen); // old fixed size response +#endif // USB_CDC_H__ diff --git a/include/common.h b/include/common.h index 998db64d..89a6cd7e 100644 --- a/include/common.h +++ b/include/common.h @@ -9,13 +9,9 @@ // Interlib Definitions //----------------------------------------------------------------------------- -#ifndef __COMMON_H -#define __COMMON_H +#ifndef COMMON_H__ +#define COMMON_H__ -#include -#include -#include -#include typedef unsigned char byte_t; #ifndef MIN @@ -25,10 +21,9 @@ typedef unsigned char byte_t; # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #ifndef ABS -# define ABS(a) ( ((a)<0) ? -(a) : (a) ) +# define ABS(a) (((a) < 0) ? -(a) : (a)) #endif - #define RAMFUNC __attribute((long_call, section(".ramfunc"))) #endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index c588328c..a4d164f0 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -10,13 +10,13 @@ // own protocol. //----------------------------------------------------------------------------- -#ifndef __USB_CMD_H -#define __USB_CMD_H +#ifndef USB_CMD_H__ +#define USB_CMD_H__ + #ifdef _MSC_VER typedef DWORD uint32_t; typedef BYTE uint8_t; #define PACKED -// stuff #else #include #include @@ -25,17 +25,29 @@ typedef BYTE uint8_t; #define USB_CMD_DATA_SIZE 512 +// the packets sent from client to PM3 typedef struct { - uint64_t cmd; - uint64_t arg[3]; - union { - uint8_t asBytes[USB_CMD_DATA_SIZE]; - uint32_t asDwords[USB_CMD_DATA_SIZE/4]; - } d; + uint64_t cmd; + uint64_t arg[3]; + union { + uint8_t asBytes[USB_CMD_DATA_SIZE]; + uint32_t asDwords[USB_CMD_DATA_SIZE/4]; + } d; } PACKED UsbCommand; +// the packets sent from PM3 to client (a smaller version of UsbCommand) +typedef struct { + uint16_t cmd; + uint16_t datalen; + uint32_t arg[3]; + union { + uint8_t asBytes[USB_CMD_DATA_SIZE]; + uint32_t asDwords[USB_CMD_DATA_SIZE/4]; + } d; +} PACKED UsbResponse; + // A struct used to send sample-configs over USB -typedef struct{ +typedef struct { uint8_t decimation; uint8_t bits_per_sample; bool averaging; @@ -44,6 +56,7 @@ typedef struct{ int samples_to_skip; } sample_config; + // For the bootloader #define CMD_DEVICE_INFO 0x0000 #define CMD_SETUP_WRITE 0x0001 @@ -165,7 +178,7 @@ typedef struct{ #define CMD_ICLASS_WRITEBLOCK 0x0397 #define CMD_ICLASS_EML_MEMSET 0x0398 #define CMD_ICLASS_CHECK 0x0399 -#define CMD_ICLASS_READCHECK 0x039A +#define CMD_ICLASS_READCHECK 0x039A // For measurements of the antenna tuning #define CMD_MEASURE_ANTENNA_TUNING 0x0400 @@ -208,7 +221,7 @@ typedef struct{ #define CMD_MIFAREU_WRITEBL 0x0722 #define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 #define CMD_MIFAREUC_AUTH 0x0724 -//0x0725 and 0x0726 no longer used +//0x0725 and 0x0726 no longer used #define CMD_MIFAREUC_SETPWD 0x0727 @@ -224,15 +237,16 @@ typedef struct{ #define CMD_HF_SNIFFER 0x0800 #define CMD_HF_PLOT 0x0801 +#define CMD_VARIABLE_SIZE_FLAG 0x8000 #define CMD_UNKNOWN 0xFFFF // Mifare simulation flags -#define FLAG_INTERACTIVE (1<<0) -#define FLAG_4B_UID_IN_DATA (1<<1) -#define FLAG_7B_UID_IN_DATA (1<<2) -#define FLAG_NR_AR_ATTACK (1<<4) -#define FLAG_RANDOM_NONCE (1<<5) +#define FLAG_INTERACTIVE (1<<0) +#define FLAG_4B_UID_IN_DATA (1<<1) +#define FLAG_7B_UID_IN_DATA (1<<2) +#define FLAG_NR_AR_ATTACK (1<<4) +#define FLAG_RANDOM_NONCE (1<<5) // iCLASS reader flags @@ -266,19 +280,19 @@ typedef struct{ // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ -#define DEVICE_INFO_FLAG_BOOTROM_PRESENT (1<<0) +#define DEVICE_INFO_FLAG_BOOTROM_PRESENT (1<<0) /* Whether a osimage that understands the common_area is present */ -#define DEVICE_INFO_FLAG_OSIMAGE_PRESENT (1<<1) +#define DEVICE_INFO_FLAG_OSIMAGE_PRESENT (1<<1) /* Set if the bootloader is currently executing */ -#define DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM (1<<2) +#define DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM (1<<2) /* Set if the OS is currently executing */ -#define DEVICE_INFO_FLAG_CURRENT_MODE_OS (1<<3) +#define DEVICE_INFO_FLAG_CURRENT_MODE_OS (1<<3) /* Set if this device understands the extend start flash command */ -#define DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH (1<<4) +#define DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH (1<<4) /* CMD_START_FLASH may have three arguments: start of area to flash, end of area to flash, optional magic. diff --git a/uart/uart.h b/uart/uart.h index 3b563be2..c0a709cf 100644 --- a/uart/uart.h +++ b/uart/uart.h @@ -29,24 +29,21 @@ * @file uart.h */ -#ifndef _PM3_UART_H_ -#define _PM3_UART_H_ +#ifndef PM3_UART_H__ +#define PM3_UART_H__ -#include -#include #include - #include #include /* Used to substitute for an example serial port path on each platform. */ #ifdef _WIN32 -#define SERIAL_PORT_H "com3" +#define SERIAL_PORT_H "com3" #elif __APPLE__ -#define SERIAL_PORT_H "/dev/tty.usbmodem*" +#define SERIAL_PORT_H "/dev/tty.usbmodem*" #else -#define SERIAL_PORT_H "/dev/ttyACM0" +#define SERIAL_PORT_H "/dev/ttyACM0" #endif /* serial_port is declared as a void*, which you should cast to whatever type @@ -69,11 +66,11 @@ typedef void* serial_port; * * On errors, this method returns INVALID_SERIAL_PORT or CLAIMED_SERIAL_PORT. */ -serial_port uart_open(const char* pcPortName); +extern serial_port uart_open(const char* pcPortName); /* Closes the given port. */ -void uart_close(const serial_port sp); +extern void uart_close(const serial_port sp); /* Reads from the given serial port for up to 30ms. * pbtRx: A pointer to a buffer for the returned data to be written to. @@ -84,15 +81,17 @@ void uart_close(const serial_port sp); * * Returns FALSE if there was an error reading from the device. Note that a * partial read may have completed into the buffer by the corresponding - * implementation, so pszRxLen should be checked to see if any data was written. + * implementation, so pszRxLen should be checked to see if any data was written. */ -bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen); +extern bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen); /* Sends a buffer to a given serial port. * pbtTx: A pointer to a buffer containing the data to send. * szTxLen: The amount of data to be sent. + * + * Returns TRUE if all data could be sent within 30ms. */ -bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen); +extern bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen); /* Sets the current speed of the serial port, in baud. */ @@ -100,7 +99,7 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed); /* Gets the current speed of the serial port, in baud. */ -uint32_t uart_get_speed(const serial_port sp); +extern uint32_t uart_get_speed(const serial_port sp); -#endif // _PM3_UART_H_ +#endif // PM3_UART_H__ diff --git a/uart/uart_posix.c b/uart/uart_posix.c old mode 100644 new mode 100755 index 29a02cf7..f6e6519d --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -1,391 +1,370 @@ -/* - * Generic uart / rs232/ serial port library - * - * Copyright (c) 2013, Roel Verdult - * Copyright (c) 2018 Google - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holders nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * @file uart_posix.c - * - * This version of the library has functionality removed which was not used by - * proxmark3 project. - */ - -// Test if we are dealing with posix operating systems -#ifndef _WIN32 -#define _DEFAULT_SOURCE - -#include "uart.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Fix missing definition on OS X. -// Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 -#ifndef SOL_TCP -#define SOL_TCP IPPROTO_TCP -#endif - -typedef struct termios term_info; -typedef struct { - int fd; // Serial port file descriptor - term_info tiOld; // Terminal info before using the port - term_info tiNew; // Terminal info during the transaction -} serial_port_unix; - -// Set time-out on 30 miliseconds -struct timeval timeout = { - .tv_sec = 0, // 0 second - .tv_usec = 30000 // 30000 micro seconds -}; - -serial_port uart_open(const char* pcPortName) -{ - serial_port_unix* sp = malloc(sizeof(serial_port_unix)); - if (sp == 0) return INVALID_SERIAL_PORT; - - if (memcmp(pcPortName, "tcp:", 4) == 0) { - struct addrinfo *addr = NULL, *rp; - char *addrstr = strdup(pcPortName + 4); - if (addrstr == NULL) { - printf("Error: strdup\n"); - return INVALID_SERIAL_PORT; - } - char *colon = strrchr(addrstr, ':'); - char *portstr; - - // Set time-out to 300 miliseconds only for TCP port - timeout.tv_usec = 300000; - - if (colon) { - portstr = colon + 1; - *colon = '\0'; - } else - portstr = "7901"; - - struct addrinfo info; - - memset (&info, 0, sizeof(info)); - - info.ai_socktype = SOCK_STREAM; - - int s = getaddrinfo(addrstr, portstr, &info, &addr); - if (s != 0) { - printf("Error: getaddrinfo: %s\n", gai_strerror(s)); - return INVALID_SERIAL_PORT; - } - - int sfd; - for (rp = addr; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (sfd == -1) - continue; - - if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) - break; - - close(sfd); - } - - if (rp == NULL) { /* No address succeeded */ - printf("Error: Could not connect\n"); - return INVALID_SERIAL_PORT; - } - - freeaddrinfo(addr); - free(addrstr); - - sp->fd = sfd; - - int one = 1; - setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); - return sp; - } - - sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); - if(sp->fd == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Finally figured out a way to claim a serial port interface under unix - // We just try to set a (advisory) lock on the file descriptor - struct flock fl; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_pid = getpid(); - - // Does the system allows us to place a lock on this file descriptor - if (fcntl(sp->fd, F_SETLK, &fl) == -1) { - // A conflicting lock is held by another process - free(sp); - return CLAIMED_SERIAL_PORT; - } - - // Try to retrieve the old (current) terminal info struct - if(tcgetattr(sp->fd,&sp->tiOld) == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Duplicate the (old) terminal info struct - sp->tiNew = sp->tiOld; - - // Configure the serial port - sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; - sp->tiNew.c_iflag = IGNPAR; - sp->tiNew.c_oflag = 0; - sp->tiNew.c_lflag = 0; - - // Block until n bytes are received - sp->tiNew.c_cc[VMIN] = 0; - // Block until a timer expires (n * 100 mSec.) - sp->tiNew.c_cc[VTIME] = 0; - - // Try to set the new terminal info struct - if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Flush all lingering data that may exist - tcflush(sp->fd, TCIOFLUSH); - - return sp; -} - -void uart_close(const serial_port sp) { - serial_port_unix* spu = (serial_port_unix*)sp; - tcflush(spu->fd,TCIOFLUSH); - tcsetattr(spu->fd,TCSANOW,&(spu->tiOld)); - struct flock fl; - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - fl.l_pid = getpid(); - fcntl(spu->fd, F_SETLK, &fl); - close(spu->fd); - free(sp); -} - -bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) { - int res; - int byteCount; - fd_set rfds; - struct timeval tv; - - // Reset the output count - *pszRxLen = 0; - - do { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd,&rfds); - tv = timeout; - res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv); - - // Read error - if (res < 0) { - return false; - } - - // Read time-out - if (res == 0) { - if (*pszRxLen == 0) { - // Error, we received no data - return false; - } else { - // We received some data, but nothing more is available - return true; - } - } - - // Retrieve the count of the incoming bytes - res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); - if (res < 0) return false; - - // Cap the number of bytes, so we don't overrun the buffer - if (pszMaxRxLen - (*pszRxLen) < byteCount) { - byteCount = pszMaxRxLen - (*pszRxLen); - } - - // There is something available, read the data - res = read(((serial_port_unix*)sp)->fd, pbtRx+(*pszRxLen), byteCount); - - // Stop if the OS has some troubles reading the data - if (res <= 0) return false; - - *pszRxLen += res; - - if (*pszRxLen == pszMaxRxLen) { - // We have all the data we wanted. - return true; - } - - } while (byteCount); - - return true; -} - -bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { - int32_t res; - size_t szPos = 0; - fd_set rfds; - struct timeval tv; - - while (szPos < szTxLen) { - // Reset file descriptor - FD_ZERO(&rfds); - FD_SET(((serial_port_unix*)sp)->fd,&rfds); - tv = timeout; - res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv); - - // Write error - if (res < 0) { - return false; - } - - // Write time-out - if (res == 0) { - return false; - } - - // Send away the bytes - res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos); - - // Stop if the OS has some troubles sending the data - if (res <= 0) return false; - - szPos += res; - } - return true; -} - -bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { - const serial_port_unix* spu = (serial_port_unix*)sp; - speed_t stPortSpeed; - switch (uiPortSpeed) { - case 0: stPortSpeed = B0; break; - case 50: stPortSpeed = B50; break; - case 75: stPortSpeed = B75; break; - case 110: stPortSpeed = B110; break; - case 134: stPortSpeed = B134; break; - case 150: stPortSpeed = B150; break; - case 300: stPortSpeed = B300; break; - case 600: stPortSpeed = B600; break; - case 1200: stPortSpeed = B1200; break; - case 1800: stPortSpeed = B1800; break; - case 2400: stPortSpeed = B2400; break; - case 4800: stPortSpeed = B4800; break; - case 9600: stPortSpeed = B9600; break; - case 19200: stPortSpeed = B19200; break; - case 38400: stPortSpeed = B38400; break; -# ifdef B57600 - case 57600: stPortSpeed = B57600; break; -# endif -# ifdef B115200 - case 115200: stPortSpeed = B115200; break; -# endif -# ifdef B230400 - case 230400: stPortSpeed = B230400; break; -# endif -# ifdef B460800 - case 460800: stPortSpeed = B460800; break; -# endif -# ifdef B921600 - case 921600: stPortSpeed = B921600; break; -# endif - default: return false; - }; - struct termios ti; - if (tcgetattr(spu->fd,&ti) == -1) return false; - // Set port speed (Input and Output) - cfsetispeed(&ti,stPortSpeed); - cfsetospeed(&ti,stPortSpeed); - return (tcsetattr(spu->fd,TCSANOW,&ti) != -1); -} - -uint32_t uart_get_speed(const serial_port sp) { - struct termios ti; - uint32_t uiPortSpeed; - const serial_port_unix* spu = (serial_port_unix*)sp; - if (tcgetattr(spu->fd,&ti) == -1) return 0; - // Set port speed (Input) - speed_t stPortSpeed = cfgetispeed(&ti); - switch (stPortSpeed) { - case B0: uiPortSpeed = 0; break; - case B50: uiPortSpeed = 50; break; - case B75: uiPortSpeed = 75; break; - case B110: uiPortSpeed = 110; break; - case B134: uiPortSpeed = 134; break; - case B150: uiPortSpeed = 150; break; - case B300: uiPortSpeed = 300; break; - case B600: uiPortSpeed = 600; break; - case B1200: uiPortSpeed = 1200; break; - case B1800: uiPortSpeed = 1800; break; - case B2400: uiPortSpeed = 2400; break; - case B4800: uiPortSpeed = 4800; break; - case B9600: uiPortSpeed = 9600; break; - case B19200: uiPortSpeed = 19200; break; - case B38400: uiPortSpeed = 38400; break; -# ifdef B57600 - case B57600: uiPortSpeed = 57600; break; -# endif -# ifdef B115200 - case B115200: uiPortSpeed = 115200; break; -# endif -# ifdef B230400 - case B230400: uiPortSpeed = 230400; break; -# endif -# ifdef B460800 - case B460800: uiPortSpeed = 460800; break; -# endif -# ifdef B921600 - case B921600: uiPortSpeed = 921600; break; -# endif - default: return 0; - }; - return uiPortSpeed; -} - -#endif - +/* + * Generic uart / rs232/ serial port library + * + * Copyright (c) 2013, Roel Verdult + * Copyright (c) 2018 Google + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @file uart_posix.c + * + * This version of the library has functionality removed which was not used by + * proxmark3 project. + */ + +// Test if we are dealing with posix operating systems +#ifndef _WIN32 +#define _DEFAULT_SOURCE + +#include "uart.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Fix missing definition on OS X. +// Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif + +typedef struct termios term_info; +typedef struct { + int fd; // Serial port file descriptor + term_info tiOld; // Terminal info before using the port + term_info tiNew; // Terminal info during the transaction +} serial_port_unix; + +// Set time-out on 30 miliseconds +static struct timeval timeout = { + .tv_sec = 0, // 0 second + .tv_usec = 30000 // 30000 micro seconds +}; + + +void uart_close(const serial_port sp) { + serial_port_unix* spu = (serial_port_unix*)sp; + tcflush(spu->fd, TCIOFLUSH); + tcsetattr(spu->fd, TCSANOW, &(spu->tiOld)); + struct flock fl; + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + fcntl(spu->fd, F_SETLK, &fl); + close(spu->fd); + free(sp); +} + + +serial_port uart_open(const char* pcPortName) { + + serial_port_unix* sp = malloc(sizeof(serial_port_unix)); + if (sp == 0) return INVALID_SERIAL_PORT; + + if (memcmp(pcPortName, "tcp:", 4) == 0) { + struct addrinfo *addr = NULL, *rp; + char *addrstr = strdup(pcPortName + 4); + if (addrstr == NULL) { + printf("Error: strdup\n"); + return INVALID_SERIAL_PORT; + } + char *colon = strrchr(addrstr, ':'); + char *portstr; + + // Set time-out to 300 milliseconds only for TCP port + timeout.tv_usec = 300000; + + if (colon) { + portstr = colon + 1; + *colon = '\0'; + } else { + portstr = "7901"; + } + + struct addrinfo info; + + memset(&info, 0, sizeof(info)); + + info.ai_socktype = SOCK_STREAM; + + int s = getaddrinfo(addrstr, portstr, &info, &addr); + if (s != 0) { + printf("Error: getaddrinfo: %s\n", gai_strerror(s)); + return INVALID_SERIAL_PORT; + } + + int sfd; + for (rp = addr; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) + continue; + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + close(sfd); + } + + if (rp == NULL) { /* No address succeeded */ + printf("Error: Could not connect\n"); + return INVALID_SERIAL_PORT; + } + + freeaddrinfo(addr); + free(addrstr); + + sp->fd = sfd; + + int one = 1; + setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); + return sp; + } + + sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if (sp->fd == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Finally figured out a way to claim a serial port interface under unix + // We just try to set a (advisory) lock on the file descriptor + struct flock fl; + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + fl.l_pid = getpid(); + + // Does the system allows us to place a lock on this file descriptor + if (fcntl(sp->fd, F_SETLK, &fl) == -1) { + // A conflicting lock is held by another process + free(sp); + return CLAIMED_SERIAL_PORT; + } + + // Try to retrieve the old (current) terminal info struct + if (tcgetattr(sp->fd,&sp->tiOld) == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Duplicate the (old) terminal info struct + sp->tiNew = sp->tiOld; + + // Configure the serial port + sp->tiNew.c_cflag &= ~(CSIZE | PARENB); + sp->tiNew.c_cflag |= (CS8 | CLOCAL | CREAD); + sp->tiNew.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + sp->tiNew.c_iflag |= IGNPAR; + sp->tiNew.c_oflag &= ~OPOST; + sp->tiNew.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + + + // Try to set the new terminal info struct + if (tcsetattr(sp->fd, TCSANOW, &sp->tiNew) == -1) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Flush all lingering data that may exist + tcflush(sp->fd, TCIOFLUSH); + + return sp; +} + + +bool uart_receive(const serial_port sp, uint8_t* pbtRx, size_t szMaxRxLen, size_t* pszRxLen) { + + *pszRxLen = 0; + + if (szMaxRxLen == 0) return true; + + struct timeval t_current; + gettimeofday(&t_current, NULL); + struct timeval t_end; + timeradd(&t_current, &timeout, &t_end); + + while (true) { + int res = read(((serial_port_unix*)sp)->fd, pbtRx, szMaxRxLen - *pszRxLen); + if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) return false; + if (res > 0) { + *pszRxLen += res; + pbtRx += res; + } + if (*pszRxLen == szMaxRxLen) return true; // we could read all requested bytes in time + gettimeofday(&t_current, NULL); + if (timercmp(&t_current, &t_end, >)) return true; // timeout + // set next select timeout + struct timeval t_remains; + timersub(&t_end, &t_current, &t_remains); + // Set the file descriptor set + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(((serial_port_unix*)sp)->fd, &rfds); + // wait for more bytes available + res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &t_remains); + if (res < 0) return false; + if (res == 0) return true; // timeout + } + return true; // should never come here +} + + +bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { + + if (szTxLen == 0) return true; + + size_t bytes_written = 0; + + struct timeval t_current; + gettimeofday(&t_current, NULL); + struct timeval t_end; + timeradd(&t_current, &timeout, &t_end); + + while (true) { + int res = write(((serial_port_unix*)sp)->fd, pbtTx, szTxLen - bytes_written); + if (res < 0 && res != EAGAIN && res != EWOULDBLOCK) return false; + if (res > 0) { + pbtTx += res; + bytes_written += res; + } + if (bytes_written == szTxLen) return true; // we could write all bytes + gettimeofday(&t_current, NULL); + if (timercmp(&t_current, &t_end, >)) return false; // timeout + // set next select timeout + struct timeval t_remains; + timersub(&t_end, &t_current, &t_remains); + // Set the file descriptor set + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(((serial_port_unix*)sp)->fd, &wfds); + // wait until more bytes can be written + res = select(((serial_port_unix*)sp)->fd+1, NULL, &wfds, NULL, &t_remains); + if (res < 0) return false; // error + if (res == 0) return false; // timeout + } + return true; +} + + +bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { + const serial_port_unix* spu = (serial_port_unix*)sp; + speed_t stPortSpeed; + switch (uiPortSpeed) { + case 0: stPortSpeed = B0; break; + case 50: stPortSpeed = B50; break; + case 75: stPortSpeed = B75; break; + case 110: stPortSpeed = B110; break; + case 134: stPortSpeed = B134; break; + case 150: stPortSpeed = B150; break; + case 300: stPortSpeed = B300; break; + case 600: stPortSpeed = B600; break; + case 1200: stPortSpeed = B1200; break; + case 1800: stPortSpeed = B1800; break; + case 2400: stPortSpeed = B2400; break; + case 4800: stPortSpeed = B4800; break; + case 9600: stPortSpeed = B9600; break; + case 19200: stPortSpeed = B19200; break; + case 38400: stPortSpeed = B38400; break; +# ifdef B57600 + case 57600: stPortSpeed = B57600; break; +# endif +# ifdef B115200 + case 115200: stPortSpeed = B115200; break; +# endif +# ifdef B230400 + case 230400: stPortSpeed = B230400; break; +# endif +# ifdef B460800 + case 460800: stPortSpeed = B460800; break; +# endif +# ifdef B921600 + case 921600: stPortSpeed = B921600; break; +# endif + default: return false; + }; + struct termios ti; + if (tcgetattr(spu->fd, &ti) == -1) return false; + // Set port speed (Input and Output) + cfsetispeed(&ti,stPortSpeed); + cfsetospeed(&ti,stPortSpeed); + return (tcsetattr(spu->fd, TCSANOW, &ti) != -1); +} + +uint32_t uart_get_speed(const serial_port sp) { + struct termios ti; + uint32_t uiPortSpeed; + const serial_port_unix* spu = (serial_port_unix*)sp; + if (tcgetattr(spu->fd, &ti) == -1) return 0; + // Set port speed (Input) + speed_t stPortSpeed = cfgetispeed(&ti); + switch (stPortSpeed) { + case B0: uiPortSpeed = 0; break; + case B50: uiPortSpeed = 50; break; + case B75: uiPortSpeed = 75; break; + case B110: uiPortSpeed = 110; break; + case B134: uiPortSpeed = 134; break; + case B150: uiPortSpeed = 150; break; + case B300: uiPortSpeed = 300; break; + case B600: uiPortSpeed = 600; break; + case B1200: uiPortSpeed = 1200; break; + case B1800: uiPortSpeed = 1800; break; + case B2400: uiPortSpeed = 2400; break; + case B4800: uiPortSpeed = 4800; break; + case B9600: uiPortSpeed = 9600; break; + case B19200: uiPortSpeed = 19200; break; + case B38400: uiPortSpeed = 38400; break; +# ifdef B57600 + case B57600: uiPortSpeed = 57600; break; +# endif +# ifdef B115200 + case B115200: uiPortSpeed = 115200; break; +# endif +# ifdef B230400 + case B230400: uiPortSpeed = 230400; break; +# endif +# ifdef B460800 + case B460800: uiPortSpeed = 460800; break; +# endif +# ifdef B921600 + case B921600: uiPortSpeed = 921600; break; +# endif + default: return 0; + }; + return uiPortSpeed; +} + +#endif diff --git a/uart/uart_win32.c b/uart/uart_win32.c index b15e8786..0e4227de 100644 --- a/uart/uart_win32.c +++ b/uart/uart_win32.c @@ -38,97 +38,109 @@ #include "uart.h" +#include +#include +#include + + // The windows serial port implementation #ifdef _WIN32 #include typedef struct { - HANDLE hPort; // Serial port handle - DCB dcb; // Device control settings - COMMTIMEOUTS ct; // Serial port time-out configuration + HANDLE hPort; // Serial port handle + DCB dcb; // Device control settings + COMMTIMEOUTS ct; // Serial port time-out configuration } serial_port_windows; + void upcase(char *p) { - while(*p != '\0') { - if(*p >= 97 && *p <= 122) { - *p -= 32; - } - ++p; - } + while(*p != '\0') { + if(*p >= 97 && *p <= 122) { + *p -= 32; + } + ++p; + } } -serial_port uart_open(const char* pcPortName) { - char acPortName[255]; - serial_port_windows* sp = malloc(sizeof(serial_port_windows)); - - // Copy the input "com?" to "\\.\COM?" format - sprintf(acPortName,"\\\\.\\%s",pcPortName); - upcase(acPortName); - - // Try to open the serial port - sp->hPort = CreateFileA(acPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); - if (sp->hPort == INVALID_HANDLE_VALUE) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Prepare the device control - memset(&sp->dcb, 0, sizeof(DCB)); - sp->dcb.DCBlength = sizeof(DCB); - if(!BuildCommDCBA("baud=9600 data=8 parity=N stop=1",&sp->dcb)) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - // Update the active serial port - if(!SetCommState(sp->hPort,&sp->dcb)) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - sp->ct.ReadIntervalTimeout = 0; - sp->ct.ReadTotalTimeoutMultiplier = 0; - sp->ct.ReadTotalTimeoutConstant = 30; - sp->ct.WriteTotalTimeoutMultiplier = 0; - sp->ct.WriteTotalTimeoutConstant = 30; - - if(!SetCommTimeouts(sp->hPort,&sp->ct)) { - uart_close(sp); - return INVALID_SERIAL_PORT; - } - - PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR); - - return sp; -} void uart_close(const serial_port sp) { - CloseHandle(((serial_port_windows*)sp)->hPort); - free(sp); + CloseHandle(((serial_port_windows*)sp)->hPort); + free(sp); } + +serial_port uart_open(const char* pcPortName) { + char acPortName[255]; + serial_port_windows* sp = malloc(sizeof(serial_port_windows)); + + // Copy the input "com?" to "\\.\COM?" format + sprintf(acPortName,"\\\\.\\%s",pcPortName); + upcase(acPortName); + + // Try to open the serial port + sp->hPort = CreateFileA(acPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (sp->hPort == INVALID_HANDLE_VALUE) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Prepare the device control + memset(&sp->dcb, 0, sizeof(DCB)); + sp->dcb.DCBlength = sizeof(DCB); + if (!BuildCommDCBA("baud=9600 data=8 parity=N stop=1",&sp->dcb)) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + // Update the active serial port + if (!SetCommState(sp->hPort,&sp->dcb)) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + sp->ct.ReadIntervalTimeout = 0; + sp->ct.ReadTotalTimeoutMultiplier = 0; + sp->ct.ReadTotalTimeoutConstant = 30; + sp->ct.WriteTotalTimeoutMultiplier = 0; + sp->ct.WriteTotalTimeoutConstant = 30; + + if (!SetCommTimeouts(sp->hPort, &sp->ct)) { + uart_close(sp); + return INVALID_SERIAL_PORT; + } + + PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR); + + return sp; +} + + bool uart_receive(const serial_port sp, uint8_t *pbtRx, size_t pszMaxRxLen, size_t *pszRxLen) { - return ReadFile(((serial_port_windows*)sp)->hPort, pbtRx, pszMaxRxLen, (LPDWORD)pszRxLen, NULL); + return ReadFile(((serial_port_windows*)sp)->hPort, pbtRx, pszMaxRxLen, (LPDWORD)pszRxLen, NULL); } + bool uart_send(const serial_port sp, const uint8_t* pbtTx, const size_t szTxLen) { - DWORD dwTxLen = 0; - return WriteFile(((serial_port_windows*)sp)->hPort, pbtTx, szTxLen, &dwTxLen, NULL); + DWORD dwTxLen = 0; + return WriteFile(((serial_port_windows*)sp)->hPort, pbtTx, szTxLen, &dwTxLen, NULL); } + bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) { - serial_port_windows* spw; - spw = (serial_port_windows*)sp; - spw->dcb.BaudRate = uiPortSpeed; - return SetCommState(spw->hPort, &spw->dcb); + serial_port_windows* spw; + spw = (serial_port_windows*)sp; + spw->dcb.BaudRate = uiPortSpeed; + return SetCommState(spw->hPort, &spw->dcb); } + uint32_t uart_get_speed(const serial_port sp) { - const serial_port_windows* spw = (serial_port_windows*)sp; - if (!GetCommState(spw->hPort, (serial_port)&spw->dcb)) { - return spw->dcb.BaudRate; - } - return 0; + const serial_port_windows* spw = (serial_port_windows*)sp; + if (!GetCommState(spw->hPort, (serial_port)&spw->dcb)) { + return spw->dcb.BaudRate; + } + return 0; } #endif