diff --git a/Dumps/EM4233_example.dmp b/Dumps/EM4233_example.dmp new file mode 100644 index 0000000..4387c6e Binary files /dev/null and b/Dumps/EM4233_example.dmp differ diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index 1002d31..af0dd2a 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -16,7 +16,11 @@ #include "MifareUltralight.h" #include "MifareClassic.h" #include "Reader14443A.h" +#include "Vicinity.h" +#include "Sl2s2002.h" +#include "TITagitstandard.h" #include "Sniff14443A.h" +#include "EM4233.h" /* Function wrappers */ INLINE void ApplicationInit(void) { @@ -24,11 +28,11 @@ INLINE void ApplicationInit(void) { } INLINE void ApplicationTask(void) { - ActiveConfiguration.ApplicationTaskFunc(); + ActiveConfiguration.ApplicationTaskFunc(); } INLINE void ApplicationTick(void) { - ActiveConfiguration.ApplicationTickFunc(); + ActiveConfiguration.ApplicationTickFunc(); } INLINE uint16_t ApplicationProcess(uint8_t* ByteBuffer, uint16_t ByteCount) { diff --git a/Firmware/Chameleon-Mini/Application/EM4233.c b/Firmware/Chameleon-Mini/Application/EM4233.c new file mode 100644 index 0000000..f3cd7a7 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/EM4233.c @@ -0,0 +1,696 @@ +/* + * EM4233.c + * + * Created on: 12-05-2018 + * Author: ceres-c & MrMoDDoM + * Notes: + * - In EM4233.h you can find the define EM4233_LOGIN_YES_CARD that has to be uncommnted + * to allow any login request without checking the password. + * + * TODO: + * - Check with real tag every command's actual response in addressed/selected State + * (Only EM4233_Read_Single and EM4233_Read_Multiple have been checked up to now) + */ + +#include "../Random.h" +#include "ISO15693-A.h" +#include "EM4233.h" + +static enum { + STATE_READY, + STATE_SELECTED, + STATE_QUIET +} State; + +bool loggedIn; +uint8_t MyAFI; /* This variable holds current tag's AFI (is used in inventory) */ + +CurrentFrame FrameInfo; + +void EM4233AppInit(void) +{ + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + loggedIn = false; + MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1); + +} + +void EM4233AppReset(void) +{ + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + loggedIn = false; +} + +void EM4233AppTask(void) +{ + +} + +void EM4233AppTick(void) +{ + +} + +uint16_t EM4233_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, (EM4233_MEM_LSM_ADDRESS + BlockAddress), 1); + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (BlockAddress > EM4233_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, (EM4233_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 EM4233_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 > EM4233_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, (EM4233_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 * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount += 1; + } + + return ResponseByteCount; +} + +uint16_t EM4233_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 >= EM4233_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, (EM4233_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 * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); + ResponseByteCount += 4; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + + return ResponseByteCount; +} + +uint16_t EM4233_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 >= EM4233_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) >= EM4233_NUMBER_OF_BLCKS) { /* last block is out of bound */ + BlocksNumber = EM4233_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 * EM4233_BYTES_PER_BLCK, BlocksNumber * EM4233_BYTES_PER_BLCK); + ResponseByteCount += BlocksNumber * EM4233_BYTES_PER_BLCK; + + } else { /* we have to slice blocks' data with lock statuses */ + uint8_t DataBuffer[ BlocksNumber * EM4233_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 * EM4233_BYTES_PER_BLCK, BlocksNumber * EM4233_BYTES_PER_BLCK); + MemoryReadBlock(&LockStatusBuffer, EM4233_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 * EM4233_BYTES_PER_BLCK + 0]; + FrameBuf[FramePtr++] = DataBuffer[block * EM4233_BYTES_PER_BLCK + 1]; + FrameBuf[FramePtr++] = DataBuffer[block * EM4233_BYTES_PER_BLCK + 2]; + FrameBuf[FramePtr++] = DataBuffer[block * EM4233_BYTES_PER_BLCK + 3]; + ResponseByteCount += EM4233_BYTES_PER_BLCK; + } + } + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t EM4233_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, EM4233_MEM_INF_ADDRESS, 1); + + if (LockStatus & EM4233_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, EM4233_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 EM4233_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, EM4233_MEM_INF_ADDRESS, 1); + + if (LockStatus & EM4233_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 |= EM4233_MASK_AFI_STATUS; + + MemoryWriteBlock(&LockStatus, EM4233_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 EM4233_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, EM4233_MEM_INF_ADDRESS, 1); + + if (LockStatus & EM4233_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, EM4233_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 EM4233_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, EM4233_MEM_INF_ADDRESS, 1); + + if (LockStatus & EM4233_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 |= EM4233_MASK_DSFID_STATUS; + + MemoryWriteBlock(&LockStatus, EM4233_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 EM4233_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]; + EM4233GetUid(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], EM4233_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], EM4233_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] = EM4233_NUMBER_OF_BLCKS - 0x01; + FramePtr += 1; /* Move forward the buffer data pointer */ + ResponseByteCount += 1; /* Increment the response count */ + + FrameBuf[FramePtr] = EM4233_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] = EM4233_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 EM4233_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 > EM4233_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) >= EM4233_NUMBER_OF_BLCKS) { /* last block is out of bound */ + BlocksNumber = EM4233_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], EM4233_MEM_LSM_ADDRESS + BlockAddress, BlocksNumber); + ResponseByteCount += BlocksNumber; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t EM4233_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 EM4233_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 EM4233_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 */ + loggedIn = 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; + + // 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 + + loggedIn = true; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + ResponseByteCount += 1; + return ResponseByteCount; +} + +uint16_t EM4233_Auth1(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + // uint8_t KeyNo = *FrameInfo.Parameters; /* Right now this parameter is unused, but it will be useful */ + + if (FrameInfo.ParamLen != 1) /* Malformed: not enough or too much data */ + return ISO15693_APP_NO_RESPONSE; + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + #ifdef EM4233_LOGIN_YES_CARD + /* Will be useful for testing purposes, probably removed in final version */ + FrameBuf[ISO15693_ADDR_FLAGS + 1] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 2] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 3] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 4] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 5] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 6] = 0x00; + FrameBuf[ISO15693_ADDR_FLAGS + 7] = 0x00; + #else + /* Respond like a real tag */ + RandomGetBuffer(FrameBuf + 0x01, 7); /* Random number A1 in EM Marin definitions */ + #endif + ResponseByteCount += 8; + return ResponseByteCount; +} + +uint16_t EM4233_Auth2(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + // uint8_t A2 = FrameInfo.Parameters; + // uint8_t f = FrameInfo.Parameters + 0x08; + // uint8_t g[3] = { 0 }; /* Names according to EM Marin definitions */ + + if (FrameInfo.ParamLen != 11) /* Malformed: not enough or too much data */ + return ISO15693_APP_NO_RESPONSE; + // else if (!fFunc()) /* Actual f implementation to check if the f bytes we received are correct */ + // return ISO15693_APP_NO_RESPONSE; + + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + RandomGetBuffer(FrameBuf + 0x01, 3); /* This should be replaced with actual gFunc() implementation */ + ResponseByteCount += 4; + return ResponseByteCount; +} + +uint16_t EM4233AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Uid[ActiveConfiguration.UidSize]; + EM4233GetUid(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 = EM4233_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], EM4233_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 = EM4233_Read_Single(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_SINGLE) { + ResponseByteCount = EM4233_Write_Single(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_BLOCK) { + ResponseByteCount = EM4233_Lock_Block(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_READ_MULTIPLE) { + ResponseByteCount = EM4233_Read_Multiple(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_AFI) { + ResponseByteCount = EM4233_Write_AFI(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_AFI) { + ResponseByteCount = EM4233_Lock_AFI(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_DSFID) { + ResponseByteCount = EM4233_Write_DSFID(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_DSFID) { + ResponseByteCount = EM4233_Lock_DSFID(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_GET_SYS_INFO) { + ResponseByteCount = EM4233_Get_SysInfo(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_GET_BLOCK_SEC) { + ResponseByteCount = EM4233_Get_Multi_Block_Sec_Stat(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { + ResponseByteCount = EM4233_Reset_To_Ready (FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == EM4233_CMD_LOGIN) { + ResponseByteCount = EM4233_Login(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == EM4233_CMD_AUTH1) { + ResponseByteCount = EM4233_Auth1(FrameBuf, FrameBytes); + + } else if (*FrameInfo.Command == EM4233_CMD_AUTH2) { + ResponseByteCount = EM4233_Auth2(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 = EM4233_Reset_To_Ready (FrameBuf, FrameBytes); + } + } + + if (ResponseByteCount > 0) { + /* There is data to send. Append CRC */ + ISO15693AppendCRC(FrameBuf, ResponseByteCount); + ResponseByteCount += ISO15693_CRC16_SIZE; + } + + return ResponseByteCount; +} + +void EM4233GetUid(ConfigurationUidType Uid) +{ + MemoryReadBlock(&Uid[0], EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + +void EM4233SetUid(ConfigurationUidType Uid) +{ + MemoryWriteBlock(Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Application/EM4233.h b/Firmware/Chameleon-Mini/Application/EM4233.h new file mode 100644 index 0000000..e291b6d --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/EM4233.h @@ -0,0 +1,79 @@ +/* + * EM4233.h + * + * Created on: 04.12.2018 + * Author: ceres-c & MrMoDDoM + */ + +#ifndef EM4233_H_ +#define EM4233_H_ + +#include "Application.h" + +#define EM4233_STD_UID_SIZE ISO15693_GENERIC_UID_SIZE +#define EM4233_STD_MEM_SIZE 0xD0 // Bytes +#define EM4233_BYTES_PER_BLCK 0x04 +#define EM4233_BLCKS_PER_PAGE 0x04 +#define EM4233_NUMBER_OF_BLCKS ( EM4233_STD_MEM_SIZE / EM4233_BYTES_PER_BLCK ) +#define EM4233_NUMBER_OF_PAGES ( EM4233_STD_MEM_SIZE / (EM4233_BYTES_PER_BLCK * EM4233_BLCKS_PER_PAGE) ) + +#define EM4233_IC_REFERENCE 0x02 // From EM4233SLIC datasheet and checked against real tags + +#define EM4233_MEM_UID_ADDRESS 0xD0 // From 0x0100 to 0x0107 - UID +#define EM4233_MEM_AFI_ADDRESS 0xD8 // AFI byte address +#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_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_WRITE_PROT ( 1 << 3 ) +#define EM4233_MASK_AFI_STATUS ( 1 << 0 ) +#define EM4233_MASK_DSFID_STATUS ( 1 << 1 ) + +/* Custom command code */ +#define EM4233_CMD_SET_EAS 0xA2 +#define EM4233_CMD_RST_EAS 0xA3 +#define EM4233_CMD_LCK_EAS 0xA4 +#define EM4233_CMD_ACT_EAS 0xA5 +#define EM4233_CMD_PRT_EAS 0xA6 +#define EM4233_CMD_WRT_EAS_ID 0xA7 +#define EM4233_CMD_WRT_EAS_CFG 0xA8 +#define EM4233_CMD_WRT_PSW 0xB4 +#define EM4233_CMD_WRT_MEM_PAG 0xB6 +#define EM4233_CMD_GET_BLKS_PRT_STS 0xB8 +#define EM4233_CMD_DESTROY 0xB9 +#define EM4233_CMD_ENABLE_PRCY 0xBA +#define EM4233_CMD_DISBLE_PRCY 0xBB +#define EM4233_CMD_FST_READ_BLKS 0xC3 + +/* 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_WRITE 0xE3 // Same +#define EM4233_CMD_LOGIN 0xE4 + +/* 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 EM4233AppInit(void); +void EM4233AppReset(void); +void EM4233AppTask(void); +void EM4233AppTick(void); +uint16_t EM4233AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes); +void EM4233GetUid(ConfigurationUidType Uid); +void EM4233SetUid(ConfigurationUidType Uid); +void EM4233FlipUid(ConfigurationUidType Uid); + +#endif /* EM4233_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.c b/Firmware/Chameleon-Mini/Application/ISO15693-A.c new file mode 100644 index 0000000..b435393 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.c @@ -0,0 +1,160 @@ +#include "ISO15693-A.h" +#include "../Common.h" +#include + +//Refer to ISO/IEC 15693-3:2001 page 41 +uint16_t calculateCRC(void* FrameBuf, uint16_t FrameBufSize) +{ + uint16_t reg = ISO15693_CRC16_PRESET; + uint8_t i, j; + + uint8_t *DataPtr = (uint8_t *)FrameBuf; + + for(i = 0; i < FrameBufSize; i++) { + reg = reg ^ *DataPtr++; + for (j = 0; j < 8; j++) { + if (reg & 0x0001) { + reg = (reg >> 1) ^ ISO15693_CRC16_POLYNORMAL; + } else { + reg = (reg >> 1); + } + } + } + + return ~reg; +} + +void ISO15693AppendCRC(uint8_t* FrameBuf, uint16_t FrameBufSize) +{ + uint16_t crc; + + crc = calculateCRC(FrameBuf, FrameBufSize); + + uint8_t crcLb = crc & 0xFF; + uint8_t crcHb = crc >> 8; + + + FrameBuf[FrameBufSize] = crcLb; + FrameBuf[FrameBufSize + 1] = crcHb; +} + +bool ISO15693CheckCRC(void* FrameBuf, uint16_t FrameBufSize) +{ + uint16_t crc; + uint8_t *DataPtr = (uint8_t *)FrameBuf; + + crc = calculateCRC(DataPtr, FrameBufSize); + + uint8_t crcLb = crc & 0xFF; + uint8_t crcHb = crc >> 8; + + return (DataPtr[FrameBufSize] == crcLb && DataPtr[FrameBufSize + 1] == crcHb); +} + +/* + * ISO15693PrepareFrame + * + * This function sets pointers in 'frame' struct to relevant byte(s) of 'FrameBuf'. + * Also sets frame.Addressed as true if the command is addressed, same goes for frame.Selected + * + * Returns: + * - true: Frame is valid and a response is needed + * - false: Request is not addressed to us + * Frame is not valid because it's too short or CRC is wrong + * + * Authors: ceres-c & MrMoDDoM + */ +bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t IsSelected, uint8_t* MyUid, uint8_t MyAFI) +{ + /* following declarations are not dependent on addressed/unaddressed state */ + FrameStruct -> Flags = &FrameBuf[ISO15693_ADDR_FLAGS]; + FrameStruct -> Command = &FrameBuf[ISO15693_REQ_ADDR_CMD]; + + if(!(FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_INVENTORY)) { /* if inventory flag is not set */ + FrameStruct -> Addressed = (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_ADDRESS); /* check for addressed flag */ + FrameStruct -> Selected = (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_SELECT); /* check for selected flag */ + } else { /* otherwise always false */ + FrameStruct -> Addressed = false; + FrameStruct -> Selected = false; + } + + if (FrameStruct -> Addressed) + /* UID sits between CMD and PARAM */ + FrameStruct -> Parameters = &FrameBuf[ISO15693_REQ_ADDR_PARAM + ISO15693_GENERIC_UID_SIZE]; + else + FrameStruct -> Parameters = &FrameBuf[ISO15693_REQ_ADDR_PARAM]; + + if ( (*FrameStruct -> Command) >= 0xA0) { /* if command is Custom or Proprietary */ + /* then between CMD and UID is placed another byte which is IC Mfg Code, but we don't need it */ + if (FrameBuf[ISO15693_REQ_ADDR_PARAM] != MyUid[1]) + /* if IC Mfg Code is different from our Mfg code (2nd byte of UID), then don't respond */ + return false; + FrameStruct -> Parameters += 0x01; + } + else if ( ((*FrameStruct -> Command) == ISO15693_CMD_INVENTORY) && (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_AFI)) { /* or if it is Inventory with AFI flag set */ + /* then between CMD and UID is placed another byte which is requested AFI, but we don't need it */ + if (FrameBuf[ISO15693_REQ_ADDR_PARAM] != MyAFI) + /* if requested AFI is different from our current one, then don't respond */ + return false; + FrameStruct -> Parameters += 0x01; + } + + FrameStruct -> ParamLen = FrameBuf + (FrameBytes - ISO15693_CRC16_SIZE) - (FrameStruct -> Parameters); + + /* The UID, if present, always sits right befoore the parameters */ + if (FrameStruct -> Addressed && !ISO15693CompareUid(FrameStruct -> Parameters - ISO15693_GENERIC_UID_SIZE, MyUid)) { + /* addressed request but we're not the addressee */ + return false; + } else if (FrameStruct -> Selected && !IsSelected) { + /* selected request but we're not in selected state */ + return false; + } else { + return true; + } +} + +/* + * ISO15693AntiColl + * + * This function performs ISO15693 Anticollision + * + * Returns: + * - true: Inventory is addressed to us and a response is needed + * - false: Request is not addressed to us (different bitmask) + * and no response should be issued. + * + * Authors: ceres-c + * + * TODO: + * - Implement 16 slots mode (still, it seems to work as it is, even for 16 slots mode ._.) + */ +bool ISO15693AntiColl(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t* MyUid) { + uint8_t CurrentUID[ ISO15693_GENERIC_UID_SIZE ]; /* Holds the UID flipped */ + ISO15693CopyUid(CurrentUID, MyUid); + + uint8_t MaskLenght = *FrameStruct -> Parameters; /* First byte of parameters is mask lenght... */ + uint8_t* MaskValue = FrameStruct -> Parameters + 1; /* ... then the mask itself begins */ + uint8_t BytesNum = MaskLenght / 8; /* Gets the number of full bytes in mask */ + uint8_t BitsNum = MaskLenght % 8; /* Gets the number of spare bits */ + + uint8_t B; /* B stands for Bytes and will be our reference point (I know, terrible name, I'm sorry) */ + /* Compare the full bytes in mask with UID */ + for (B = 0; B < BytesNum; B++ ) { + if (CurrentUID[B] != MaskValue[B]) + return false; /* UID different */ + } + /* Once we got here, B points for sure to the last byte of the mask, the one composed of spare bits */ + + /* 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. + */ + return false; + } + + return true; +} diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.h b/Firmware/Chameleon-Mini/Application/ISO15693-A.h new file mode 100644 index 0000000..42b1655 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.h @@ -0,0 +1,147 @@ +/* + * ISO15693-3.h + * + * Created on: 24.08.2013 + * Author: skuser + */ + +#ifndef ISO15693_3_H_ +#define ISO15693_3_H_ + +#include "../Common.h" + +/* request and response fields addresses */ +#define ISO15693_ADDR_FLAGS 0x00 +#define ISO15693_REQ_ADDR_CMD 0x01 +#define ISO15693_REQ_ADDR_PARAM 0x02 + +#define ISO15693_RES_ADDR_PARAM 0x01 + +/* command codes */ +#define ISO15693_CMD_INVENTORY 0x01 +#define ISO15693_CMD_STAY_QUIET 0x02 +#define ISO15693_CMD_READ_SINGLE 0x20 +#define ISO15693_CMD_WRITE_SINGLE 0x21 +#define ISO15693_CMD_LOCK_BLOCK 0x22 +#define ISO15693_CMD_READ_MULTIPLE 0x23 +#define ISO15693_CMD_WRITE_MULTIPLE 0x24 +#define ISO15693_CMD_SELECT 0x25 +#define ISO15693_CMD_RESET_TO_READY 0x26 +#define ISO15693_CMD_WRITE_AFI 0x27 +#define ISO15693_CMD_LOCK_AFI 0x28 +#define ISO15693_CMD_WRITE_DSFID 0x29 +#define ISO15693_CMD_LOCK_DSFID 0x2A +#define ISO15693_CMD_GET_SYS_INFO 0x2B +#define ISO15693_CMD_GET_BLOCK_SEC 0x2C + +#define ISO15693_REQ_FLAG_SUBCARRIER 0x01 +#define ISO15693_REQ_FLAG_DATARATE 0x02 +#define ISO15693_REQ_FLAG_INVENTORY 0x04 +#define ISO15693_REQ_FLAG_PROT_EXT 0x08 +#define ISO15693_REQ_FLAG_OPTION 0x40 +#define ISO15693_REQ_FLAG_RFU 0x80 +/* When INVENTORY flag is not set: */ +#define ISO15693_REQ_FLAG_SELECT 0x10 +#define ISO15693_REQ_FLAG_ADDRESS 0x20 +/* When INVENTORY flag is set: */ +#define ISO15693_REQ_FLAG_AFI 0x10 +#define ISO15693_REQ_FLAG_NB_SLOTS 0x20 + +#define ISO15693_RES_FLAG_NO_ERROR 0x00 +#define ISO15693_RES_FLAG_ERROR 0x01 +#define ISO15693_RES_FLAG_PROT_EXT 0x08 + +#define ISO15693_RES_ERR_NOT_SUPP 0x01 +#define ISO15693_RES_ERR_NOT_REC 0x02 +#define ISO15693_RES_ERR_OPT_NOT_SUPP 0x03 +#define ISO15693_RES_ERR_GENERIC 0x0F +#define ISO15693_RES_ERR_BLK_NOT_AVL 0x10 +#define ISO15693_RES_ERR_BLK_ALRD_LKD 0x11 +#define ISO15693_RES_ERR_BLK_CHG_LKD 0x12 +#define ISO15693_RES_ERR_BLK_NOT_PRGR 0x13 +#define ISO15693_RES_ERR_BLK_NOT_LKD 0x14 + +#define ISO15693_RES_INVENTORY_DSFID 0x00 + +#define ISO15693_MIN_FRAME_SIZE 0x04 + +#define ISO15693_GENERIC_UID_SIZE 0x08 +#define ISO15693_GENERIC_MEM_SIZE 8192 + +#define ISO15693_CRC16_SIZE 0x2 /* Bytes */ +#define ISO15693_CRC16_POLYNORMAL 0x8408 +#define ISO15693_CRC16_PRESET 0xFFFF + +/* The lock status byte has bits assigned as follow */ +#define ISO15693_MASK_UNLOCKED ( 0 << 0 ) +#define ISO15693_MASK_USER_LOCK ( 1 << 0 ) +#define ISO15693_MASK_FACTORY_LOCK ( 1 << 1 ) + +typedef struct { + uint8_t* Flags; + uint8_t* Command; + uint8_t* Parameters; + uint8_t ParamLen; + bool Addressed; + bool Selected; +} CurrentFrame; + +void ISO15693AppendCRC(uint8_t* FrameBuf, uint16_t FrameBufSize); +bool ISO15693CheckCRC(void* FrameBuf, uint16_t FrameBufSize); +bool ISO15693PrepareFrame(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t IsSelected, uint8_t* MyUid, uint8_t MyAFI); +bool ISO15693AntiColl(uint8_t* FrameBuf, uint16_t FrameBytes, CurrentFrame* FrameStruct, uint8_t* MyUid); + +INLINE +bool ISO15693CompareUid(uint8_t* Uid1, uint8_t* Uid2) +{ + if ( (Uid1[0] == Uid2[7]) + && (Uid1[1] == Uid2[6]) + && (Uid1[2] == Uid2[5]) + && (Uid1[3] == Uid2[4]) + && (Uid1[4] == Uid2[3]) + && (Uid1[5] == Uid2[2]) + && (Uid1[6] == Uid2[1]) + && (Uid1[7] == Uid2[0]) ) { + return true; + } else { + return false; + } +} + +INLINE +void ISO15693CopyUid(uint8_t* DstUid, uint8_t* SrcUid) +{ + DstUid[0] = SrcUid[7]; + DstUid[1] = SrcUid[6]; + DstUid[2] = SrcUid[5]; + DstUid[3] = SrcUid[4]; + DstUid[4] = SrcUid[3]; + DstUid[5] = SrcUid[2]; + DstUid[6] = SrcUid[1]; + DstUid[7] = SrcUid[0]; +} + +INLINE +bool ISO15693Addressed(uint8_t* Buffer) { + return (Buffer[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_ADDRESS); /* if the flag is set, the command is addressed */ +} + + +INLINE +bool ISO15693AddressedLegacy(uint8_t* Buffer, uint8_t* MyUid) { + if (Buffer[0] & ISO15693_REQ_FLAG_ADDRESS) { + /* Addressed mode */ + if ( ISO15693CompareUid(&Buffer[2], MyUid) ) { + /* Our UID addressed */ + return true; + } else { + /* Our UID not addressed */ + return false; + } + } else { + /* Non-Addressed mode */ + return true; + } +} + +#endif /* ISO15693_3_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Sl2s2002.c b/Firmware/Chameleon-Mini/Application/Sl2s2002.c new file mode 100644 index 0000000..dbef868 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Sl2s2002.c @@ -0,0 +1,180 @@ +/* + * ISO15693.c + * + * Created on: 01-03-2017 + * Author: Phillip Nash + * + * TODO: + * - ISO15693AddressedLegacy should be replaced with ISO15693Addressed and appropriate check + * should be performed (see TITagitstandard.c) - ceres-c + */ + + +#include "Sl2s2002.h" +#include "../Codec/ISO15693.h" +#include "../Memory.h" +#include "Crypto1.h" +#include "../Random.h" +#include "ISO15693-A.h" + +#define BYTES_PER_PAGE 4 +#define MEM_UID_ADDRESS 0x00 + +static enum { + STATE_READY, + STATE_SELECTED, + STATE_QUIET +} State; + +void Sl2s2002AppInit(void) +{ + State = STATE_READY; +} + +void Sl2s2002AppReset(void) +{ + State = STATE_READY; +} + + +void Sl2s2002AppTask(void) +{ + +} + +void Sl2s2002AppTick(void) +{ + + +} + +uint16_t Sl2s2002AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + if (FrameBytes >= ISO15693_MIN_FRAME_SIZE) { + if(ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) { + // At this point, we have a valid ISO15693 frame + uint8_t Command = FrameBuf[1]; + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Uid[8]; + MemoryReadBlock(Uid, MEM_UID_ADDRESS, ActiveConfiguration.UidSize); + + switch(State) { + case STATE_READY: + if (Command == ISO15693_CMD_INVENTORY) { + FrameBuf[0] = 0x00; /* Flags */ + FrameBuf[1] = 0x00; /* DSFID */ + ISO15693CopyUid(&FrameBuf[2], Uid); + ResponseByteCount = 10; + } else if (Command == ISO15693_CMD_STAY_QUIET) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + State = STATE_QUIET; + } + } else if (Command == ISO15693_CMD_GET_SYS_INFO) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + FrameBuf[0] = 0; /* Flags */ + FrameBuf[1] = 0x0F; /* InfoFlags */ + ISO15693CopyUid(&FrameBuf[2], Uid); + FrameBuf[10] = 0x00; + FrameBuf[11] = 0xC2; + FrameBuf[12] = 0x03; + FrameBuf[13] = 0x03; + FrameBuf[14] = 0x01; + ResponseByteCount = 15; + } + } else if (Command == ISO15693_CMD_READ_SINGLE) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + uint8_t PageAddress = FrameBuf[10]; + if (FrameBuf[0] & ISO15693_REQ_FLAG_OPTION) + { + FrameBuf[0] = 0x00; /* Flags */ + FrameBuf[1] = 0x00; /* security dummy to 0 */ + MemoryReadBlock(FrameBuf + 2, PageAddress * BYTES_PER_PAGE, BYTES_PER_PAGE); + ResponseByteCount = 6; + } else { + FrameBuf[0] = 0x00; /* Flags */ + MemoryReadBlock(FrameBuf + 1, PageAddress * BYTES_PER_PAGE, BYTES_PER_PAGE); + ResponseByteCount = 5; + } + } + } else if (Command == ISO15693_CMD_READ_MULTIPLE) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + uint16_t PageAddress = FrameBuf[10]; + uint16_t PageAddressCount = FrameBuf[11] + 1; + + uint8_t * FrameBufPtr = FrameBuf + 1; + if (FrameBuf[0] & ISO15693_REQ_FLAG_OPTION) + { + uint8_t count; + for (count = 0; count < PageAddressCount; count++) + { + *FrameBufPtr++ = 0; // block security status = unlocked + MemoryReadBlock(FrameBufPtr, PageAddress * BYTES_PER_PAGE, BYTES_PER_PAGE); + FrameBufPtr += BYTES_PER_PAGE; + PageAddress += 1; + } + ResponseByteCount = 1 + (BYTES_PER_PAGE + 1) * PageAddressCount; + } else { + MemoryReadBlock(FrameBufPtr, PageAddress * BYTES_PER_PAGE, BYTES_PER_PAGE * PageAddressCount); + ResponseByteCount = 1 + BYTES_PER_PAGE * PageAddressCount; + } + FrameBuf[0] = 0; /* Flags */ + } + } else if (Command == ISO15693_CMD_GET_BLOCK_SEC) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + uint8_t PageAddressStart = FrameBuf[10]; + uint8_t PageAddressCount = FrameBuf[11] + 1; + FrameBuf[0] = 0; /* Flags */ + for (uint8_t i = 0; i < PageAddressCount; i++) { + FrameBuf[i] = 0x00; + } + ResponseByteCount = 1 + PageAddressCount; + } + } + break; + case STATE_SELECTED: + + break; + + case STATE_QUIET: + if (Command == ISO15693_CMD_RESET_TO_READY) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + FrameBuf[0] = 0; + ResponseByteCount = 1; + State = STATE_READY; + } + } + break; + + default: + break; + } + + if (ResponseByteCount > 0) { + /* There is data to be sent. Append CRC */ + ISO15693AppendCRC(FrameBuf, ResponseByteCount); + ResponseByteCount += ISO15693_CRC16_SIZE; + } + + return ResponseByteCount; + + } else { // Invalid CRC + return ISO15693_APP_NO_RESPONSE; + } + } else { // Min frame size not met + return ISO15693_APP_NO_RESPONSE; + } + +} + +void Sl2s2002GetUid(ConfigurationUidType Uid) +{ + MemoryReadBlock(&Uid[0], MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + +void Sl2s2002SetUid(ConfigurationUidType Uid) +{ + MemoryWriteBlock(Uid, MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + + + diff --git a/Firmware/Chameleon-Mini/Application/Sl2s2002.h b/Firmware/Chameleon-Mini/Application/Sl2s2002.h new file mode 100644 index 0000000..9f58761 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Sl2s2002.h @@ -0,0 +1,24 @@ +/* + * MifareClassic.h + * + * Created on: 01.03.2017 + * Author: skuser + */ + +#ifndef SL2S2002_H_ +#define SL2S2002_H_ + +#include "Application.h" +#include "ISO15693-A.h" + +void Sl2s2002AppInit(void); +void Sl2s2002AppReset(void); +void Sl2s2002AppTask(void); +void Sl2s2002AppTick(void); +uint16_t Sl2s2002AppProcess(uint8_t* FrameBuf, uint16_t FrameBytes); +void Sl2s2002GetUid(ConfigurationUidType Uid); +void Sl2s2002SetUid(ConfigurationUidType Uid); + + + +#endif /* VICINITY_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.c b/Firmware/Chameleon-Mini/Application/TITagitstandard.c new file mode 100644 index 0000000..465d426 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.c @@ -0,0 +1,240 @@ +/* + * TITagitstandard.c + * + * Created on: 01-03-2017 + * Author: Phillip Nash + * Modified by rickventura for texas 15693 tag-it STANDARD + * Modified by ceres-c & MrMoDDoM to finish things up + */ + +#include "ISO15693-A.h" +#include "TITagitstandard.h" + +static enum { + STATE_READY, + STATE_SELECTED, + 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; + + FactoryLockBits_Mask |= (1 << 8); /* Locks block 8... */ + FactoryLockBits_Mask |= (1 << 9); /* ...and 9, which contains the UID */ + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; + + MemoryReadBlock(&MyAFI, TITAGIT_MEM_AFI_ADDRESS, 1); +} + +void TITagitstandardAppReset(void) +{ + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + FrameInfo.Selected = false; +} + + +void TITagitstandardAppTask(void) +{ + +} + +void TITagitstandardAppTick(void) +{ + +} + +uint16_t TITagitstandardAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Uid[ActiveConfiguration.UidSize]; + TITagitstandardGetUid(Uid); + + if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) + /* malformed frame */ + return ResponseByteCount; + + if (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, State == STATE_SELECTED, Uid, MyAFI)) + return ISO15693_APP_NO_RESPONSE; + + switch(State) { + case STATE_READY: + if (*FrameInfo.Command == ISO15693_CMD_INVENTORY) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_INVENTORY_DSFID; + 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) { + uint8_t *FramePtr; /* holds the address where block's data will be put */ + uint8_t PageAddress = *FrameInfo.Parameters; + + if (FrameInfo.ParamLen != 1) + break; /* malformed: not enough or too much data */ + + if (PageAddress >= TITAGIT_NUMBER_OF_SECTORS) { /* the reader is requesting a sector out of bound */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_NOT_AVL; /* real TiTag standard reply with this error */ + ResponseByteCount = 2; + break; + } + + if (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_OPTION) { /* request with option flag set */ + if (FactoryLockBits_Mask & (1 << PageAddress)) { /* tests if the n-th bit of the factory bitmask if set to 1 */ + FrameBuf[1] = 0x02; /* return bit 1 set as 1 (factory locked) */ + } else if (UserLockBits_Mask & (1 << PageAddress)) { /* tests if the n-th bit of the user bitmask if set to 1 */ + FrameBuf[1] = 0x01; /* return bit 0 set as 1 (user locked) */ + } else + FrameBuf[1] = 0x00; /* return lock status 00 (unlocked) */ + FramePtr = FrameBuf + 2; /* block's data from byte 2 */ + ResponseByteCount = 6; + } else { /* request with option flag not set */ + FramePtr = FrameBuf + 1; /* block's data from byte 1 */ + ResponseByteCount = 5; + } + + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; /* flags */ + MemoryReadBlock(FramePtr, PageAddress * TITAGIT_BYTES_PER_PAGE, TITAGIT_BYTES_PER_PAGE); + + } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_SINGLE) { + uint8_t* Dataptr; + uint8_t PageAddress = *FrameInfo.Parameters; + + if (FrameInfo.ParamLen != 5) + break; /* malformed: not enough or too much data */ + + if (PageAddress > TITAGIT_NUMBER_OF_SECTORS) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = 2; + break; /* malformed: trying to write in a non-existing block */ + } + + Dataptr = PageAddress + 0x01; + + if (FactoryLockBits_Mask & (1 << PageAddress)) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = 2; + } else if (UserLockBits_Mask & (1 << PageAddress)) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_CHG_LKD; + ResponseByteCount = 2; + } else { + MemoryWriteBlock(Dataptr, PageAddress * TITAGIT_BYTES_PER_PAGE, TITAGIT_BYTES_PER_PAGE); + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount = 1; + } + + } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_BLOCK) { + uint8_t PageAddress = *FrameInfo.Parameters; + + if (FrameInfo.ParamLen != 1) + break; /* malformed: not enough or too much data */ + + if (PageAddress > TITAGIT_NUMBER_OF_SECTORS) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = 2; + break; /* malformed: trying to lock a non-existing block */ + } + + if ((FactoryLockBits_Mask & (1 << PageAddress)) || (UserLockBits_Mask & (1 << PageAddress))) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_ALRD_LKD; + ResponseByteCount = 2; + } else { + UserLockBits_Mask |= (1 << PageAddress); /* */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount = 1; + } + + } else { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; + ResponseByteCount = 2; + } + break; + + case STATE_SELECTED: + /* Selected state is not supported by Ti TagIt Standard */ + break; + + case STATE_QUIET: + /* Ti TagIt Standard does not support reset to ready command */ + /* following code is lef for future reference for other tags */ + /* + if (Command == ISO15693_CMD_RESET_TO_READY) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount = 1; + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + } + */ + ResponseByteCount = 0; /* better safe than sorry */ + break; + + default: + break; + } + + if (ResponseByteCount > 0) { + /* There is data to be sent. Append CRC */ + ISO15693AppendCRC(FrameBuf, ResponseByteCount); + ResponseByteCount += ISO15693_CRC16_SIZE; + } + + return ResponseByteCount; +} + +void TITagitstandardGetUid(ConfigurationUidType Uid) +{ + MemoryReadBlock(&Uid[0], TITAGIT_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); + + // Reverse UID after reading it + TITagitstandardFlipUid(Uid); +} + +void TITagitstandardSetUid(ConfigurationUidType Uid) +{ + // Reverse UID before writing it + TITagitstandardFlipUid(Uid); + + MemoryWriteBlock(Uid, TITAGIT_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + +void TITagitstandardFlipUid(ConfigurationUidType Uid) +{ + uint8_t tmp, *tail; + tail = Uid + ActiveConfiguration.UidSize - 1; + while ( Uid < tail ) { + tmp = *Uid; + *Uid++ = *tail; + *tail-- = tmp; + } +} diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.h b/Firmware/Chameleon-Mini/Application/TITagitstandard.h new file mode 100644 index 0000000..2c264c6 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.h @@ -0,0 +1,30 @@ +/* + * MifareClassic.h + * + * Created on: 01.03.2017 + * Author: skuser + * modified by rickventura + */ + +#ifndef TITAGITSTANDARD_H_ +#define TITAGITSTANDARD_H_ + +#include "Application.h" + +#define TITAGIT_STD_UID_SIZE ISO15693_GENERIC_UID_SIZE //ISO15693_UID_SIZE +#define TITAGIT_STD_MEM_SIZE 44 //TAG-IT STANDARD MAX MEM SIZE +#define TITAGIT_BYTES_PER_PAGE 4 +#define TITAGIT_NUMBER_OF_SECTORS ( TITAGIT_STD_MEM_SIZE / TITAGIT_BYTES_PER_PAGE ) +#define TITAGIT_MEM_UID_ADDRESS 0x20 +#define TITAGIT_MEM_AFI_ADDRESS 0x28 // AFI byte address + +void TITagitstandardAppInit(void); +void TITagitstandardAppReset(void); +void TITagitstandardAppTask(void); +void TITagitstandardAppTick(void); +uint16_t TITagitstandardAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes); +void TITagitstandardGetUid(ConfigurationUidType Uid); +void TITagitstandardSetUid(ConfigurationUidType Uid); +void TITagitstandardFlipUid(ConfigurationUidType Uid); + +#endif /* TITAGITSTANDARD_H_ */ diff --git a/Firmware/Chameleon-Mini/Application/Vicinity.c b/Firmware/Chameleon-Mini/Application/Vicinity.c new file mode 100644 index 0000000..0b8b9a4 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Vicinity.c @@ -0,0 +1,128 @@ +/* + * ISO15693.c + * + * Created on: 01-03-2017 + * Author: Phillip Nash + * + * TODO: + * - ISO15693AddressedLegacy should be replaced with ISO15693Addressed and appropriate check + * should be performed (see TITagitstandard.c) - ceres-c + */ + + +#include "Vicinity.h" +#include "../Codec/ISO15693.h" +#include "../Memory.h" +#include "Crypto1.h" +#include "../Random.h" +#include "ISO15693-A.h" + +#define MEM_UID_ADDRESS 0x00 + +static enum { + STATE_READY, + STATE_SELECTED, + STATE_QUIET +} State; + +void VicinityAppInit(void) +{ + State = STATE_READY; +} + +void VicinityAppReset(void) +{ + State = STATE_READY; +} + + +void VicinityAppTask(void) +{ + +} + +void VicinityAppTick(void) +{ + + +} + +uint16_t VicinityAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + if (FrameBytes >= ISO15693_MIN_FRAME_SIZE) { + if(ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) { + // At this point, we have a valid ISO15693 frame + uint8_t Command = FrameBuf[1]; + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t Uid[8]; + MemoryReadBlock(Uid, MEM_UID_ADDRESS, ActiveConfiguration.UidSize); + + switch(State) { + case STATE_READY: + if (Command == ISO15693_CMD_INVENTORY) { + FrameBuf[0] = 0x00; /* Flags */ + FrameBuf[1] = 0x00; /* DSFID */ + ISO15693CopyUid(&FrameBuf[2], Uid); + ResponseByteCount = 10; + } else if (Command == ISO15693_CMD_STAY_QUIET) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + State = STATE_QUIET; + } + } else if (Command == ISO15693_CMD_GET_SYS_INFO) { + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + FrameBuf[0] = 0; /* Flags */ + FrameBuf[1] = 0; /* InfoFlags */ + ISO15693CopyUid(&FrameBuf[2], Uid); + ResponseByteCount = 10; + } + } + break; + + case STATE_SELECTED: + + break; + + case STATE_QUIET: + if (Command == ISO15693_CMD_RESET_TO_READY) { + MemoryReadBlock(Uid, MEM_UID_ADDRESS, ActiveConfiguration.UidSize); + if (ISO15693AddressedLegacy(FrameBuf, Uid)) { + FrameBuf[0] = 0; + ResponseByteCount = 1; + State = STATE_READY; + } + } + break; + + default: + break; + } + + if (ResponseByteCount > 0) { + /* There is data to be sent. Append CRC */ + ISO15693AppendCRC(FrameBuf, ResponseByteCount); + ResponseByteCount += ISO15693_CRC16_SIZE; + } + + return ResponseByteCount; + + } else { // Invalid CRC + return ISO15693_APP_NO_RESPONSE; + } + } else { // Min frame size not met + return ISO15693_APP_NO_RESPONSE; + } + +} + +void VicinityGetUid(ConfigurationUidType Uid) +{ + MemoryReadBlock(&Uid[0], MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + +void VicinitySetUid(ConfigurationUidType Uid) +{ + MemoryWriteBlock(Uid, MEM_UID_ADDRESS, ActiveConfiguration.UidSize); +} + + + diff --git a/Firmware/Chameleon-Mini/Application/Vicinity.h b/Firmware/Chameleon-Mini/Application/Vicinity.h new file mode 100644 index 0000000..7f19a91 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/Vicinity.h @@ -0,0 +1,24 @@ +/* + * MifareClassic.h + * + * Created on: 01.03.2017 + * Author: skuser + */ + +#ifndef VICINITY_H_ +#define VICINITY_H_ + +#include "Application.h" +#include "ISO15693-A.h" + +void VicinityAppInit(void); +void VicinityAppReset(void); +void VicinityAppTask(void); +void VicinityAppTick(void); +uint16_t VicinityAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes); +void VicinityGetUid(ConfigurationUidType Uid); +void VicinitySetUid(ConfigurationUidType Uid); + + + +#endif /* VICINITY_H_ */ diff --git a/Firmware/Chameleon-Mini/Button.c b/Firmware/Chameleon-Mini/Button.c index 3791783..33f3eb5 100644 --- a/Firmware/Chameleon-Mini/Button.c +++ b/Firmware/Chameleon-Mini/Button.c @@ -4,6 +4,7 @@ #include "Settings.h" #include "Memory.h" #include "Map.h" +#include "Configuration.h" #include "Terminal/CommandLine.h" #include "Application/Application.h" @@ -42,6 +43,10 @@ static void ExecuteButtonAction(ButtonActionEnum ButtonAction) for (uint8_t i=0; i +#include +#include + + +#define SOC_1_OF_4_CODE 0x7B +#define SOC_1_OF_256_CODE 0x7E +#define EOC_CODE 0xDF +#define ISO15693_SAMPLE_CLK TC_CLKSEL_DIV2_gc // 13.56MHz +#define ISO15693_SAMPLE_PERIOD 128 // 9.4us + +#define WRITE_GRID_CYCLES 4096 +#define SUBCARRIER_1 32 +#define SUBCARRIER_2 28 +#define SUBCARRIER_OFF 0 +#define SOF_PATTERN 0x1D // 0001 1101 +#define EOF_PATTERN 0xB8 // 1011 1000 + +// These registers provide quick access but are limited +// so global vars will be necessary +#define DataRegister Codec8Reg0 +#define StateRegister Codec8Reg1 +#define ModulationPauseCount Codec8Reg2 +#define SampleRegister Codec8Reg3 +#define BitSent CodecCount16Register1 +#define BitSampleCount CodecCount16Register2 +#define CodecBufferPtr CodecPtrRegister1 + +static volatile struct { + volatile bool DemodFinished; + volatile bool LoadmodFinished; + volatile bool DemodAborted; +} Flags = { 0 }; + +typedef enum { + DEMOD_SOC_STATE, + DEMOD_1_OUT_OF_4_STATE, + DEMOD_1_OUT_OF_256_STATE +} DemodStateType; + +static volatile enum { + LOADMOD_WAIT, + + /* Single subcarrier */ + LOADMOD_START_SINGLE, + LOADMOD_SOF_SINGLE, + LOADMOD_BIT0_SINGLE, + LOADMOD_BIT1_SINGLE, + LOADMOD_EOF_SINGLE, + + /* Dual subcarrier */ + LOADMOD_START_DUAL, + LOADMOD_SOF_DUAL, + LOADMOD_BIT0_DUAL, + LOADMOD_BIT1_DUAL, + LOADMOD_EOF_DUAL, + + LOADMOD_FINISHED +} LoadModState; + +static volatile DemodStateType DemodState; +static volatile uint8_t ShiftRegister; +static volatile uint8_t ByteCount; +static volatile uint16_t BitRate1; +static volatile uint16_t BitRate2; +static volatile uint16_t SampleDataCount; +static volatile uint16_t ReadCommandFromReader = 0; + +#ifdef CONFIG_VICINITY_SUPPORT + +/* This function implements CODEC_DEMOD_IN_INT0_VECT interrupt vector. + * It is called when a pulse is detected in CODEC_DEMOD_IN_PORT (PORTB). + * The relevatn interrupt vector is registered to CODEC_DEMOD_IN_MASK0 (PIN1) via: + * CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; + * and unregistered writing the INT0MASK to 0 + */ +// ISR(CODEC_DEMOD_IN_INT0_VECT) +void 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), + * the period for clock sampling is specified in StartISO15693Demod. + */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; + /* Sets register INTCTRLB to TC_CCCINTLVL_HI_gc = (0x03<<4) to enable compare/capture for high level interrupts on Channel C (CCC) */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_HI_gc; + + /* Disable this interrupt as we've already sensed the relevant pulse and will use our internal clock from now on */ + CODEC_DEMOD_IN_PORT.INT0MASK = 0; +} + +/* This function is called from isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT + * when we have 8 bits in SampleRegister and they represent an end of frame. + */ +INLINE void ISO15693_EOC(void) +{ + /* Set bitrate required by the reader on SOF for our following response */ + BitRate1 = 256 * 4; // 256 * 4 - 1 + if (CodecBuffer[0] & ISO15693_REQ_DATARATE_HIGH) + BitRate1 = 256; + + if (CodecBuffer[0] & ISO15693_REQ_SUBCARRIER_DUAL) + { + BitRate2 = 252 * 4; // 252 * 4 - 3 + if (CodecBuffer[0] & ISO15693_REQ_DATARATE_HIGH) + BitRate2 = 252; + } else { + BitRate2 = BitRate1; + } + + /* Disable event action for CODEC_TIMER_LOADMOD (TCE0) as we're done receiving data */ + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_OFF_gc; + /* Set Counter Channel B (CCB) with relevant bitmask (TC0_CCBIF_bm), the period for clock sampling is specified below */ + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_CCBIF_bm; // TODO This might not be needed since commenting it does not break anything + /* Sets register INTCTRLB to TC_CCBINTLVL_HI_gc = (0x03<<2) to enable compare/capture for high level interrupts on channel B */ + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_HI_gc; + /* Set the period for CODEC_TIMER_LOADMOD (TCE0) to Bitrate - 1 because PERBUF is 0-based + * + * TODO Why are we using PERBUF instead of PER? + * With PERBUF the period register will occur on the next overflow. + */ + CODEC_TIMER_LOADMOD.PERBUF = BitRate1 - 1; + + Flags.DemodFinished = 1; + /* Sets timer off for CODEC_TIMER_SAMPLING (TCD0) disabling clock source */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ + CODEC_TIMER_SAMPLING.INTCTRLB = 0; +} + +/* This function is registered to CODEC_TIMER_SAMPLING (TCD0)'s Counter Channel C (CCC). + * When the timer is enabled, this is called on counter's overflow + * + * It demodulates bits received from the reader and saves them in CodecBuffer. + * + * It disables its own interrupt when receives an EOF (calling ISO15693_EOC) or when it receives garbage + */ +// ISR(CODEC_TIMER_SAMPLING_CCC_VECT) // Reading data sent from the reader +void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) +{ + /* Shift demod data */ + SampleRegister = (SampleRegister << 1) | (!(CODEC_DEMOD_IN_PORT.IN & CODEC_DEMOD_IN_MASK) ? 0x01 : 0x00); + + if (++BitSampleCount == 8) + { + BitSampleCount = 0; + switch (DemodState) + { + case DEMOD_SOC_STATE: + if (SampleRegister == SOC_1_OF_4_CODE) + { + DemodState = DEMOD_1_OUT_OF_4_STATE; + SampleDataCount = 0; + ModulationPauseCount = 0; + } else if (SampleRegister == SOC_1_OF_256_CODE) { + DemodState = DEMOD_1_OUT_OF_256_STATE; + SampleDataCount = 0; + } else { // No SOC. Restart and try again, we probably received garbage. + Flags.DemodFinished = 1; + /* Sets timer off for CODEC_TIMER_SAMPLING (TCD0) disabling clock source */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ + CODEC_TIMER_SAMPLING.INTCTRLB = 0; + } + break; + + case DEMOD_1_OUT_OF_4_STATE: + if (SampleRegister == EOC_CODE) + { + ISO15693_EOC(); + } else { + uint8_t SampleData = ~SampleRegister; + if (SampleData == (0x01 << 6)) + { + /* ^_^^^^^^ -> 00 */ + ModulationPauseCount++; + DataRegister >>= 2; + + } else if (SampleData == (0x01 << 4)) { + /* ^^^_^^^^ -> 01 */ + ModulationPauseCount++; + DataRegister >>= 2; + DataRegister |= 0b01 << 6; + + } else if (SampleData == (0x01 << 2)) { + /* ^^^^^_^^ -> 10 */ + ModulationPauseCount++; + DataRegister >>= 2; + DataRegister |= 0b10 << 6; + + } else if (SampleData == (0x01 << 0)) { + /* ^^^^^^^_ -> 11 */ + ModulationPauseCount++; + DataRegister >>= 2; + DataRegister |= 0b11 << 6; + } + + if (ModulationPauseCount == 4) + { + ModulationPauseCount = 0; + *CodecBufferPtr = DataRegister; + ++CodecBufferPtr; + ++ByteCount; + } + } + break; + + case DEMOD_1_OUT_OF_256_STATE: + if (SampleRegister == EOC_CODE) + { + ISO15693_EOC(); + } else { + uint8_t Position = ((SampleDataCount / 2) % 256) - 1; + uint8_t SampleData = ~SampleRegister; + + if (SampleData == (0x01 << 6)) + { + /* ^_^^^^^^ -> N-3 */ + DataRegister = Position - 3; + ModulationPauseCount++; + + } else if (SampleData == (0x01 << 4)) { + /* ^^^_^^^^ -> N-2 */ + DataRegister = Position - 2; + ModulationPauseCount++; + + } else if (SampleData == (0x01 << 2)) { + /* ^^^^^_^^ -> N-1 */ + DataRegister = Position - 1; + ModulationPauseCount++; + + } else if (SampleData == (0x01 << 0)) { + /* ^^^^^^^_ -> N-0 */ + DataRegister = Position - 0; + ModulationPauseCount++; + } + + if (ModulationPauseCount == 1) + { + ModulationPauseCount = 0; + *CodecBufferPtr = DataRegister; + ++CodecBufferPtr; + ++ByteCount; + } + } + break; + } + } + SampleDataCount++; +} + + +/* This function is registered to CODEC_TIMER_LOADMOD (TCE0)'s Counter Channel B (CCB). + * When the timer is enabled, this is called on counter's overflow + * + * It modulates the carrier with consuming bytes in CodecBuffer until ByteCount is 0. + * + * 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) +{ + static void* JumpTable[] = { + [LOADMOD_START_SINGLE] = &&LOADMOD_START_SINGLE_LABEL, + [LOADMOD_SOF_SINGLE] = &&LOADMOD_SOF_SINGLE_LABEL, + [LOADMOD_BIT0_SINGLE] = &&LOADMOD_BIT0_SINGLE_LABEL, + [LOADMOD_BIT1_SINGLE] = &&LOADMOD_BIT1_SINGLE_LABEL, + [LOADMOD_EOF_SINGLE] = &&LOADMOD_EOF_SINGLE_LABEL, + [LOADMOD_START_DUAL] = &&LOADMOD_START_DUAL_LABEL, + [LOADMOD_SOF_DUAL] = &&LOADMOD_SOF_DUAL_LABEL, + [LOADMOD_BIT0_DUAL] = &&LOADMOD_BIT0_DUAL_LABEL, + [LOADMOD_BIT1_DUAL] = &&LOADMOD_BIT1_DUAL_LABEL, + [LOADMOD_EOF_DUAL] = &&LOADMOD_EOF_DUAL_LABEL, + [LOADMOD_FINISHED] = &&LOADMOD_FINISHED_LABEL + }; + + if ( (StateRegister >= LOADMOD_START_SINGLE) && (StateRegister <= LOADMOD_FINISHED) ) { + goto *JumpTable[StateRegister]; + } else { + return; + } + + LOADMOD_START_SINGLE_LABEL: + /* Application produced data. With this interrupt we are aligned to the bit-grid. */ + ShiftRegister = SOF_PATTERN; + BitSent = 0; + /* Fallthrough */ + LOADMOD_SOF_SINGLE_LABEL: + if (ShiftRegister & 0x80) { + CodecSetLoadmodState(true); + } else { + CodecSetLoadmodState(false); + } + + CodecStartSubcarrier(); + + ShiftRegister <<= 1; + BitSent++; + + if ( (BitSent % 8) == 0) { + /* Last SOF bit has been put out. Start sending out data */ + StateRegister = LOADMOD_BIT0_SINGLE; + ShiftRegister = (*CodecBufferPtr++); + } else { + StateRegister = LOADMOD_SOF_SINGLE; + } + return; + + LOADMOD_BIT0_SINGLE_LABEL: //Manchester encoding + if (ShiftRegister & 0x01) { + /* Deactivate carrier */ + CodecSetLoadmodState(false); + } else { + /* Activate carrier */ + CodecSetLoadmodState(true); + } + + StateRegister = LOADMOD_BIT1_SINGLE; + return; + + LOADMOD_BIT1_SINGLE_LABEL: //Manchester encoding + if (ShiftRegister & 0x01) { + CodecSetLoadmodState(true); + } else { + CodecSetLoadmodState(false); + } + + ShiftRegister >>= 1; + BitSent++; + + StateRegister = LOADMOD_BIT0_SINGLE; + + if ( (BitSent % 8) == 0 ) { + /* Byte boundary */ + if (--ByteCount == 0) { + /* No more data left */ + ShiftRegister = EOF_PATTERN; + StateRegister = LOADMOD_EOF_SINGLE; + } else { + ShiftRegister = (*CodecBufferPtr++); + } + } + return; + + LOADMOD_EOF_SINGLE_LABEL: //End of Manchester encoding + /* Output EOF */ + if (ShiftRegister & 0x80) { + CodecSetLoadmodState(true); + } else { + CodecSetLoadmodState(false); + } + + ShiftRegister <<= 1; + BitSent++; + + if ( (BitSent % 8) == 0) { + /* Last bit has been put out */ + StateRegister = LOADMOD_FINISHED; + } else { + StateRegister = LOADMOD_EOF_SINGLE; + } + return; + + // ------------------------------------------------------------- + + LOADMOD_START_DUAL_LABEL: + ShiftRegister = SOF_PATTERN; + BitSent = 0; + CodecSetLoadmodState(true); + CodecStartSubcarrier(); + // fallthrough + LOADMOD_SOF_DUAL_LABEL: + if (ShiftRegister & 0x80) { + CodecChangeDivider(SUBCARRIER_1); + CODEC_TIMER_LOADMOD.PER = BitRate1 - 1; + } else { + CodecChangeDivider(SUBCARRIER_2); + CODEC_TIMER_LOADMOD.PER = BitRate2 - 1; + } + + ShiftRegister <<= 1; + BitSent++; + + if ( (BitSent % 8) == 0) { + /* Last SOF bit has been put out. Start sending out data */ + StateRegister = LOADMOD_BIT0_DUAL; + ShiftRegister = (*CodecBufferPtr++); + } else { + StateRegister = LOADMOD_SOF_DUAL; + } + return; + + LOADMOD_BIT0_DUAL_LABEL: //Manchester encoding + if (ShiftRegister & 0x01) { + CodecChangeDivider(SUBCARRIER_2); + CODEC_TIMER_LOADMOD.PER = BitRate2 - 1; + } else { + CodecChangeDivider(SUBCARRIER_1); + CODEC_TIMER_LOADMOD.PER = BitRate1 - 1; + } + + StateRegister = LOADMOD_BIT1_DUAL; + return; + + LOADMOD_BIT1_DUAL_LABEL: //Manchester encoding + if (ShiftRegister & 0x01) { + /* fc / 32 */ + CodecChangeDivider(SUBCARRIER_1); + CODEC_TIMER_LOADMOD.PER = BitRate1 - 1; + } else { + /* fc / 28 */ + CodecChangeDivider(SUBCARRIER_2); + CODEC_TIMER_LOADMOD.PER = BitRate2 - 1; + } + + ShiftRegister >>= 1; + BitSent++; + + StateRegister = LOADMOD_BIT0_DUAL; + + if ( (BitSent % 8) == 0 ) { + /* Byte boundary */ + if (--ByteCount == 0) { + /* No more data left */ + ShiftRegister = EOF_PATTERN; + StateRegister = LOADMOD_EOF_DUAL; + } else { + ShiftRegister = (*CodecBufferPtr++); + } + } + return; + + LOADMOD_EOF_DUAL_LABEL: //End of Manchester encoding + /* Output EOF */ + if (ShiftRegister & 0x80) { + CodecChangeDivider(SUBCARRIER_1); + CODEC_TIMER_LOADMOD.PER = BitRate1 - 1; + } else { + CodecChangeDivider(SUBCARRIER_2); + CODEC_TIMER_LOADMOD.PER = BitRate2 - 1; + } + + ShiftRegister <<= 1; + BitSent++; + + if ( (BitSent % 8) == 0) { + /* Last bit has been put out */ + StateRegister = LOADMOD_FINISHED; + } else { + StateRegister = LOADMOD_EOF_DUAL; + } + return; + + LOADMOD_FINISHED_LABEL: + /* Sets timer off for CODEC_TIMER_LOADMOD (TCE0) disabling clock source as we're done modulating */ + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, 0); + Flags.LoadmodFinished = 1; + return; +} + +#endif /* CONFIG_VICINITY_SUPPORT */ + +/* This functions resets all global variables used in the codec and enables interrupts to wait for reader data */ +void StartISO15693Demod(void) { + /* Reset global variables to default values */ + CodecBufferPtr = CodecBuffer; + Flags.DemodFinished = 0; + Flags.LoadmodFinished = 0; + DemodState = DEMOD_SOC_STATE; + StateRegister = LOADMOD_WAIT; + DataRegister = 0; + SampleRegister = 0; + BitSampleCount = 0; + SampleDataCount = 0; + ModulationPauseCount = 0; + ByteCount = 0; + ShiftRegister = 0; + + /* Activate Power for demodulator */ + CodecSetDemodPower(true); + + /* Configure sampling-timer free running and sync to first modulation-pause. */ + /* Resets the counter to 0 */ + CODEC_TIMER_SAMPLING.CNT = 0; + /* Set the period for CODEC_TIMER_SAMPLING (TCD0) to ISO15693_SAMPLE_PERIOD - 1 because PER is 0-based */ + CODEC_TIMER_SAMPLING.PER = ISO15693_SAMPLE_PERIOD - 1; + /* Set Counter Channel C (CCC) register with half bit period - 1. (- 14 to compensate ISR timing overhead) */ + CODEC_TIMER_SAMPLING.CCC = ISO15693_SAMPLE_PERIOD / 2 - 14 - 1; + /* Set timer for CODEC_TIMER_SAMPLING (TCD0) to ISO15693_SAMPLE_CLK = TC_CLKSEL_DIV2_gc = System Clock / 2 + * + * TODO Why system clock / 2 and not iso period? + */ + CODEC_TIMER_SAMPLING.CTRLA = ISO15693_SAMPLE_CLK; + /* Set event action for CODEC_TIMER_SAMPLING (TCD0) to restart and trigger CODEC_TIMER_MODSTART_EVSEL = TC_EVSEL_CH0_gc = Event Channel 0 */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; + /* Set Counter Channel C (CCC) with relevant bitmask (TC0_CCCIF_bm), the period for clock sampling is specified above */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; + /* Sets register INTCTRLB to TC_CCCINTLVL_OFF_gc = (0x00<<4) to disable compare/capture C interrupts + * + * TODO Why turn it off? + */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + + /* Set event action for CODEC_TIMER_LOADMOD (TCE0) to restart and trigger CODEC_TIMER_MODSTART_EVSEL = TC_EVSEL_CH0_gc = Event Channel 0 */ + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; + /* Set the period for CODEC_TIMER_LOADMOD (TCE0) to... some magic numbers? + * Using PER instead of PERBUF breaks it when receiving ISO15693_APP_NO_RESPONSE from Application. + * + * TODO What are these numbers? + */ + CODEC_TIMER_LOADMOD.PERBUF = 4192 + 128 + 128 - 1; + /* Sets register INTCTRLA to 0 to disable timer error or overflow interrupts */ + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + /* Set timer for CODEC_TIMER_SAMPLING (TCD0) to TC_CLKSEL_EVCH6_gc = Event Channel 6 */ + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_EVCH6_gc; + + /* Start looking out for modulation pause via interrupt. */ + /* Sets register INTFLAGS to PORT_INT0LVL_HI_gc = (0x03<<0) to enable compare/capture for high level interrupts on CODEC_DEMOD_IN_PORT (PORTB) */ + CODEC_DEMOD_IN_PORT.INTFLAGS = PORT_INT0LVL_HI_gc; + /* Sets INT0MASK to CODEC_DEMOD_IN_MASK0 = PIN1_bm to use it as source for port interrupt 0 */ + CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; +} + +void ISO15693CodecInit(void) +{ + CodecInitCommon(); + + /* Register isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT function + * to CODEC_TIMER_SAMPLING (TCD0)'s Counter Channel C (CCC) + */ + isr_func_TCD0_CCC_vect = &isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT; + /* Register isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT function + * to CODEC_DEMOD_IN_PORT (PORTB) interrupt 0 + */ + isr_func_CODEC_DEMOD_IN_INT0_VECT = &isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT; + /* Register isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT function + * to CODEC_TIMER_LOADMOD (TCE0)'s Counter Channel B (CCB) + */ + isr_func_CODEC_TIMER_LOADMOD_CCB_VECT = &isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT; + + StartISO15693Demod(); +} + +void ISO15693CodecDeInit(void) +{ + /* Gracefully shutdown codec */ + CODEC_DEMOD_IN_PORT.INT0MASK = 0; + + /* Reset global variables to default values */ + CodecBufferPtr = CodecBuffer; + Flags.DemodFinished = 0; + Flags.LoadmodFinished = 0; + DemodState = DEMOD_SOC_STATE; + StateRegister = LOADMOD_WAIT; + DataRegister = 0; + SampleRegister = 0; + BitSampleCount = 0; + SampleDataCount = 0; + ModulationPauseCount = 0; + ByteCount = 0; + ShiftRegister = 0; + + /* Disable sample timer */ + /* Sets timer off for CODEC_TIMER_SAMPLING (TCD0) disabling clock source */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + /* Disable event action for CODEC_TIMER_SAMPLING (TCD0) */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + /* Sets register INTCTRLB to TC_CCCINTLVL_OFF_gc = (0x00<<4) to disable compare/capture C interrupts */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + /* Restore Counter Channel C (CCC) interrupt mask (TC0_CCCIF_bm) */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; + + /* Disable load modulation */ + /* Disable event action for CODEC_TIMER_LOADMOD (TCE0) */ + CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_OFF_gc; + /* Sets register INTCTRLB to TC_CCBINTLVL_OFF_gc = (0x00<<2) to disable compare/capture B interrupts */ + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_OFF_gc; + /* Restore Counter Channel B (CCB) interrupt mask (TC0_CCBIF_bm) */ + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_CCBIF_bm; + + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, 0); + CodecSetDemodPower(false); + CodecSetLoadmodState(false); +} + +void ISO15693CodecTask(void) +{ + if (Flags.DemodFinished) { + Flags.DemodFinished = 0; + + uint16_t DemodByteCount = ByteCount; + uint16_t AppReceivedByteCount = 0; + bool bDualSubcarrier = false; + + if (DemodByteCount > 0) + { + LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, DemodByteCount); + LEDHook(LED_CODEC_RX, LED_PULSE); + + if (CodecBuffer[0] & ISO15693_REQ_SUBCARRIER_DUAL) + { + bDualSubcarrier = true; + } + AppReceivedByteCount = ApplicationProcess(CodecBuffer, DemodByteCount); + } + + /* This is only reached when we've received a valid frame */ + if (AppReceivedByteCount != ISO15693_APP_NO_RESPONSE) { + LogEntry(LOG_INFO_CODEC_TX_DATA, CodecBuffer, AppReceivedByteCount); + LEDHook(LED_CODEC_TX, LED_PULSE); + + ByteCount = AppReceivedByteCount; + CodecBufferPtr = CodecBuffer; + + /* Start loadmodulating */ + if (bDualSubcarrier) { + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OOK, SUBCARRIER_2); + StateRegister = LOADMOD_START_DUAL; + } else { + CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OOK, SUBCARRIER_1); + StateRegister = LOADMOD_START_SINGLE; + } + + } else { + /* No data to process. Disable CODEC_TIMER_LOADMOD (TCE0) counter and start listening again */ + /* Sets timer off for CODEC_TIMER_LOADMOD (TCE0) disabling clock source as we're done modulating */ + CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_OFF_gc; + /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ + CODEC_TIMER_LOADMOD.INTCTRLB = 0; + + StartISO15693Demod(); + } + } + + if (Flags.LoadmodFinished) { + Flags.LoadmodFinished = 0; + /* Load modulation has been finished. Stop it and start to listen for incoming data again. */ + StartISO15693Demod(); + } +} diff --git a/Firmware/Chameleon-Mini/Codec/ISO15693.h b/Firmware/Chameleon-Mini/Codec/ISO15693.h new file mode 100644 index 0000000..6c2e01b --- /dev/null +++ b/Firmware/Chameleon-Mini/Codec/ISO15693.h @@ -0,0 +1,42 @@ +/* + * ISO15693.h + * + * Created on: 25.01.2017 + * Author: Phillip Nash + */ + +#ifndef ISO15693_H_ +#define ISO15693_H_ + +#include "Terminal/CommandLine.h" + +#define ISO15693_APP_NO_RESPONSE 0x0000 + +#define SUBCARRIER_1 32 +#define SUBCARRIER_2 28 +#define SUBCARRIER_OFF 0 +#define SOF_PATTERN 0x1D +#define EOF_PATTERN 0xB8 + +#define T1_NOMINAL_CYCLES 4352 - 14//4352 - 25 /* ISR prologue compensation */ +#define WRITE_GRID_CYCLES 4096 + +//Used when checking the request sent from the reader +#define ISO15693_REQ_SUBCARRIER_SINGLE 0x00 +#define ISO15693_REQ_SUBCARRIER_DUAL 0x01 +#define ISO15693_REQ_DATARATE_LOW 0x00 +#define ISO15693_REQ_DATARATE_HIGH 0x02 + + +/* Codec Interface */ +void ISO15693CodecInit(void); +void ISO15693CodecDeInit(void); +void ISO15693CodecTask(void); + +/* Application Interface */ +void ISO15693CodecStart(void); +void ISO15693CodecReset(void); + + + +#endif /* ISO15693_H_ */ diff --git a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c index 1bea53b..e26c0a2 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c @@ -48,6 +48,7 @@ void Reader14443ACodecInit(void) { /* Initialize common peripherals and start listening * for incoming data. */ CodecInitCommon(); + isr_func_TCD0_CCC_vect = &isr_Reader14443_2A_TCD0_CCC_vect; CodecSetDemodPower(true); CODEC_TIMER_SAMPLING.PER = SAMPLE_RATE_SYSTEM_CYCLES - 1; @@ -180,6 +181,12 @@ INLINE void BufferToSequence(void) } // Frame Delay Time PCD to PICC ends ISR (CODEC_TIMER_SAMPLING_CCC_VECT) +{ + isr_func_TCD0_CCC_vect(); +} + +// ISR (TCD0_CCC_vect) +void isr_Reader14443_2A_TCD0_CCC_vect(void) { CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c index 628eead..b86e7ce 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -363,11 +363,18 @@ ISR(ACA_AC0_vect) // this interrupt either finds the SOC or gets triggered befor CODEC_TIMER_LOADMOD.CTRLA = TC_CLKSEL_DIV1_gc; StateRegister = PICC_FRAME; } + +ISR(CODEC_TIMER_LOADMOD_CCB_VECT) // pause found +{ + isr_func_CODEC_TIMER_LOADMOD_CCB_VECT(); +} + // 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 +//ISR(CODEC_TIMER_LOADMOD_CCB_VECT) // pause found +void isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void) { uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; CODEC_TIMER_TIMESTAMPS.CNT = 0; @@ -487,6 +494,7 @@ void Sniff14443ACodecInit(void) PORTE.DIRSET= PIN3_bm | PIN2_bm; // Common Codec Register settings CodecInitCommon(); + isr_func_CODEC_TIMER_LOADMOD_CCB_VECT = &isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT; // Enable demodulator power CodecSetDemodPower(true); diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 1fffdd0..df5a1ff 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -37,6 +37,21 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { #ifdef CONFIG_ISO14443A_READER_SUPPORT { .Id = CONFIG_ISO14443A_READER, .Text = "ISO14443A_READER" }, #endif +#ifdef CONFIG_VICINITY_SUPPORT + { .Id = CONFIG_VICINITY, .Text = "VICINITY" }, +#endif +#ifdef CONFIG_ISO15693_SNIFF_SUPPORT + { .Id = CONFIG_ISO15693_SNIFF, .Text = "ISO15693_SNIFF" }, +#endif +#ifdef CONFIG_SL2S2002_SUPPORT + { .Id = CONFIG_SL2S2002, .Text = "SL2S2002" }, +#endif +#ifdef CONFIG_TITAGITSTANDARD_SUPPORT + { .Id = CONFIG_TITAGITSTANDARD, .Text = "TITAGITSTANDARD" }, +#endif +#ifdef CONFIG_EM4233_SUPPORT + { .Id = CONFIG_EM4233, .Text = "EM4233" }, +#endif }; /* Include all Codecs and Applications */ @@ -69,7 +84,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = ApplicationSetUidDummy, .UidSize = 0, .MemorySize = 0, - .ReadOnly = true + .ReadOnly = true, + .TagFamily = TAG_FAMILY_NONE }, #ifdef CONFIG_MF_ULTRALIGHT_SUPPORT [CONFIG_MF_ULTRALIGHT] = { @@ -85,7 +101,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareUltralightSetUid, .UidSize = MIFARE_ULTRALIGHT_UID_SIZE, .MemorySize = MIFARE_ULTRALIGHT_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, [CONFIG_MF_ULTRALIGHT_EV1_80B] = { .CodecInitFunc = ISO14443ACodecInit, @@ -100,7 +117,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareUltralightSetUid, .UidSize = MIFARE_ULTRALIGHT_UID_SIZE, .MemorySize = MIFARE_ULTRALIGHT_EV11_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, [CONFIG_MF_ULTRALIGHT_EV1_164B] = { .CodecInitFunc = ISO14443ACodecInit, @@ -115,7 +133,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareUltralightSetUid, .UidSize = MIFARE_ULTRALIGHT_UID_SIZE, .MemorySize = MIFARE_ULTRALIGHT_EV12_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, #endif #ifdef CONFIG_MF_CLASSIC_1K_SUPPORT @@ -132,7 +151,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareClassicSetUid, .UidSize = MIFARE_CLASSIC_UID_SIZE, .MemorySize = MIFARE_CLASSIC_1K_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, #endif #ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT @@ -149,7 +169,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareClassicSetUid, .UidSize = ISO14443A_UID_SIZE_DOUBLE, .MemorySize = MIFARE_CLASSIC_1K_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, #endif #ifdef CONFIG_MF_CLASSIC_4K_SUPPORT @@ -166,7 +187,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareClassicSetUid, .UidSize = MIFARE_CLASSIC_UID_SIZE, .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, #endif #ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT @@ -183,7 +205,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = MifareClassicSetUid, .UidSize = ISO14443A_UID_SIZE_DOUBLE, .MemorySize = MIFARE_CLASSIC_4K_MEM_SIZE, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A }, #endif #ifdef CONFIG_ISO14443A_SNIFF_SUPPORT @@ -200,7 +223,8 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = ApplicationSetUidDummy, .UidSize = 0, .MemorySize = 0, - .ReadOnly = true + .ReadOnly = true, + .TagFamily = TAG_FAMILY_NONE }, #endif #ifdef CONFIG_ISO14443A_READER_SUPPORT @@ -217,7 +241,98 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .ApplicationSetUidFunc = ApplicationSetUidDummy, .UidSize = 0, .MemorySize = 0, - .ReadOnly = false + .ReadOnly = false, + .TagFamily = TAG_FAMILY_NONE + }, +#endif +#ifdef CONFIG_VICINITY_SUPPORT + [CONFIG_VICINITY] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = VicinityAppInit, + .ApplicationResetFunc = VicinityAppReset, + .ApplicationTaskFunc = VicinityAppTask, + .ApplicationTickFunc = VicinityAppTick, + .ApplicationProcessFunc = VicinityAppProcess, + .ApplicationGetUidFunc = VicinityGetUid, + .ApplicationSetUidFunc = VicinitySetUid, + .UidSize = ISO15693_GENERIC_UID_SIZE, + .MemorySize = ISO15693_GENERIC_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO15693 + }, +#endif +#ifdef CONFIG_ISO15693_SNIFF_SUPPORT + [CONFIG_ISO15693_SNIFF] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = ApplicationInitDummy, + .ApplicationResetFunc = ApplicationResetDummy, + .ApplicationTaskFunc = ApplicationTaskDummy, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = ApplicationProcessDummy, + .ApplicationGetUidFunc = ApplicationGetUidDummy, + .ApplicationSetUidFunc = ApplicationSetUidDummy, + .UidSize = 0, + .MemorySize = 0, + .ReadOnly = true, + .TagFamily = TAG_FAMILY_NONE + }, +#endif +#ifdef CONFIG_SL2S2002_SUPPORT + [CONFIG_SL2S2002] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = Sl2s2002AppInit, + .ApplicationResetFunc = Sl2s2002AppReset, + .ApplicationTaskFunc = Sl2s2002AppTask, + .ApplicationTickFunc = Sl2s2002AppTick, + .ApplicationProcessFunc = Sl2s2002AppProcess, + .ApplicationGetUidFunc = Sl2s2002GetUid, + .ApplicationSetUidFunc = Sl2s2002SetUid, + .UidSize = ISO15693_GENERIC_UID_SIZE, + .MemorySize = ISO15693_GENERIC_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO15693 + }, +#endif +#ifdef CONFIG_TITAGITSTANDARD_SUPPORT + [CONFIG_TITAGITSTANDARD] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = TITagitstandardAppInit, + .ApplicationResetFunc = TITagitstandardAppReset, + .ApplicationTaskFunc = TITagitstandardAppTask, + .ApplicationTickFunc = TITagitstandardAppTick, + .ApplicationProcessFunc = TITagitstandardAppProcess, + .ApplicationGetUidFunc = TITagitstandardGetUid, + .ApplicationSetUidFunc = TITagitstandardSetUid, + .UidSize = TITAGIT_STD_UID_SIZE, + .MemorySize = TITAGIT_STD_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO15693 + }, +#endif +#ifdef CONFIG_EM4233_SUPPORT + [CONFIG_EM4233] = { + .CodecInitFunc = ISO15693CodecInit, + .CodecDeInitFunc = ISO15693CodecDeInit, + .CodecTaskFunc = ISO15693CodecTask, + .ApplicationInitFunc = EM4233AppInit, + .ApplicationResetFunc = EM4233AppReset, + .ApplicationTaskFunc = EM4233AppTask, + .ApplicationTickFunc = EM4233AppTick, + .ApplicationProcessFunc = EM4233AppProcess, + .ApplicationGetUidFunc = EM4233GetUid, + .ApplicationSetUidFunc = EM4233SetUid, + .UidSize = EM4233_STD_UID_SIZE, + .MemorySize = EM4233_STD_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO15693 }, #endif }; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 2ca4944..9d53936 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -42,11 +42,33 @@ typedef enum { #endif #ifdef CONFIG_ISO14443A_READER_SUPPORT CONFIG_ISO14443A_READER, +#endif +#ifdef CONFIG_VICINITY_SUPPORT + CONFIG_VICINITY, +#endif +#ifdef CONFIG_ISO15693_SNIFF_SUPPORT + CONFIG_ISO15693_SNIFF, +#endif +#ifdef CONFIG_SL2S2002_SUPPORT + CONFIG_SL2S2002, +#endif +#ifdef CONFIG_TITAGITSTANDARD_SUPPORT + CONFIG_TITAGITSTANDARD, +#endif +#ifdef CONFIG_EM4233_SUPPORT + CONFIG_EM4233, #endif /* This HAS to be the last element */ CONFIG_COUNT } ConfigurationEnum; +/** Tag Family definitions **/ +#define TAG_FAMILY_NONE 0 +#define TAG_FAMILY_ISO14443A 1 +#define TAG_FAMILY_ISO14443B 2 +#define TAG_FAMILY_ISO15693 5 + + /** With this `struct` the behavior of a configuration is defined. */ typedef struct { /** @@ -124,6 +146,10 @@ typedef struct { * Implies whether the Memory can be changed. */ bool ReadOnly; + /** + * Specify tag family - see the defines above. + */ + uint8_t TagFamily; } ConfigurationType; diff --git a/Firmware/Chameleon-Mini/DUMP_TEST b/Firmware/Chameleon-Mini/DUMP_TEST new file mode 100644 index 0000000..afaba81 Binary files /dev/null and b/Firmware/Chameleon-Mini/DUMP_TEST differ diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 3824633..5e61f05 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -12,6 +12,11 @@ SETTINGS += -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT SETTINGS += -DCONFIG_MF_ULTRALIGHT_SUPPORT SETTINGS += -DCONFIG_ISO14443A_SNIFF_SUPPORT SETTINGS += -DCONFIG_ISO14443A_READER_SUPPORT +SETTINGS += -DCONFIG_VICINITY_SUPPORT +SETTINGS += -DCONFIG_SL2S2002_SUPPORT +SETTINGS += -DCONFIG_TITAGITSTANDARD_SUPPORT +SETTINGS += -DCONFIG_ISO15693_SNIFF_SUPPORT +SETTINGS += -DCONFIG_EM4233_SUPPORT #Support magic mode on mifare classic configuration SETTINGS += -DSUPPORT_MF_CLASSIC_MAGIC_MODE @@ -94,6 +99,8 @@ SRC += $(TARGET).c LUFADescriptors.c System.c Configuration.c Random.c C SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Terminal/CommandLine.c 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 +SRC += Codec/ISO15693.c +SRC += Application/Vicinity.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 c6307a8..6577768 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -80,6 +80,11 @@ CommandStatusIdType CommandSetUid(char* OutMessage, const char* InParam) for (uint8_t i=0; i; + } block [52]; + + struct Emulation_data { + char UID[8] ; + char AFI[1] ; + char DSFID[1] ; + char RFU[2] ; + char Info_bits[4] ; + struct Lock_status_bytes { + char lsbyte ; + } lsb [52]; + char Password[4] ; + char Key[12] ; + } emudata; + +} file ; \ No newline at end of file