diff --git a/Doc/Fun_with_Icode.pdf b/Doc/Fun_with_Icode.pdf new file mode 100755 index 00000000..7fbd11b5 Binary files /dev/null and b/Doc/Fun_with_Icode.pdf differ diff --git a/Dumps/ICODE_SLIXL_example.dmp b/Dumps/ICODE_SLIXL_example.dmp new file mode 100644 index 00000000..5a7b6723 Binary files /dev/null and b/Dumps/ICODE_SLIXL_example.dmp differ diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index c773a22e..2cb634b5 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -21,6 +21,7 @@ #include "TITagitstandard.h" #include "Sniff14443A.h" #include "EM4233.h" +#include "ICODE-SLIL.h" /* Function wrappers */ INLINE void ApplicationInit(void) { diff --git a/Firmware/Chameleon-Mini/Application/EM4233.c b/Firmware/Chameleon-Mini/Application/EM4233.c index 0bf28b26..2e0d0824 100644 --- a/Firmware/Chameleon-Mini/Application/EM4233.c +++ b/Firmware/Chameleon-Mini/Application/EM4233.c @@ -22,10 +22,7 @@ static enum { STATE_QUIET } State; -bool loggedIn; -uint8_t MyAFI; /* This variable holds current tag's AFI (is used in inventory) */ - -CurrentFrame FrameInfo; +bool EM4233LoggedIn; void EM4233AppInit(void) { State = STATE_READY; @@ -36,7 +33,7 @@ void EM4233AppInit(void) { FrameInfo.ParamLen = 0; FrameInfo.Addressed = false; FrameInfo.Selected = false; - loggedIn = false; + EM4233LoggedIn = false; MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1); } @@ -50,7 +47,7 @@ void EM4233AppReset(void) { FrameInfo.ParamLen = 0; FrameInfo.Addressed = false; FrameInfo.Selected = false; - loggedIn = false; + EM4233LoggedIn = false; } void EM4233AppTask(void) { @@ -498,14 +495,14 @@ uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) { #ifdef EM4233_LOGIN_YES_CARD /* Accept any password from reader as correct one */ - loggedIn = true; + EM4233LoggedIn = true; MemoryWriteBlock(FrameInfo.Parameters, EM4233_MEM_PSW_ADDRESS, 4); /* Store password in memory for retrival */ #else /* Check if the password is actually the right one */ if (memcmp(Password, FrameInfo.Parameters, 4) != 0) { /* Incorrect password */ - loggedIn = false; + EM4233LoggedIn = false; // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; @@ -515,7 +512,7 @@ uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) { #endif - loggedIn = true; + EM4233LoggedIn = true; FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ ResponseByteCount += 1; diff --git a/Firmware/Chameleon-Mini/Application/EM4233.h b/Firmware/Chameleon-Mini/Application/EM4233.h index dbd0e491..c4360999 100644 --- a/Firmware/Chameleon-Mini/Application/EM4233.h +++ b/Firmware/Chameleon-Mini/Application/EM4233.h @@ -24,16 +24,16 @@ #define EM4233_MEM_DSFID_ADDRESS 0xD9 // DSFID byte adress #define EM4233_MEM_INF_ADDRESS 0xDC // Some status bits -#define EM4233_MEM_LSM_ADDRESS 0xE0 // From 0xE0 to 0x0113 - Lock status masks +#define EM4233_MEM_LSM_ADDRESS 0xE0 // From 0xE0 to 0x0113 - Memory blocks lock status masks #define EM4233_MEM_PSW_ADDRESS 0x0114 // From 0x0114 to 0x0117 - 32 bit Password #define EM4233_MEM_KEY_ADDRESS 0x0118 // From 0x0118 to 0x0123 - 96 bit Encryption Key #define EM4233_SYSINFO_BYTE 0x0F // == DSFID - AFI - VICC mem size - IC ref are present /* Bit masks */ -#define EM4233_MASK_READ_PROT ( 1 << 2 ) // For lock status byte +#define EM4233_MASK_READ_PROT ( 1 << 2 ) // For block status byte #define EM4233_MASK_WRITE_PROT ( 1 << 3 ) -#define EM4233_MASK_AFI_STATUS ( 1 << 0 ) +#define EM4233_MASK_AFI_STATUS ( 1 << 0 ) // For status bits #define EM4233_MASK_DSFID_STATUS ( 1 << 1 ) /* Custom command code */ @@ -55,7 +55,7 @@ /* Proprietary command code */ #define EM4233_CMD_AUTH1 0xE0 #define EM4233_CMD_AUTH2 0xE1 -#define EM4233_CMD_GEN_READ 0xE2 // Implies some sort of singed CRC. Unknown at the moment +#define EM4233_CMD_GEN_READ 0xE2 // Implies some sort of signed CRC. Unknown at the moment #define EM4233_CMD_GEN_WRITE 0xE3 // Same #define EM4233_CMD_LOGIN 0xE4 diff --git a/Firmware/Chameleon-Mini/Application/ICODE-SLIL.c b/Firmware/Chameleon-Mini/Application/ICODE-SLIL.c new file mode 100644 index 00000000..8282a909 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ICODE-SLIL.c @@ -0,0 +1,648 @@ +/* + * ICODE-SLIL.c + * + * Created on: 27.12.2019 + * Author: ceres-c & fptrs + * + * TODO: + * - EAS handling + * - All commands marked as TODO in ICODE-SLIL.h + * - Long range commands (if possible) + * - Compile time switch for nonrandom get-random response + * - Compile time switch for Tonies (privacy mode enabled by default)? + * + * NOTES: + * - To emulate Tonies, set State as STATE_PRIV in ICODEAppInit and ICODEAppReset + */ + +#include "../Random.h" +#include "ISO15693-A.h" +#include "ICODE-SLIL.h" + +static enum { + STATE_READY, + STATE_SELECTED, + STATE_QUIET, + STATE_PRIV +} State; + +bool SLILLoggedIn; + +void ICODEAppInit(void) { + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + SLILLoggedIn = false; + MemoryReadBlock(&MyAFI, ICODE_MEM_AFI_ADDRESS, 1); + +} + +void ICODEAppReset(void) { + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + SLILLoggedIn = false; +} + +void ICODEAppTask(void) { + +} + +void ICODEAppTick(void) { + +} + +uint16_t ICODE_GetRandom(uint8_t * FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint16_t random = 0; // super random + FrameBuf[0] = ISO15693_RES_FLAG_NO_ERROR; + memcpy(FrameBuf + 0x1, &random, 2); + ResponseByteCount +=3; + return ResponseByteCount; +} + +uint16_t ICODE_SetPassword(uint8_t * FrameBuf, uint16_t FrameBytes) { + /* accept any password */ + FrameBuf[0] = ISO15693_RES_FLAG_NO_ERROR; + State = STATE_READY; + return 1; +} + +uint16_t ICODE_Lock_Block(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t BlockAddress = *FrameInfo.Parameters; + uint8_t LockStatus = 0; + + MemoryReadBlock(&LockStatus, (ICODE_MEM_LSM_ADDRESS + BlockAddress), 1); + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress > ICODE_NUMBER_OF_BLCKS) { + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; /* malformed: trying to lock a non-existing block */ + } + + + if (LockStatus > ISO15693_MASK_UNLOCKED) { /* LockStatus 0x00 represent unlocked block, greater values are different kind of locks */ + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + } else { + LockStatus |= ISO15693_MASK_USER_LOCK; + MemoryWriteBlock(&LockStatus, (ICODE_MEM_LSM_ADDRESS + BlockAddress), 1); /* write user lock in memory */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + } + + return ResponseByteCount; +} + +uint16_t ICODE_Write_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t BlockAddress = *FrameInfo.Parameters; + uint8_t *Dataptr = FrameInfo.Parameters + 0x01; /* Data to write begins on 2nd byte of the frame received by the reader */ + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 5) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress > ICODE_NUMBER_OF_BLCKS) { + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; /* malformed: trying to write in a non-existing block */ + } + + MemoryReadBlock(&LockStatus, (ICODE_MEM_LSM_ADDRESS + BlockAddress), 1); + + if (LockStatus & ISO15693_MASK_FACTORY_LOCK) { + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway - probably: no factory lock exists? */ + } else if (LockStatus & ISO15693_MASK_USER_LOCK) { + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_CHG_LKD; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + } else { + MemoryWriteBlock(Dataptr, BlockAddress * ICODE_BYTES_PER_BLCK, ICODE_BYTES_PER_BLCK); + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + } + + return ResponseByteCount; +} + +uint16_t ICODE_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t FramePtr; /* holds the address where block's data will be put */ + uint8_t BlockAddress = FrameInfo.Parameters[0]; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress >= ICODE_NUMBER_OF_BLCKS) { /* check if the reader is requesting a sector out of bound */ + if (FrameInfo.Addressed) { /* If the request is addressed */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */ + ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ + } + return ResponseByteCount; /* If not addressed real tag does not respond */ + } + + FramePtr = 1; + + if (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_OPTION) { /* request with option flag set */ + MemoryReadBlock(&LockStatus, (ICODE_MEM_LSM_ADDRESS + BlockAddress), 1); + if (LockStatus & ISO15693_MASK_FACTORY_LOCK) { /* tests if the n-th bit of the factory bitmask if set to 1 */ + FrameBuf[FramePtr] = ISO15693_MASK_FACTORY_LOCK; /* return bit 1 set as 1 (factory locked) */ + } else if (LockStatus & ISO15693_MASK_USER_LOCK) { /* tests if the n-th bit of the user bitmask if set to 1 */ + FrameBuf[FramePtr] = ISO15693_MASK_USER_LOCK; /* return bit 0 set as 1 (user locked) */ + } else + FrameBuf[FramePtr] = ISO15693_MASK_UNLOCKED; /* return lock status 00 (unlocked) */ + FramePtr += 1; /* block's data from byte 2 */ + ResponseByteCount += 1; + } + + MemoryReadBlock(&FrameBuf[FramePtr], BlockAddress * ICODE_BYTES_PER_BLCK, ICODE_BYTES_PER_BLCK); + ResponseByteCount += 4; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + + return ResponseByteCount; +} + +uint16_t ICODE_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t FramePtr; /* holds the address where block's data will be put */ + uint8_t BlockAddress = FrameInfo.Parameters[0]; + uint8_t BlocksNumber = FrameInfo.Parameters[1] + 0x01; /* according to ISO standard, we have to read 0x08 blocks if we get 0x07 in request */ + + if (FrameInfo.ParamLen != 2) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress >= ICODE_NUMBER_OF_BLCKS) { /* the reader is requesting a block out of bound */ + if (FrameInfo.Addressed) { /* If the request is addressed */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = 0x0F; /* Magic number from real tag */ + ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ + } + return ResponseByteCount; /* If not addressed real tag does not respond */ + } else if ((BlockAddress + BlocksNumber) >= ICODE_NUMBER_OF_BLCKS) { /* last block is out of bound */ + BlocksNumber = ICODE_NUMBER_OF_BLCKS - BlockAddress; /* we read up to latest block, as real tag does */ + } + + FramePtr = 1; /* start of response data */ + + if ((FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_OPTION) == 0) { /* blocks' lock status is not requested */ + /* read data straight into frame */ + MemoryReadBlock(&FrameBuf[FramePtr], BlockAddress * ICODE_BYTES_PER_BLCK, BlocksNumber * ICODE_BYTES_PER_BLCK); + ResponseByteCount += BlocksNumber * ICODE_BYTES_PER_BLCK; + + } else { /* we have to slice blocks' data with lock statuses */ + uint8_t DataBuffer[ BlocksNumber * ICODE_BYTES_PER_BLCK ]; /* a temporary vector with blocks' content */ + uint8_t LockStatusBuffer[ BlocksNumber ]; /* a temporary vector with blocks' lock status */ + + /* read all at once to reduce timing issues */ + MemoryReadBlock(&DataBuffer, BlockAddress * ICODE_BYTES_PER_BLCK, BlocksNumber * ICODE_BYTES_PER_BLCK); + MemoryReadBlock(&LockStatusBuffer, ICODE_MEM_LSM_ADDRESS + BlockAddress, BlocksNumber); + + for (uint8_t block = 0; block < BlocksNumber; block++) { /* we cycle through the blocks */ + + /* add lock status */ + FrameBuf[FramePtr++] = LockStatusBuffer[block]; /* Byte in dump equals to the byte that has to be sent */ + /* I.E. We store 0x01 to identify user lock, which is the same as what ISO15693 enforce */ + ResponseByteCount += 1; + + /* then copy block's data */ + FrameBuf[FramePtr++] = DataBuffer[block * ICODE_BYTES_PER_BLCK + 0]; + FrameBuf[FramePtr++] = DataBuffer[block * ICODE_BYTES_PER_BLCK + 1]; + FrameBuf[FramePtr++] = DataBuffer[block * ICODE_BYTES_PER_BLCK + 2]; + FrameBuf[FramePtr++] = DataBuffer[block * ICODE_BYTES_PER_BLCK + 3]; + ResponseByteCount += ICODE_BYTES_PER_BLCK; + } + } + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t ICODE_Write_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t AFI = FrameInfo.Parameters[0]; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + MemoryReadBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); + + if (LockStatus & ICODE_MASK_AFI_STATUS) { /* The AFI is locked */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + // ResponseByteCount += 2; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; + } + + MemoryWriteBlock(&AFI, ICODE_MEM_AFI_ADDRESS, 1); /* Actually write new AFI */ + MyAFI = AFI; /* And update global variable */ + + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + // ResponseByteCount += 1; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; +} + +uint16_t ICODE_Lock_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 0) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + MemoryReadBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); + + if (LockStatus & ICODE_MASK_AFI_STATUS) { /* The AFI is already locked */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + // ResponseByteCount += 2; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; + } + + LockStatus |= ICODE_MASK_AFI_STATUS; + + MemoryWriteBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); /* Write in info bits AFI lockdown */ + + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + // ResponseByteCount += 1; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; +} + +uint16_t ICODE_Write_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t DSFID = FrameInfo.Parameters[0]; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + MemoryReadBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); + + if (LockStatus & ICODE_MASK_DSFID_STATUS) { /* The DSFID is locked */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + // ResponseByteCount += 2; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; + } + + MemoryWriteBlock(&DSFID, ICODE_MEM_DSFID_ADDRESS, 1); /* Actually write new DSFID */ + + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + // ResponseByteCount += 1; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; +} + +uint16_t ICODE_Lock_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 0) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + MemoryReadBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); + + if (LockStatus & ICODE_MASK_DSFID_STATUS) { /* The DSFID is already locked */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + // ResponseByteCount += 2; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; + } + + LockStatus |= ICODE_MASK_DSFID_STATUS; + + MemoryWriteBlock(&LockStatus, ICODE_MEM_INF_ADDRESS, 1); /* Write in info bits DSFID lockdown */ + + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + // ResponseByteCount += 1; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; +} + +uint8_t ICODE_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t FramePtr; /* holds the address where block's data will be put */ + + if (FrameInfo.ParamLen != 0) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + FramePtr = 1; + + /* I've no idea how this request could generate errors ._. + if ( ) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + ResponseByteCount += 2; + return ResponseByteCount; + } + */ + + /* System info flags */ + FrameBuf[FramePtr] = EM4233_SYSINFO_BYTE; /* check EM4233SLIC datasheet for this */ + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + + /* Then append UID */ + uint8_t Uid[ActiveConfiguration.UidSize]; + ICODEGetUid(Uid); + ISO15693CopyUid(&FrameBuf[FramePtr], Uid); + FramePtr += ISO15693_GENERIC_UID_SIZE; /* Move forward the buffer data pointer */ + ResponseByteCount += ISO15693_GENERIC_UID_SIZE; /* Increment the response count */ + + /* Append DSFID */ + if (EM4233_SYSINFO_BYTE & (1 << 0)) { + MemoryReadBlock(&FrameBuf[FramePtr], ICODE_MEM_DSFID_ADDRESS, 1); + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + } + + /* Append AFI */ + if (EM4233_SYSINFO_BYTE & (1 << 1)) { + MemoryReadBlock(&FrameBuf[FramePtr], ICODE_MEM_AFI_ADDRESS, 1); + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + } + + /* Append VICC memory size */ + if (EM4233_SYSINFO_BYTE & (1 << 2)) { + FrameBuf[FramePtr] = ICODE_NUMBER_OF_BLCKS - 0x01; + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + + FrameBuf[FramePtr] = ICODE_BYTES_PER_BLCK - 0x01; + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + } + + /* Append IC reference */ + if (EM4233_SYSINFO_BYTE & (1 << 3)) { + FrameBuf[FramePtr] = ICODE_IC_REFERENCE; + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + } + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t ICODE_Get_Multi_Block_Sec_Stat(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t FramePtr; /* holds the address where block's data will be put */ + uint8_t BlockAddress = FrameInfo.Parameters[0]; + uint8_t BlocksNumber = FrameInfo.Parameters[1] + 0x01; + + if (FrameInfo.ParamLen != 2) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress > ICODE_NUMBER_OF_BLCKS) { /* the reader is requesting a starting block out of bound */ + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_NOT_AVL; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* real tag does not respond anyway */ + return ResponseByteCount; + } else if ((BlockAddress + BlocksNumber) >= ICODE_NUMBER_OF_BLCKS) { /* last block is out of bound */ + BlocksNumber = ICODE_NUMBER_OF_BLCKS - BlockAddress; /* we read up to latest block, as real tag does */ + } + + FramePtr = 1; /* start of response data */ + + /* read all at once to reduce timing issues */ + MemoryReadBlock(&FrameBuf[FramePtr], ICODE_MEM_LSM_ADDRESS + BlockAddress, BlocksNumber); + ResponseByteCount += BlocksNumber; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t ICODE_Select(uint8_t *FrameBuf, uint16_t FrameBytes, uint8_t *Uid) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + /* I've no idea how this request could generate errors ._. + if ( ) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + ResponseByteCount += 2; + return ResponseByteCount; + } + */ + + bool UidEquals = ISO15693CompareUid(&FrameBuf[ISO15693_REQ_ADDR_PARAM], Uid); + + if (!(FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_ADDRESS) || + (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_SELECT) + ) { + /* tag should remain silent if Select is performed without address flag or with select flag */ + return ISO15693_APP_NO_RESPONSE; + } else if (!UidEquals) { + /* tag should remain silent and reset if Select is performed against another UID, + * whether our the tag is selected or not + */ + State = STATE_READY; + return ISO15693_APP_NO_RESPONSE; + } else if (State != STATE_SELECTED && UidEquals) { + State = STATE_SELECTED; + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + return ResponseByteCount; + } + + /* This should never happen (TM), I've added it to shut the compiler up */ + State = STATE_READY; + return ISO15693_APP_NO_RESPONSE; +} + +uint16_t ICODE_Reset_To_Ready(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + /* I've no idea how this request could generate errors ._. + if ( ) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + ResponseByteCount += 2; + return ResponseByteCount; + } + */ + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + + State = STATE_READY; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t ICODE_Login(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Password[4] = { 0 }; + + if (FrameInfo.ParamLen != 4 || !FrameInfo.Addressed || !(FrameInfo.Selected && State == STATE_SELECTED)) + /* Malformed: not enough or too much data. Also this command only works in addressed mode */ + return ISO15693_APP_NO_RESPONSE; + + MemoryReadBlock(&Password, EM4233_MEM_PSW_ADDRESS, 4); + +#ifdef EM4233_LOGIN_YES_CARD + /* Accept any password from reader as correct one */ + SLILLoggedIn = true; + + MemoryWriteBlock(FrameInfo.Parameters, EM4233_MEM_PSW_ADDRESS, 4); /* Store password in memory for retrival */ + +#else + /* Check if the password is actually the right one */ + if (memcmp(Password, FrameInfo.Parameters, 4) != 0) { /* Incorrect password */ + SLILLoggedIn = false; + + // FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + // FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; + return ResponseByteCount; + } + +#endif + + SLILLoggedIn = true; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t ICODEAppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Uid[ActiveConfiguration.UidSize]; + ICODEGetUid(Uid); + + if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) + /* malformed frame */ + return ResponseByteCount; + + if (FrameBuf[ISO15693_REQ_ADDR_CMD] == ISO15693_CMD_SELECT) { + /* Select has its own path before PrepareFrame because we have to change the variable State + * from Select to Ready if "Select" cmd is addressed to another tag. + * It felt weird to add this kind of check in ISO15693PrepareFrame, which should not + * interfere with tag specific variables, such as State in this case. + */ + ResponseByteCount = ICODE_Select(FrameBuf, FrameBytes, Uid); + } else if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, State == STATE_SELECTED, Uid, MyAFI)) + return ISO15693_APP_NO_RESPONSE; + + if (State == STATE_READY || State == STATE_SELECTED) { + + if (*FrameInfo.Command == ISO15693_CMD_INVENTORY) { + if (FrameInfo.ParamLen == 0) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (ISO15693AntiColl(FrameBuf, FrameBytes, &FrameInfo, Uid)) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + MemoryReadBlock(&FrameBuf[ISO15693_RES_ADDR_PARAM], ICODE_MEM_DSFID_ADDRESS, 1); + ISO15693CopyUid(&FrameBuf[ISO15693_RES_ADDR_PARAM + 0x01], Uid); + ResponseByteCount += 10; + } + + } else if ((*FrameInfo.Command == ISO15693_CMD_STAY_QUIET) && FrameInfo.Addressed) { + State = STATE_QUIET; + + } else if (*FrameInfo.Command == ISO15693_CMD_READ_SINGLE) { + ResponseByteCount = ICODE_Read_Single(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_SINGLE) { + ResponseByteCount = ICODE_Write_Single(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_BLOCK) { + ResponseByteCount = ICODE_Lock_Block(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_READ_MULTIPLE) { + ResponseByteCount = ICODE_Read_Multiple(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_AFI) { + ResponseByteCount = ICODE_Write_AFI(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_AFI) { + ResponseByteCount = ICODE_Lock_AFI(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_DSFID) { + ResponseByteCount = ICODE_Write_DSFID(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_DSFID) { + ResponseByteCount = ICODE_Lock_DSFID(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_GET_SYS_INFO) { + ResponseByteCount = ICODE_Get_SysInfo(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_GET_BLOCK_SEC) { + ResponseByteCount = ICODE_Get_Multi_Block_Sec_Stat(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { + ResponseByteCount = ICODE_Reset_To_Ready(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == EM4233_CMD_LOGIN) { + ResponseByteCount = ICODE_Login(FrameBuf, FrameBytes); + + } else { + if (FrameInfo.Addressed) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; + ResponseByteCount = 2; + } /* EM4233 respond with error flag only to addressed commands */ + } + + } else if (State == STATE_QUIET) { + if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { + ResponseByteCount = ICODE_Reset_To_Ready(FrameBuf, FrameBytes); + } + } else if (State == STATE_PRIV) { + if (*FrameInfo.Command == ICODE_CMD_SET_PSW) { + ResponseByteCount = ICODE_SetPassword(FrameBuf, FrameBytes); + } else if (*FrameInfo.Command == ICODE_CMD_GET_RND) { + ResponseByteCount = ICODE_GetRandom(FrameBuf, FrameBytes); + } + } + + if (ResponseByteCount > 0) { + /* There is data to send. Append CRC */ + ISO15693AppendCRC(FrameBuf, ResponseByteCount); + ResponseByteCount += ISO15693_CRC16_SIZE; + } + + return ResponseByteCount; +} + +void ICODEGetUid(ConfigurationUidType Uid) { + MemoryReadBlock(&Uid[0], ICODE_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + +void ICODESetUid(ConfigurationUidType Uid) { + MemoryWriteBlock(Uid, ICODE_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} diff --git a/Firmware/Chameleon-Mini/Application/ICODE-SLIL.h b/Firmware/Chameleon-Mini/Application/ICODE-SLIL.h new file mode 100644 index 00000000..9079eb76 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ICODE-SLIL.h @@ -0,0 +1,83 @@ +/* + * ICODE-SLIL.h + * + * Created on: 27.12.2019 + * Author: ceres-c & fptrs + */ + +#ifndef ICODE_H_ +#define ICODE_H_ + +#include "Application.h" + +/***************************** + * E004035010963A52 - clown + * E00403500fc94a29 - gorilla + * E004035011b9b7a8 - tales + *****************************/ + + +#define ICODE_STD_UID_SIZE ISO15693_GENERIC_UID_SIZE +#define ICODE_STD_MEM_SIZE 0x40 // Bytes +#define ICODE_BYTES_PER_BLCK 0x04 +#define ICODE_BLCKS_PER_PAGE 0x04 +#define ICODE_NUMBER_OF_BLCKS ( ICODE_STD_MEM_SIZE / ICODE_BYTES_PER_BLCK ) +#define ICODE_NUMBER_OF_BLCKS_DATASHEET 0x30 // See note below +#define ICODE_NUMBER_OF_PAGES ( ICODE_STD_MEM_SIZE / (ICODE_BYTES_PER_BLCK * ICODE_BLCKS_PER_PAGE) ) +/* + * According to ICODE SLI-L datasheet Rev. 3.0 — 14 March 2007 (136430), part 8.1.2.10: + * The "Get system information" command will report having 48 blocks, even if the tag actually has only 16. + */ + +#define ICODE_IC_REFERENCE 0x03 // From ICODE SLI-L datasheet + +#define ICODE_MEM_UID_ADDRESS 0x40 // From 0x40 to 0x47 - UID +#define ICODE_MEM_AFI_ADDRESS 0x48 // AFI byte address +#define ICODE_MEM_DSFID_ADDRESS 0x49 // DSFID byte adress +#define ICODE_MEM_EAS_ADDRESS 0x4A // From 0x4A to 0x4B - EAS +#define ICODE_MEM_INF_ADDRESS 0x4C // Some status bits + +#define ICODE_MEM_LSM_ADDRESS 0x50 // From 0x50 to 0x8F - Lock status masks +#define ICODE_MEM_PRV_PSW_ADDRESS 0x90 // From 0x90 to 0x93 - 32 bit Privacy Password +#define ICODE_MEM_DSTRY_PSW_ADDRESS 0x94 // From 0x94 to 0x97 - 32 bit Destroy SLI-L Password +#define ICODE_MEM_EAS_PSW_ADDRESS 0x98 // From 0x98 to 0x9B - 32 bit EAS Password + +/* Bit masks */ +#define ICODE_MASK_AFI_STATUS ( 1 << 0 ) // Used with status bits +#define ICODE_MASK_DSFID_STATUS ( 1 << 1 ) +#define ICODE_MASK_EAS_STATUS ( 1 << 2 ) + +/* Custom command code */ +#define ICODE_CMD_SET_EAS 0xA2 // TODO +#define ICODE_CMD_RST_EAS 0xA3 // TODO +#define ICODE_CMD_LCK_EAS 0xA4 // TODO +#define ICODE_CMD_EAS_ALRM 0xA5 // TODO +#define ICODE_CMD_PRT_EAS 0xA6 // TODO +#define ICODE_CMD_WRT_EAS_ID 0xA7 // TODO + +#define ICODE_CMD_GET_RND 0xB2 +#define ICODE_CMD_SET_PSW 0xB3 +#define ICODE_CMD_WRITE_PSW 0xB4 // TODO +#define ICODE_CMD_LOCK_PSW 0xB5 // TODO +#define ICODE_CMD_DESTROY 0xB9 // TODO +#define ICODE_CMD_ENABLE_PRCY 0xBA // TODO +#define ICODE_CMD_INV_PAGE_READ 0xB0 // TODO +#define ICODE_CMD_FAST_INV_PAGE_READ 0xB1 // TODO + +/* Compile time switch */ +/* EM4233_LOGIN_YES_CARD has to be uncommented if you want your emulated card + * to accept any given password from the reader when a Login request (E4) is issued. + * It is expecially useful when analyzing an unknown system and you want to fool a reader + * into thiking you are using the original tag without actually knowing the password. + */ +#define EM4233_LOGIN_YES_CARD + +void ICODEAppInit(void); +void ICODEAppReset(void); +void ICODEAppTask(void); +void ICODEAppTick(void); +uint16_t ICODEAppProcess(uint8_t *FrameBuf, uint16_t FrameBytes); +void ICODEGetUid(ConfigurationUidType Uid); +void ICODESetUid(ConfigurationUidType Uid); + +#endif /* ICODE_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.c b/Firmware/Chameleon-Mini/Application/ISO15693-A.c index f89697e3..c4d484f9 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.c +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.c @@ -2,6 +2,9 @@ #include "../Common.h" #include +CurrentFrame FrameInfo; +uint8_t MyAFI; + //Refer to ISO/IEC 15693-3:2001 page 41 uint16_t calculateCRC(void *FrameBuf, uint16_t FrameBufSize) { uint16_t reg = ISO15693_CRC16_PRESET; @@ -96,7 +99,7 @@ bool ISO15693PrepareFrame(uint8_t *FrameBuf, uint16_t FrameBytes, CurrentFrame * FrameStruct -> ParamLen = FrameBuf + (FrameBytes - ISO15693_CRC16_SIZE) - (FrameStruct -> Parameters); - /* The UID, if present, always sits right befoore the parameters */ + /* The UID, if present, always sits right before the parameters */ if (FrameStruct -> Addressed && !ISO15693CompareUid(FrameStruct -> Parameters - ISO15693_GENERIC_UID_SIZE, MyUid)) { /* addressed request but we're not the addressee */ return false; @@ -143,11 +146,12 @@ bool ISO15693AntiColl(uint8_t *FrameBuf, uint16_t FrameBytes, CurrentFrame *Fram /* Compare spare bits in mask with bits of UID */ uint8_t BitsMask = ((1 << BitsNum) - 1); /* (1 << Bits) = 00010000 -> (1 << Bits) - 1 = 00001111 */ if ((MaskValue[B] & BitsMask) != (CurrentUID[B] & BitsMask)) { - /* |-----------------------| Here we extract bits from the mask we received from the reader - * |------------------------| Here we extract bits from the UID - * The two extracted bit vectors are compared, if different then we're not the addressee. - * Only the latest byte of MaskValue and UID is considered. - */ + /* + |-----------------------| Here we extract bits from the mask we received from the reader + |------------------------| Here we extract bits from the UID + The two extracted bit vectors are compared, if different then we're not the addressee. + Only the last bytes of, respectively, MaskValue and UID are considered. + */ return false; } diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.h b/Firmware/Chameleon-Mini/Application/ISO15693-A.h index d4fc2abc..71b9230f 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.h +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.h @@ -85,6 +85,8 @@ typedef struct { bool Addressed; bool Selected; } CurrentFrame; +extern CurrentFrame FrameInfo; /* Holds current frame information */ +extern uint8_t MyAFI; /* Holds current tag's AFI (is used in inventory) */ void ISO15693AppendCRC(uint8_t *FrameBuf, uint16_t FrameBufSize); bool ISO15693CheckCRC(void *FrameBuf, uint16_t FrameBufSize); diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index bb5826d9..92044bee 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -19,6 +19,9 @@ // TODO replace remaining magic numbers +uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE]; +uint16_t ReaderSendBitCount; + static bool Selected = false; Reader14443Command Reader14443CurrentCommand = Reader14443_Do_Nothing; diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.h b/Firmware/Chameleon-Mini/Application/Reader14443A.h index 6a41c932..e2e32b9b 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.h +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.h @@ -6,8 +6,8 @@ #define CRC_INIT 0x6363 -uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE]; -uint16_t ReaderSendBitCount; +extern uint8_t ReaderSendBuffer[]; +extern uint16_t ReaderSendBitCount; void Reader14443AAppInit(void); void Reader14443AAppReset(void); diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.c b/Firmware/Chameleon-Mini/Application/TITagitstandard.c index 4ed2c5cd..102f9a99 100644 --- a/Firmware/Chameleon-Mini/Application/TITagitstandard.c +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.c @@ -16,10 +16,8 @@ static enum { STATE_QUIET } State; -uint8_t MyAFI; /* Holds current tag's AFI (is used in inventory) */ uint16_t UserLockBits_Mask = 0; /* Holds lock state of blocks */ uint16_t FactoryLockBits_Mask = 0; /* Holds lock state of blocks */ -CurrentFrame FrameInfo; void TITagitstandardAppInit(void) { State = STATE_READY; diff --git a/Firmware/Chameleon-Mini/Codec/Codec.c b/Firmware/Chameleon-Mini/Codec/Codec.c index 30151e79..6fa3116a 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.c +++ b/Firmware/Chameleon-Mini/Codec/Codec.c @@ -24,6 +24,11 @@ static volatile struct { uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; + +void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void) = NULL; +void (* volatile isr_func_TCD0_CCC_vect)(void) = NULL; +void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void) = NULL; + // the following three functions prevent sending data directly after turning on the reader field void CodecReaderFieldStart(void) { // DO NOT CALL THIS FUNCTION INSIDE APPLICATION! if (!CodecGetReaderField() && !ReaderFieldFlags.ToBeRestarted) { diff --git a/Firmware/Chameleon-Mini/Codec/Codec.h b/Firmware/Chameleon-Mini/Codec/Codec.h index 84bf9c34..df14ceb2 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.h +++ b/Firmware/Chameleon-Mini/Codec/Codec.h @@ -116,13 +116,14 @@ typedef enum { extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; extern uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; -void (* volatile isr_func_TCD0_CCC_vect)(void); +/* Shared ISR pointers and handlers */ +extern void (* volatile isr_func_TCD0_CCC_vect)(void); void isr_Reader14443_2A_TCD0_CCC_vect(void); void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void); -void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void); +extern void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void); void isr_ISO14443_2A_TCD0_CCC_vect(void); void isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void); -void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void); +extern void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void); void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void); void isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void); diff --git a/Firmware/Chameleon-Mini/Codec/ISO15693.c b/Firmware/Chameleon-Mini/Codec/ISO15693.c index 39ea805b..4a936083 100644 --- a/Firmware/Chameleon-Mini/Codec/ISO15693.c +++ b/Firmware/Chameleon-Mini/Codec/ISO15693.c @@ -88,7 +88,6 @@ static volatile uint16_t ReadCommandFromReader = 0; * CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; * and unregistered writing the INT0MASK to 0 */ -// ISR(CODEC_DEMOD_IN_INT0_VECT) ISR_SHARED isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void) { /* Start sample timer CODEC_TIMER_SAMPLING (TCD0). * Set Counter Channel C (CCC) with relevant bitmask (TC0_CCCIF_bm), @@ -258,7 +257,7 @@ ISR_SHARED isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) { * It disables its own interrupt when all data has been sent */ //ISR(CODEC_TIMER_LOADMOD_CCB_VECT) -void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { +ISR_SHARED isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { static void *JumpTable[] = { [LOADMOD_START_SINGLE] = && LOADMOD_START_SINGLE_LABEL, [LOADMOD_SOF_SINGLE] = && LOADMOD_SOF_SINGLE_LABEL, diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c index ac132fbc..78c82107 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -56,6 +56,8 @@ static volatile uint16_t ReaderBitCount; static volatile uint16_t CardBitCount; static volatile uint16_t rawBitCount; +enum RCTraffic TrafficSource; + INLINE void CardSniffInit(void); INLINE void CardSniffDeinit(void); @@ -351,16 +353,13 @@ ISR(ACA_AC0_vect) { // this interrupt either finds the SOC or gets triggered bef StateRegister = PICC_FRAME; } -ISR(CODEC_TIMER_LOADMOD_CCB_VECT) { // pause found - isr_func_CODEC_TIMER_LOADMOD_CCB_VECT(); -} - +// Called once a pause is found // Decode the Card -> Reader signal // according to the pause and modulated period // if the half bit duration is modulated, then add 1 to buffer // if the half bit duration is not modulated, then add 0 to buffer //ISR(CODEC_TIMER_LOADMOD_CCB_VECT) // pause found -void isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void) { +ISR_SHARED isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void) { uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; CODEC_TIMER_TIMESTAMPS.CNT = 0; diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h index 0e22d464..b8616b0c 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h @@ -9,7 +9,7 @@ #include "Codec.h" #include "Terminal/CommandLine.h" -enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource; +extern enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource; /* Codec Interface */ void Sniff14443ACodecInit(void); void Sniff14443ACodecDeInit(void); diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index aef4fb82..55983af5 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -56,6 +56,9 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { #ifdef CONFIG_EM4233_SUPPORT { .Id = CONFIG_EM4233, .Text = "EM4233" }, #endif +#ifdef CONFIG_ICODE_SLI_SUPPORT + { .Id = CONFIG_ICODE_SLI, .Text = "ICODE_SLI" }, +#endif }; /* Include all Codecs and Applications */ @@ -373,6 +376,24 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .TagFamily = TAG_FAMILY_ISO15693 }, #endif +#ifdef CONFIG_ICODE_SLI_SUPPORT + [CONFIG_ICODE_SLI] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = ICODEAppInit, + .ApplicationResetFunc = ICODEAppReset, + .ApplicationTaskFunc = ICODEAppTask, + .ApplicationTickFunc = ICODEAppTick, + .ApplicationProcessFunc = ICODEAppProcess, + .ApplicationGetUidFunc = ICODEGetUid, + .ApplicationSetUidFunc = ICODESetUid, + .UidSize = ICODE_STD_UID_SIZE, + .MemorySize = ICODE_STD_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO15693 + }, +#endif }; ConfigurationType ActiveConfiguration; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index f348d44c..476faaff 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -61,6 +61,9 @@ typedef enum { #endif #ifdef CONFIG_EM4233_SUPPORT CONFIG_EM4233, +#endif +#ifdef CONFIG_ICODE_SLI_SUPPORT + CONFIG_ICODE_SLI, #endif /* This HAS to be the last element */ CONFIG_COUNT diff --git a/Firmware/Chameleon-Mini/ISRSharing.S b/Firmware/Chameleon-Mini/ISRSharing.S index 9a18a823..cf6a6cd7 100644 --- a/Firmware/Chameleon-Mini/ISRSharing.S +++ b/Firmware/Chameleon-Mini/ISRSharing.S @@ -9,7 +9,7 @@ #include "Codec/Codec.h" #include -; Use this macro to call isr functions +; Macro to call ISR functions .macro call_isr isr_address push r30 push r31 @@ -21,12 +21,28 @@ pop r30 reti .endm -; Find first pause and start sampling +; Shared ISR must be defined below as globals +; Example: +; +; .global +; INTERRUPT-TO-SHARE: +; call_isr POINTER-TO-VARIABLE-INTERRUPT-HANDLER +; +; Where: +; INTERRUPT-TO-SHARE +; The target interrupt which needs to be shared +; POINTER-TO-VARIABLE-INTERRUPT-HANDLER +; A pointer to the interrupt handler which can be modified at runtime. +; Must be a volatile pointer to function declared in Codec.h + .global CODEC_DEMOD_IN_INT0_VECT CODEC_DEMOD_IN_INT0_VECT: call_isr isr_func_CODEC_DEMOD_IN_INT0_VECT -; Frame Delay Time PCD to PICC ends .global CODEC_TIMER_SAMPLING_CCC_VECT CODEC_TIMER_SAMPLING_CCC_VECT: call_isr isr_func_TCD0_CCC_vect + +.global CODEC_TIMER_LOADMOD_CCB_VECT +CODEC_TIMER_LOADMOD_CCB_VECT: + call_isr isr_func_CODEC_TIMER_LOADMOD_CCB_VECT \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 874326e7..3d1246a3 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -18,6 +18,7 @@ SETTINGS += -DCONFIG_SL2S2002_SUPPORT SETTINGS += -DCONFIG_TITAGITSTANDARD_SUPPORT SETTINGS += -DCONFIG_ISO15693_SNIFF_SUPPORT SETTINGS += -DCONFIG_EM4233_SUPPORT +SETTINGS += -DCONFIG_ICODE_SLI_SUPPORT #Support magic mode on mifare classic configuration SETTINGS += -DSUPPORT_MF_CLASSIC_MAGIC_MODE @@ -33,7 +34,8 @@ SETTINGS += -DSUPPORT_FIRMWARE_UPGRADE #SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_1K #SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_CLASSIC_4K #SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_MF_ULTRALIGHT -SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_NONE +#SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_NONE +SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_ICODE_SLI #SETTINGS += -DDEFAULT_CONFIGURATION=CONFIG_ISO14443A_READER #Default button actions @@ -57,8 +59,8 @@ SETTINGS += -DDEFAULT_GREEN_LED_ACTION=LED_POWERED SETTINGS += -DLED_SETTING_GLOBAL #Default logging mode -SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_OFF -#SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_MEMORY +#SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_OFF +SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_MEMORY #SETTINGS += -DDEFAULT_LOG_MODE=LOG_MODE_TERMINAL #Define if log settings should be global @@ -102,7 +104,7 @@ SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Termina SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c Application/CryptoTDEA.S SRC += Codec/ISO15693.c -SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/ISO15693-A.c Application/EM4233.c +SRC += Application/Vicinity.c Application/ICODE-SLIL.c Application/Sl2s2002.c Application/TITagitstandard.c Application/ISO15693-A.c Application/EM4233.c SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -DFLASH_DATA_ADDR=$(FLASH_DATA_ADDR) -DFLASH_DATA_SIZE=$(FLASH_DATA_SIZE) -DSPM_HELPER_ADDR=$(SPM_HELPER_ADDR) -DBUILD_DATE=$(BUILD_DATE) -DCOMMIT_ID=\"$(COMMIT_ID)\" $(SETTINGS) diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 46658693..4db10f5e 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -15,6 +15,7 @@ #include "../AntennaLevel.h" #include "../Battery.h" #include "../Codec/Codec.h" +#include "../Application/Reader14443A.h" extern Reader14443Command Reader14443CurrentCommand; extern Sniff14443Command Sniff14443CurrentCommand; diff --git a/Fun_with_Icode.pdf b/Fun_with_Icode.pdf new file mode 100644 index 00000000..9a18ece3 Binary files /dev/null and b/Fun_with_Icode.pdf differ