diff --git a/armsrc/Makefile b/armsrc/Makefile index 8ecbb8b3f..1d435e73a 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -23,6 +23,7 @@ APP_CFLAGS = -DWITH_CRC \ -DWITH_FELICA \ -DWITH_FLASH \ -DWITH_SMARTCARD \ + -DWITH_FPC \ -DWITH_HFSNOOP \ -DWITH_LF_SAMYRUN \ -fno-strict-aliasing -ffunction-sections -fdata-sections @@ -54,7 +55,8 @@ SRC_CRC = crc.c crc16.c crc32.c SRC_ICLASS = iclass.c optimized_cipher.c SRC_LEGIC = legicrf.c legic_prng.c SRC_FLASH = flashmem.c -SRC_SMARTCARD = smartcard.c +SRC_SMARTCARD = i2c.c +SRC_FPC = usart.c SRC_BEE = bee.c #the FPGA bitstream files. Note: order matters! @@ -81,6 +83,7 @@ THUMBSRC = start.c \ $(SRC_LEGIC) \ $(SRC_FLASH) \ $(SRC_SMARTCARD) \ + $(SRC_FPC) \ appmain.c \ printf.c \ util.c \ diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 48fa42d4b..43999634e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -29,7 +29,7 @@ #endif #ifdef WITH_SMARTCARD -#include "smartcard.h" +#include "i2c.h" #endif @@ -382,7 +382,7 @@ void SendStatus(void) { Fpga_print_status(); Flashmem_print_status(); #ifdef WITH_SMARTCARD - SmartCard_print_status(); + i2c_print_status(); #endif #ifdef WITH_LF printConfig(); //LF Sampling config @@ -688,7 +688,10 @@ void UsbPacketReceived(uint8_t *packet, int len) { CopyIndala64toT55x7(c->arg[0], c->arg[1]); break; case CMD_INDALA_CLONE_TAG_L: - CopyIndala224toT55x7(c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6]); + CopyIndala224toT55x7( + c->d.asDwords[0], c->d.asDwords[1], c->d.asDwords[2], c->d.asDwords[3], + c->d.asDwords[4], c->d.asDwords[5], c->d.asDwords[6] + ); break; case CMD_T55XX_READ_BLOCK: T55xxReadBlock(c->arg[0], c->arg[1], c->arg[2]); @@ -706,8 +709,14 @@ void UsbPacketReceived(uint8_t *packet, int len) { ReadPCF7931(); break; case CMD_PCF7931_WRITE: - WritePCF7931(c->d.asBytes[0], c->d.asBytes[1], c->d.asBytes[2], c->d.asBytes[3], c->d.asBytes[4], c->d.asBytes[5], c->d.asBytes[6], c->d.asBytes[9], - c->d.asBytes[7] - 128, c->d.asBytes[8] - 128, c->arg[0], c->arg[1], c->arg[2]); + WritePCF7931( + c->d.asBytes[0], c->d.asBytes[1], c->d.asBytes[2], c->d.asBytes[3], + c->d.asBytes[4], c->d.asBytes[5], c->d.asBytes[6], c->d.asBytes[9], + c->d.asBytes[7] - 128, c->d.asBytes[8] - 128, + c->arg[0], + c->arg[1], + c->arg[2] + ); break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[0], c->arg[1], c->arg[2]); @@ -1012,6 +1021,26 @@ void UsbPacketReceived(uint8_t *packet, int len) { HfSnoop(c->arg[0], c->arg[1]); break; #endif +#ifdef WITH_SMARTCARD + case CMD_SMART_SEND: { + + // sending to smart card. + I2C_Reset_EnterMainProgram(); + + // sample: + // [C0 02] A0 A4 00 00 02 + // asBytes = A0 A4 00 00 02 + // arg0 = len 5 + I2C_BufferWrite(c->d.asBytes, c->arg[0], I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN); + + uint8_t resp[255] = {0}; + uint8_t len = I2C_BufferRead(resp, 255, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN); + Dbhexdump(len, resp, false); + + cmd_send(CMD_ACK, len, 0, 0, resp, len); + break; + } +#endif case CMD_BUFF_CLEAR: BigBuf_Clear(); @@ -1251,10 +1280,12 @@ void UsbPacketReceived(uint8_t *packet, int len) { case CMD_SET_ADC_MUX: switch(c->arg[0]) { case 0: SetAdcMuxFor(GPIO_MUXSEL_LOPKD); break; - case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break; case 2: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); break; +#ifndef WITH_FPC + case 1: SetAdcMuxFor(GPIO_MUXSEL_LORAW); break; case 3: SetAdcMuxFor(GPIO_MUXSEL_HIRAW); break; - } +#endif + } break; case CMD_VERSION: @@ -1265,6 +1296,11 @@ void UsbPacketReceived(uint8_t *packet, int len) { break; case CMD_PING: cmd_send(CMD_ACK,0,0,0,0,0); + + char header[] = {"*** Iceman Usart ***"}; + uint32_t res = usart_writebuffer((uint8_t *)header, sizeof(header), 100000); + Dbprintf("after sending FPC [%x]", res); + break; #ifdef WITH_LCD case CMD_LCD_RESET: @@ -1305,7 +1341,7 @@ void UsbPacketReceived(uint8_t *packet, int len) { break; } default: - Dbprintf("%s: 0x%04x","unknown command:",c->cmd); + Dbprintf("%s: 0x%04x","unknown command:", c->cmd); break; } } @@ -1330,7 +1366,7 @@ void __attribute__((noreturn)) AppMain(void) { // The FPGA gets its clock from us from PCK0 output, so set that up. AT91C_BASE_PIOA->PIO_BSR = GPIO_PCK0; AT91C_BASE_PIOA->PIO_PDR = GPIO_PCK0; - AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_PCK0; + AT91C_BASE_PMC->PMC_SCER |= AT91C_PMC_PCK0; // PCK0 is PLL clock / 4 = 96Mhz / 4 = 24Mhz AT91C_BASE_PMC->PMC_PCKR[0] = AT91C_PMC_CSS_PLL_CLK | AT91C_PMC_PRES_CLK_4; // 4 for 24Mhz pck0, 2 for 48 MHZ pck0 AT91C_BASE_PIOA->PIO_OER = GPIO_PCK0; @@ -1356,21 +1392,30 @@ void __attribute__((noreturn)) AppMain(void) { #endif #ifdef WITH_SMARTCARD - SmartCard_init(); + I2C_init(); #endif - - byte_t rx[sizeof(UsbCommand)]; +#ifdef WITH_FPC + usart_init(); +#endif + uint8_t rx[sizeof(UsbCommand)]; for(;;) { WDT_HIT(); - // Check if there is a usb packet available - if ( cmd_receive( (UsbCommand*)rx ) ) - UsbPacketReceived(rx, sizeof(UsbCommand) ); - -#ifdef WITH_SMARTCARD - SMART_CARD_ServiceSmartCard(); +#ifdef WITH_FPC + // check if there is a FPC USART1 message? + /* + uint32_t fpc_rxlen = usart_read(rx, sizeof(UsbCommand)); + if ( fpc_rxlen > 0) + Dbprintf("got a package [len %d] %02x", fpc_rxlen, rx[0]); + */ #endif + + // Check if there is a usb packet available + if ( cmd_receive( (UsbCommand*)rx ) ) { + UsbPacketReceived(rx, sizeof(UsbCommand) ); + } + // Press button for one second to enter a possible standalone mode if (BUTTON_HELD(1000) > 0) { diff --git a/common/i2c.c b/common/i2c.c new file mode 100644 index 000000000..f6451ed22 --- /dev/null +++ b/common/i2c.c @@ -0,0 +1,364 @@ +//----------------------------------------------------------------------------- +// Willok, June 2018 +// Edits by Iceman, July 2018 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// The main i2c code, for communications with smart card module +//----------------------------------------------------------------------------- +#include "i2c.h" + +// 定义连接引脚 +#define GPIO_RST AT91C_PIO_PA1 +#define GPIO_SCL AT91C_PIO_PA5 +#define GPIO_SDA AT91C_PIO_PA7 + +#define SCL_H HIGH(GPIO_SCL) +#define SCL_L LOW(GPIO_SCL) +#define SDA_H HIGH(GPIO_SDA) +#define SDA_L LOW(GPIO_SDA) + +#define SCL_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SCL) +#define SDA_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SDA) + +#define I2C_PageSize 8 + + +// 直接使用循环来延时,一个循环 6 条指令,48M, Delay=1 大概为 200kbps +void I2CSpinDelayClk(uint16_t delay) __attribute__((optimize("O0"))); +void I2CSpinDelayClk(uint16_t delay) { + volatile uint32_t c; + for (c = delay * 2; c; c--) {}; +} + +void I2C_init(void) { + // 配置复位引脚,关闭上拉,推挽输出,默认高 + // Configure reset pin, close up pull up, push-pull output, default high + AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; + AT91C_BASE_PIOA->PIO_MDDR = GPIO_RST; + + // 配置 I2C 引脚,开启上拉,开漏输出 + // Configure I2C pin, open up, open leakage + AT91C_BASE_PIOA->PIO_PPUER = GPIO_SCL | GPIO_SDA; // 打开上拉 Open up the pull up + AT91C_BASE_PIOA->PIO_MDER = GPIO_SCL | GPIO_SDA; + + // 默认三根线全部拉高 + // default three lines all pull up + AT91C_BASE_PIOA->PIO_SODR = GPIO_SCL | GPIO_SDA | GPIO_RST; + + // 允许输出 + // allow output + AT91C_BASE_PIOA->PIO_OER = GPIO_SCL | GPIO_SDA | GPIO_RST; + AT91C_BASE_PIOA->PIO_PER = GPIO_SCL | GPIO_SDA | GPIO_RST; +} + +#define I2C_DELAY_1CLK I2CSpinDelayClk(1) +#define I2C_DELAY_2CLK I2CSpinDelayClk(2) +#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) + +// 设置复位状态 +// set the reset state +void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) { + if (LineRST) + HIGH(GPIO_RST); + else + LOW(GPIO_RST); + + if (LineSCK) + HIGH(GPIO_SCL); + else + LOW(GPIO_SCL); + + if (LineSDA) + HIGH(GPIO_SDA); + else + LOW(GPIO_SDA); +} + +// 复位进入主程序 +// Reset the SIM_Adapter, then enter the main program +// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter. +void I2C_Reset_EnterMainProgram(void) { + I2C_SetResetStatus(0, 0, 0); // 拉低复位线 + SpinDelay(100); + I2C_SetResetStatus(1, 0, 0); // 解除复位 + SpinDelay(100); + I2C_SetResetStatus(1, 1, 1); // 拉高数据线 +} + +// 复位进入引导模式 +// Reset the SIM_Adapter, then enter the bootloader program +// Reserve:For firmware update. +void I2C_Reset_EnterBootloader(void) { + I2C_SetResetStatus(0, 1, 1); // 拉低复位线 + SpinDelay(100); + I2C_SetResetStatus(1, 1, 1); // 解除复位 +} + +// 等待时钟变高 +// Wait for the clock to go High. +bool WaitSCL_H(void) { + + volatile uint16_t count = 5000; + + while (count--) { + if (SCL_read) { + return true; + } + I2C_DELAY_1CLK; + } + return false; +} + +bool I2C_Start(void) { + + I2C_DELAY_XCLK(4); + SDA_H; + I2C_DELAY_1CLK; + SCL_H; + + if (!WaitSCL_H()) return false; + + I2C_DELAY_2CLK; + + if (!SCL_read) return false; + if (!SDA_read) return false; + + SDA_L; I2C_DELAY_2CLK; + return true; +} + +// send i2c STOP +void I2C_Stop(void) { + SCL_L; I2C_DELAY_2CLK; + SDA_L; I2C_DELAY_2CLK; + SCL_H; I2C_DELAY_2CLK; + SDA_H; + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; + I2C_DELAY_2CLK; +} +// Send i2c ACK +void I2C_Ack(void) { + SCL_L; I2C_DELAY_2CLK; + SDA_L; I2C_DELAY_2CLK; + SCL_H; I2C_DELAY_2CLK; + SCL_L; I2C_DELAY_2CLK; +} + +// Send i2c NACK +void I2C_NoAck(void) { + SCL_L; I2C_DELAY_2CLK; + SDA_H; I2C_DELAY_2CLK; + SCL_H; I2C_DELAY_2CLK; + SCL_L; I2C_DELAY_2CLK; +} + +bool I2C_WaitAck(void) { + SCL_L; I2C_DELAY_1CLK; + SDA_H; I2C_DELAY_1CLK; + SCL_H; + if (!WaitSCL_H()) + return false; + + I2C_DELAY_2CLK; + if (SDA_read) { + SCL_L; + return false; + } + SCL_L; + return true; +} + +void I2C_SendByte(uint8_t data) { + uint8_t i = 8; + + while (i--) { + SCL_L; I2C_DELAY_1CLK; + + if (data & 0x80) + SDA_H; + else + SDA_L; + + data <<= 1; + I2C_DELAY_1CLK; + + SCL_H; + if (!WaitSCL_H()) + return; + + I2C_DELAY_2CLK; + } + SCL_L; +} + +uint8_t I2C_ReceiveByte(void) { + uint8_t i = 8, b = 0; + + SDA_H; + while (i--) { + b <<= 1; + SCL_L; I2C_DELAY_2CLK; + SCL_H; + if (!WaitSCL_H()) + return 0; + + I2C_DELAY_2CLK; + if (SDA_read) + b |= 0x01; + } + SCL_L; + return b; +} + +// 写入1字节数据 (待写入数据,待写入地址,器件类型) +// Writes 1 byte data (Data to be written,command to be written , SlaveDevice address ). +bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) { + bool bBreak = true; + do { + if (!I2C_Start()) + return false; + + I2C_SendByte(device_address & 0xFE); + + if (!I2C_WaitAck()) + break; + + I2C_SendByte(device_cmd); + if (!I2C_WaitAck()) + break; + + I2C_SendByte(data); + if (!I2C_WaitAck()) + break; + + bBreak = false; + } while (false); + + if (bBreak) { + I2C_Stop(); + DbpString("I2C_WaitAck Error\n"); + return false; + } + + I2C_Stop(); + return true; +} + + +// 写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型) +// Write 1 strings of data (Array address, length, command to be written , SlaveDevice address ). +// len = uint8 (max buffer to write 256bytes) +bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { + bool bBreak = true; + + do { + if (!I2C_Start()) + return false; + + I2C_SendByte(device_address & 0xFE); + + if (!I2C_WaitAck()) + break; + + I2C_SendByte(device_cmd); + + if (!I2C_WaitAck()) + break; + + while (len) { + I2C_SendByte(*data); + + if (!I2C_WaitAck()) + break; + + len--; + data++; + } + + if (len == 0) + bBreak = false; + } while (false); + + if (bBreak) { + I2C_Stop(); + DbpString("I2C_WaitAck Error\n"); + return false; + } + + I2C_Stop(); + return true; +} + +// 读出1串数据(存放读出数据,待读出长度,带读出地址,器件类型) +// read 1 strings of data (Data storage array, Readout length, command to be written , SlaveDevice address ). +// len = uint8 (max buffer to read 256bytes) +uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { + bool bBreak = true; + uint8_t readcount = 0; + + // sending + do { + if (!I2C_Start()) + return 0; + + I2C_SendByte(device_address & 0xFE); + + if (!I2C_WaitAck()) + break; + + I2C_SendByte(device_cmd); + if (!I2C_WaitAck()) + break; + + I2C_Start(); + I2C_SendByte(device_address | 1); + if (!I2C_WaitAck()) + break; + + bBreak = false; + } while (false); + + if (bBreak) { + I2C_Stop(); + DbpString("I2C_WaitAck Error\n"); + return 0; + } + + // reading + while (len) { + len--; + *data = I2C_ReceiveByte(); + // 读取的第一个字节为后续长度 + // The first byte read is the message length + if (!readcount && (len > *data)) + len = *data; + + if (len == 0) + I2C_NoAck(); + else + I2C_Ack(); + + data++; + readcount++; + } + + I2C_Stop(); + return readcount; +} + +void i2c_print_status(void) { + DbpString("Smart card module (ISO 7816)"); + + I2C_init(); + I2C_Reset_EnterMainProgram(); + // get version + uint8_t resp[3] = {0}; + uint8_t len = I2C_BufferRead(resp, 3, I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN); + if ( len == 3) + Dbprintf(" FW version................v%x.%02x", resp[1], resp[2]); +} \ No newline at end of file diff --git a/common/i2c.h b/common/i2c.h new file mode 100644 index 000000000..bec05de41 --- /dev/null +++ b/common/i2c.h @@ -0,0 +1,33 @@ +#ifndef __I2C_H +#define __I2C_H + +#include +#include "proxmark3.h" +#include "apps.h" +#include "util.h" + + +#define I2C_DEVICE_ADDRESS_BOOT 0xB0 +#define I2C_DEVICE_ADDRESS_MAIN 0xC0 + +#define I2C_DEVICE_CMD_GENERATE_ATR 0x01 +#define I2C_DEVICE_CMD_SEND 0x02 +#define I2C_DEVICE_CMD_READ 0x03 +#define I2C_DEVICE_CMD_SETBAUD 0x04 +#define I2C_DEVICE_CMD_SIM_CLC 0x05 +#define I2C_DEVICE_CMD_GETVERSION 0x06 + + +void I2C_init(void); +void I2C_Reset(void); +void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA); + +void I2C_Reset_EnterMainProgram(void); +void I2C_Reset_EnterBootloader(void); + +bool I2C_WriteByte(uint8_t SendData, uint8_t device_cmd, uint8_t device_address); +bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address); +uint8_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address); + +void i2c_print_status(void); +#endif \ No newline at end of file