diff --git a/Doc/DoxygenPages/Buttons.txt b/Doc/DoxygenPages/Buttons.txt index 70b75d25..35db309a 100644 --- a/Doc/DoxygenPages/Buttons.txt +++ b/Doc/DoxygenPages/Buttons.txt @@ -29,6 +29,7 @@ * `RECALL_MEM` | Recalls a setting from the permanent Flash memory. Equivalent to the `RECALL` command. * `TOGGLE_FIELD` | Activates the reader field if it was deactivated, deactivates the reader field if it was activated. * `STORE_LOG` | Writes the current log from SRAM to FRAM and clears the SRAM log. Equivalent to the `STORE_LOG` command. + * `CLONE_MFU` | Triggers the clone of a Mifare Ultralight card in range of the antenna to the selected slot and configures it to emulate it. Equivalent to the `CLONE_MFU` command. * * Note the UID commands have no effect when the slot is configured as reader. */ \ No newline at end of file diff --git a/Doc/DoxygenPages/CommandLine.txt b/Doc/DoxygenPages/CommandLine.txt index fe0628b1..5e848a57 100644 --- a/Doc/DoxygenPages/CommandLine.txt +++ b/Doc/DoxygenPages/CommandLine.txt @@ -111,6 +111,7 @@ * `SEND_RAW `| Does NOT add parity bits, sends the given byte string and returns the cards answer * `GETUID` | Obtains the UID of a card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command". * `DUMP_MFU` | Reads the whole content of a Mifare Ultralight card that is in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command". + * `CLONE_MFU` | Clones a Mifare Ultralight card that is in the range of the antenna to the current slot, which is then accordingly configured to emulate it. This command is a \ref Anchor_TimeoutCommands "Timeout command". * `IDENTIFY` | Identifies the type of a card in the range of the antenna and returns it. This command is a \ref Anchor_TimeoutCommands "Timeout command". * `THRESHOLD=?` | Returns the possible number range for the reader threshold. * `THRESHOLD=` | Globally sets the reader threshold. The influences the reader function and range. Setting a wrong value may result in malfunctioning of the reader. DEFAULT: 400 diff --git a/Firmware/Chameleon-Mini/Application/EM4233.c b/Firmware/Chameleon-Mini/Application/EM4233.c index 0bf28b26..5a8856a9 100644 --- a/Firmware/Chameleon-Mini/Application/EM4233.c +++ b/Firmware/Chameleon-Mini/Application/EM4233.c @@ -23,9 +23,6 @@ static enum { } 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; @@ -38,7 +35,7 @@ void EM4233AppInit(void) { FrameInfo.Selected = false; loggedIn = false; MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1); - + MemoryReadBlock(&Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); } void EM4233AppReset(void) { @@ -51,6 +48,8 @@ void EM4233AppReset(void) { FrameInfo.Addressed = false; FrameInfo.Selected = false; loggedIn = false; + MemoryReadBlock(&MyAFI, EM4233_MEM_AFI_ADDRESS, 1); + MemoryReadBlock(&Uid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); } void EM4233AppTask(void) { @@ -62,7 +61,7 @@ void EM4233AppTick(void) { } uint16_t EM4233_Lock_Block(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t BlockAddress = *FrameInfo.Parameters; uint8_t LockStatus = 0; @@ -92,7 +91,7 @@ uint16_t EM4233_Lock_Block(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Write_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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; @@ -127,7 +126,7 @@ uint16_t EM4233_Write_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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; @@ -138,7 +137,7 @@ uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { 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 */ + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ } return ResponseByteCount; /* If not addressed real tag does not respond */ @@ -168,7 +167,7 @@ uint16_t EM4233_Read_Single(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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 */ @@ -179,7 +178,7 @@ uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) { 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 */ + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_GENERIC; ResponseByteCount += 2; /* Copied this behaviour from real tag, not specified in ISO documents */ } return ResponseByteCount; /* If not addressed real tag does not respond */ @@ -224,7 +223,7 @@ uint16_t EM4233_Read_Multiple(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Write_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t AFI = FrameInfo.Parameters[0]; uint8_t LockStatus = 0; @@ -251,7 +250,7 @@ uint16_t EM4233_Write_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Lock_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t LockStatus = 0; if (FrameInfo.ParamLen != 0) @@ -278,7 +277,7 @@ uint16_t EM4233_Lock_AFI(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Write_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t DSFID = FrameInfo.Parameters[0]; uint8_t LockStatus = 0; @@ -304,7 +303,7 @@ uint16_t EM4233_Write_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Lock_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t LockStatus = 0; if (FrameInfo.ParamLen != 0) @@ -331,7 +330,7 @@ uint16_t EM4233_Lock_DSFID(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t FramePtr; /* holds the address where block's data will be put */ if (FrameInfo.ParamLen != 0) @@ -354,8 +353,6 @@ uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) { 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 */ @@ -398,7 +395,7 @@ uint8_t EM4233_Get_SysInfo(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Get_Multi_Block_Sec_Stat(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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; @@ -427,7 +424,7 @@ uint16_t EM4233_Get_Multi_Block_Sec_Stat(uint8_t *FrameBuf, uint16_t FrameBytes) } uint16_t EM4233_Select(uint8_t *FrameBuf, uint16_t FrameBytes, uint8_t *Uid) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* I've no idea how this request could generate errors ._. if ( ) { FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; @@ -463,7 +460,7 @@ uint16_t EM4233_Select(uint8_t *FrameBuf, uint16_t FrameBytes, uint8_t *Uid) { } uint16_t EM4233_Reset_To_Ready(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; /* I've no idea how this request could generate errors ._. if ( ) { FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; @@ -487,7 +484,7 @@ uint16_t EM4233_Reset_To_Ready(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + ResponseByteCount = ISO15693_APP_NO_RESPONSE; uint8_t Password[4] = { 0 }; if (FrameInfo.ParamLen != 4 || !FrameInfo.Addressed || !(FrameInfo.Selected && State == STATE_SELECTED)) @@ -523,7 +520,7 @@ uint16_t EM4233_Login(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Auth1(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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 */ @@ -548,7 +545,7 @@ uint16_t EM4233_Auth1(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233_Auth2(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + 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 */ @@ -566,9 +563,7 @@ uint16_t EM4233_Auth2(uint8_t *FrameBuf, uint16_t FrameBytes) { } uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { - uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; - uint8_t Uid[ActiveConfiguration.UidSize]; - EM4233GetUid(Uid); + ResponseByteCount = ISO15693_APP_NO_RESPONSE; if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) /* malformed frame */ @@ -585,8 +580,8 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { return ISO15693_APP_NO_RESPONSE; if (State == STATE_READY || State == STATE_SELECTED) { - - if (*FrameInfo.Command == ISO15693_CMD_INVENTORY) { + switch (*FrameInfo.Command) { + case ISO15693_CMD_INVENTORY: if (FrameInfo.ParamLen == 0) return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ @@ -596,59 +591,77 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { ISO15693CopyUid(&FrameBuf[ISO15693_RES_ADDR_PARAM + 0x01], Uid); ResponseByteCount += 10; } + break; - } else if ((*FrameInfo.Command == ISO15693_CMD_STAY_QUIET) && FrameInfo.Addressed) { - State = STATE_QUIET; + case ISO15693_CMD_STAY_QUIET: + if (FrameInfo.Addressed) + State = STATE_QUIET; + break; - } else if (*FrameInfo.Command == ISO15693_CMD_READ_SINGLE) { + case ISO15693_CMD_READ_SINGLE: ResponseByteCount = EM4233_Read_Single(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_SINGLE) { + case ISO15693_CMD_WRITE_SINGLE: ResponseByteCount = EM4233_Write_Single(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_BLOCK) { + case ISO15693_CMD_LOCK_BLOCK: ResponseByteCount = EM4233_Lock_Block(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_READ_MULTIPLE) { + case ISO15693_CMD_READ_MULTIPLE: ResponseByteCount = EM4233_Read_Multiple(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_AFI) { + case ISO15693_CMD_WRITE_AFI: ResponseByteCount = EM4233_Write_AFI(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_AFI) { + case ISO15693_CMD_LOCK_AFI: ResponseByteCount = EM4233_Lock_AFI(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_WRITE_DSFID) { + case ISO15693_CMD_WRITE_DSFID: ResponseByteCount = EM4233_Write_DSFID(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_LOCK_DSFID) { + case ISO15693_CMD_LOCK_DSFID: ResponseByteCount = EM4233_Lock_DSFID(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_GET_SYS_INFO) { + case ISO15693_CMD_GET_SYS_INFO: ResponseByteCount = EM4233_Get_SysInfo(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_GET_BLOCK_SEC) { + case ISO15693_CMD_GET_BLOCK_SEC: ResponseByteCount = EM4233_Get_Multi_Block_Sec_Stat(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { + case ISO15693_CMD_RESET_TO_READY: ResponseByteCount = EM4233_Reset_To_Ready(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == EM4233_CMD_LOGIN) { + case EM4233_CMD_LOGIN: ResponseByteCount = EM4233_Login(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == EM4233_CMD_AUTH1) { + case EM4233_CMD_AUTH1: ResponseByteCount = EM4233_Auth1(FrameBuf, FrameBytes); + break; - } else if (*FrameInfo.Command == EM4233_CMD_AUTH2) { + case EM4233_CMD_AUTH2: ResponseByteCount = EM4233_Auth2(FrameBuf, FrameBytes); + break; - } else { + default: 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 */ - } + break; +} } else if (State == STATE_QUIET) { if (*FrameInfo.Command == ISO15693_CMD_RESET_TO_READY) { @@ -656,12 +669,6 @@ uint16_t EM4233AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { } } - if (ResponseByteCount > 0) { - /* There is data to send. Append CRC */ - ISO15693AppendCRC(FrameBuf, ResponseByteCount); - ResponseByteCount += ISO15693_CRC16_SIZE; - } - return ResponseByteCount; } @@ -669,6 +676,7 @@ 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); +void EM4233SetUid(ConfigurationUidType NewUid) { + memcpy(Uid, NewUid, ActiveConfiguration.UidSize); + MemoryWriteBlock(NewUid, EM4233_MEM_UID_ADDRESS, ActiveConfiguration.UidSize); } diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.c b/Firmware/Chameleon-Mini/Application/ISO15693-A.c index f89697e3..9308d9e4 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.c +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.c @@ -2,6 +2,11 @@ #include "../Common.h" #include +CurrentFrame FrameInfo; +uint8_t Uid[ISO15693_GENERIC_UID_SIZE]; +uint8_t MyAFI; +uint16_t ResponseByteCount; + //Refer to ISO/IEC 15693-3:2001 page 41 uint16_t calculateCRC(void *FrameBuf, uint16_t FrameBufSize) { uint16_t reg = ISO15693_CRC16_PRESET; diff --git a/Firmware/Chameleon-Mini/Application/ISO15693-A.h b/Firmware/Chameleon-Mini/Application/ISO15693-A.h index d4fc2abc..61d67018 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.h +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.h @@ -85,6 +85,10 @@ typedef struct { bool Addressed; bool Selected; } CurrentFrame; +extern CurrentFrame FrameInfo; /* Holds current frame information */ +extern uint8_t Uid[]; +extern uint8_t MyAFI; /* Holds current tag's AFI, used during inventory */ +extern uint16_t ResponseByteCount; /* Length of response, used when building response frames */ void ISO15693AppendCRC(uint8_t *FrameBuf, uint16_t FrameBufSize); bool ISO15693CheckCRC(void *FrameBuf, uint16_t FrameBufSize); diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.c b/Firmware/Chameleon-Mini/Application/Reader14443A.c index 6d6c236a..921a171a 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.c +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.c @@ -20,6 +20,9 @@ // TODO replace remaining magic numbers +uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE]; +uint16_t ReaderSendBitCount; + static bool Selected = false; Reader14443Command Reader14443CurrentCommand = Reader14443_Do_Nothing; @@ -684,6 +687,7 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { return rVal; } + case Reader14443_Clone_MF_Ultralight: case Reader14443_Read_MF_Ultralight: { static uint8_t MFURead_CurrentAdress = 0; static uint8_t MFUContents[64]; @@ -718,18 +722,28 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { if (MFURead_CurrentAdress == 16) { Selected = false; MFURead_CurrentAdress = 0; - Reader14443CurrentCommand = Reader14443_Do_Nothing; - - char tmpBuf[135]; // 135 = 128 hex digits + 3 * \r\n + \0 - BufferToHexString(tmpBuf, 135, MFUContents, 16); - snprintf(tmpBuf + 32, 135 - 32, "\r\n"); - BufferToHexString(tmpBuf + 32 + 2, 135 - 32 - 2, MFUContents + 16, 16); - snprintf(tmpBuf + 32 + 2 + 32, 135 - 32 - 2 - 32, "\r\n"); - BufferToHexString(tmpBuf + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2, MFUContents + 32, 16); - snprintf(tmpBuf + 32 + 2 + 32 + 2 + 32, 135 - 32 - 2 - 32 - 2 - 32, "\r\n"); - BufferToHexString(tmpBuf + 32 + 2 + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2 - 32 - 2, MFUContents + 48, 16); - CodecReaderFieldStop(); - CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + + if (Reader14443CurrentCommand == Reader14443_Read_MF_Ultralight) { // dump + Reader14443CurrentCommand = Reader14443_Do_Nothing; + char tmpBuf[135]; // 135 = 128 hex digits + 3 * \r\n + \0 + BufferToHexString(tmpBuf, 135, MFUContents, 16); + snprintf(tmpBuf + 32, 135 - 32, "\r\n"); + BufferToHexString(tmpBuf + 32 + 2, 135 - 32 - 2, MFUContents + 16, 16); + snprintf(tmpBuf + 32 + 2 + 32, 135 - 32 - 2 - 32, "\r\n"); + BufferToHexString(tmpBuf + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2, MFUContents + 32, 16); + snprintf(tmpBuf + 32 + 2 + 32 + 2 + 32, 135 - 32 - 2 - 32 - 2 - 32, "\r\n"); + BufferToHexString(tmpBuf + 32 + 2 + 32 + 2 + 32 + 2, 135 - 32 - 2 - 32 - 2 - 32 - 2, MFUContents + 48, 16); + CodecReaderFieldStop(); + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, tmpBuf); + } else { // clone + Reader14443CurrentCommand = Reader14443_Do_Nothing; + CodecReaderFieldStop(); + MemoryUploadBlock(&MFUContents, 0, 64); + CommandLinePendingTaskFinished(COMMAND_INFO_OK_WITH_TEXT_ID, "Card Cloned to Slot"); + ConfigurationSetById(CONFIG_MF_ULTRALIGHT); + MemoryStore(); + SettingsSave(); + } return 0; } Buffer[0] = 0x30; // MiFare Ultralight read command @@ -803,17 +817,17 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { if (CardCandidatesIdx == 1) { int cfgid = -1; switch (CardCandidates[0]) { -#ifdef CONFIG_MF_ULTRALIGHT_SUPPORT case CardType_NXP_MIFARE_Ultralight: { cfgid = CONFIG_MF_ULTRALIGHT; // TODO: enter MFU clone mdoe break; } -#endif case CardType_NXP_MIFARE_Classic_1k: case CardType_Infineon_MIFARE_Classic_1k: { if (CardCharacteristics.UIDSize == UIDSize_Single) { +#ifdef CONFIG_MF_CLASSIC_1K_SUPPORT cfgid = CONFIG_MF_CLASSIC_1K; +#endif #ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT } else if (CardCharacteristics.UIDSize == UIDSize_Double) { cfgid = CONFIG_MF_CLASSIC_1K_7B; @@ -825,8 +839,10 @@ uint16_t Reader14443AAppProcess(uint8_t *Buffer, uint16_t BitCount) { case CardType_Nokia_MIFARE_Classic_4k_emulated_6212: case CardType_Nokia_MIFARE_Classic_4k_emulated_6131: { if (CardCharacteristics.UIDSize == UIDSize_Single) { +#ifdef CONFIG_MF_CLASSIC_4K_SUPPORT cfgid = CONFIG_MF_CLASSIC_4K; -#ifdef CONFIG_MF_CLASSIC_1K_7B_SUPPORT +#endif +#ifdef CONFIG_MF_CLASSIC_4K_7B_SUPPORT } else if (CardCharacteristics.UIDSize == UIDSize_Double) { cfgid = CONFIG_MF_CLASSIC_4K_7B; #endif diff --git a/Firmware/Chameleon-Mini/Application/Reader14443A.h b/Firmware/Chameleon-Mini/Application/Reader14443A.h index 9125470c..e2e32b9b 100644 --- a/Firmware/Chameleon-Mini/Application/Reader14443A.h +++ b/Firmware/Chameleon-Mini/Application/Reader14443A.h @@ -6,8 +6,8 @@ #define CRC_INIT 0x6363 -uint8_t ReaderSendBuffer[CODEC_BUFFER_SIZE]; -uint16_t ReaderSendBitCount; +extern uint8_t ReaderSendBuffer[]; +extern uint16_t ReaderSendBitCount; void Reader14443AAppInit(void); void Reader14443AAppReset(void); @@ -30,7 +30,8 @@ typedef enum { Reader14443_Autocalibrate, Reader14443_Read_MF_Ultralight, Reader14443_Identify, - Reader14443_Identify_Clone + Reader14443_Identify_Clone, + Reader14443_Clone_MF_Ultralight } Reader14443Command; diff --git a/Firmware/Chameleon-Mini/Application/Sl2s2002.c b/Firmware/Chameleon-Mini/Application/Sl2s2002.c index e8a242e5..ffdbed1e 100644 --- a/Firmware/Chameleon-Mini/Application/Sl2s2002.c +++ b/Firmware/Chameleon-Mini/Application/Sl2s2002.c @@ -141,12 +141,6 @@ uint16_t Sl2s2002AppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { break; } - if (ResponseByteCount > 0) { - /* There is data to be sent. Append CRC */ - ISO15693AppendCRC(FrameBuf, ResponseByteCount); - ResponseByteCount += ISO15693_CRC16_SIZE; - } - return ResponseByteCount; } else { // Invalid CRC diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.c b/Firmware/Chameleon-Mini/Application/TITagitstandard.c index 4ed2c5cd..2d4618c9 100644 --- a/Firmware/Chameleon-Mini/Application/TITagitstandard.c +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.c @@ -16,10 +16,8 @@ static enum { STATE_QUIET } State; -uint8_t MyAFI; /* Holds current tag's AFI (is used in inventory) */ uint16_t UserLockBits_Mask = 0; /* Holds lock state of blocks */ uint16_t FactoryLockBits_Mask = 0; /* Holds lock state of blocks */ -CurrentFrame FrameInfo; void TITagitstandardAppInit(void) { State = STATE_READY; @@ -35,6 +33,7 @@ void TITagitstandardAppInit(void) { FrameInfo.Selected = false; MemoryReadBlock(&MyAFI, TITAGIT_MEM_AFI_ADDRESS, 1); + TITagitstandardGetUid(Uid); } void TITagitstandardAppReset(void) { @@ -46,6 +45,9 @@ void TITagitstandardAppReset(void) { FrameInfo.ParamLen = 0; FrameInfo.Addressed = false; FrameInfo.Selected = false; + + MemoryReadBlock(&MyAFI, TITAGIT_MEM_AFI_ADDRESS, 1); + TITagitstandardGetUid(Uid); } @@ -58,9 +60,7 @@ 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); + ResponseByteCount = ISO15693_APP_NO_RESPONSE; if ((FrameBytes < ISO15693_MIN_FRAME_SIZE) || !ISO15693CheckCRC(FrameBuf, FrameBytes - ISO15693_CRC16_SIZE)) /* malformed frame */ @@ -198,12 +198,6 @@ uint16_t TITagitstandardAppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { break; } - if (ResponseByteCount > 0) { - /* There is data to be sent. Append CRC */ - ISO15693AppendCRC(FrameBuf, ResponseByteCount); - ResponseByteCount += ISO15693_CRC16_SIZE; - } - return ResponseByteCount; } @@ -214,7 +208,8 @@ void TITagitstandardGetUid(ConfigurationUidType Uid) { TITagitstandardFlipUid(Uid); } -void TITagitstandardSetUid(ConfigurationUidType Uid) { +void TITagitstandardSetUid(ConfigurationUidType NewUid) { + memcpy(Uid, NewUid, ActiveConfiguration.UidSize); // Update the local variable // Reverse UID before writing it TITagitstandardFlipUid(Uid); diff --git a/Firmware/Chameleon-Mini/Application/Vicinity.c b/Firmware/Chameleon-Mini/Application/Vicinity.c index a79e167c..c3bc1716 100644 --- a/Firmware/Chameleon-Mini/Application/Vicinity.c +++ b/Firmware/Chameleon-Mini/Application/Vicinity.c @@ -92,12 +92,6 @@ uint16_t VicinityAppProcess(uint8_t *FrameBuf, uint16_t FrameBytes) { break; } - if (ResponseByteCount > 0) { - /* There is data to be sent. Append CRC */ - ISO15693AppendCRC(FrameBuf, ResponseByteCount); - ResponseByteCount += ISO15693_CRC16_SIZE; - } - return ResponseByteCount; } else { // Invalid CRC diff --git a/Firmware/Chameleon-Mini/Button.c b/Firmware/Chameleon-Mini/Button.c index 392cdc02..5d572536 100644 --- a/Firmware/Chameleon-Mini/Button.c +++ b/Firmware/Chameleon-Mini/Button.c @@ -43,6 +43,7 @@ static const MapEntryType PROGMEM ButtonActionMap[] = { { .Id = BUTTON_ACTION_STORE_LOG, .Text = "STORE_LOG" }, { .Id = BUTTON_ACTION_CLEAR_LOG, .Text = "CLEAR_LOG" }, { .Id = BUTTON_ACTION_CLONE, .Text = "CLONE" }, + { .Id = BUTTON_ACTION_CLONE_MFU, .Text = "CLONE_MFU" }, }; static void ExecuteButtonAction(ButtonActionEnum ButtonAction) { @@ -202,6 +203,10 @@ static void ExecuteButtonAction(ButtonActionEnum ButtonAction) { CommandExecute("CLONE"); break; } + case BUTTON_ACTION_CLONE_MFU: { + CommandExecute("CLONE_MFU"); + break; + } default: break; diff --git a/Firmware/Chameleon-Mini/Button.h b/Firmware/Chameleon-Mini/Button.h index 4ec4833c..dd66cf9d 100644 --- a/Firmware/Chameleon-Mini/Button.h +++ b/Firmware/Chameleon-Mini/Button.h @@ -35,6 +35,7 @@ typedef enum { BUTTON_ACTION_STORE_LOG, BUTTON_ACTION_CLEAR_LOG, BUTTON_ACTION_CLONE, + BUTTON_ACTION_CLONE_MFU, /* This has to be last element */ BUTTON_ACTION_COUNT diff --git a/Firmware/Chameleon-Mini/Codec/Codec.c b/Firmware/Chameleon-Mini/Codec/Codec.c index 14d0bdf4..703ed17a 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.c +++ b/Firmware/Chameleon-Mini/Codec/Codec.c @@ -25,6 +25,11 @@ static volatile struct { uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; + +void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void) = NULL; +void (* volatile isr_func_TCD0_CCC_vect)(void) = NULL; +void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void) = NULL; + // the following three functions prevent sending data directly after turning on the reader field void CodecReaderFieldStart(void) { // DO NOT CALL THIS FUNCTION INSIDE APPLICATION! if (!CodecGetReaderField() && !ReaderFieldFlags.ToBeRestarted) { diff --git a/Firmware/Chameleon-Mini/Codec/Codec.h b/Firmware/Chameleon-Mini/Codec/Codec.h index d985e426..df14ceb2 100644 --- a/Firmware/Chameleon-Mini/Codec/Codec.h +++ b/Firmware/Chameleon-Mini/Codec/Codec.h @@ -8,26 +8,6 @@ #ifndef CODEC_H_ #define CODEC_H_ -#include -#include -#include -#include "../Common.h" -#include "../Configuration.h" -#include "../Settings.h" - -#include "ISO14443-2A.h" -#include "Reader14443-2A.h" -#include "SniffISO14443-2A.h" -#include "ISO15693.h" - -/* Timing definitions for ISO14443A */ -#define ISO14443A_SUBCARRIER_DIVIDER 16 -#define ISO14443A_BIT_GRID_CYCLES 128 -#define ISO14443A_BIT_RATE_CYCLES 128 -#define ISO14443A_FRAME_DELAY_PREV1 1236 -#define ISO14443A_FRAME_DELAY_PREV0 1172 -#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms - /* Peripheral definitions */ #define CODEC_DEMOD_POWER_PORT PORTB #define CODEC_DEMOD_POWER_MASK PIN0_bm @@ -87,6 +67,27 @@ #define CODEC_TIMER_TIMESTAMPS_CCA_VECT TCD1_CCA_vect #define CODEC_TIMER_TIMESTAMPS_CCB_VECT TCD1_CCB_vect +#ifndef __ASSEMBLER__ + +#include +#include +#include +#include "../Common.h" +#include "../Configuration.h" +#include "../Settings.h" + +#include "ISO14443-2A.h" +#include "Reader14443-2A.h" +#include "SniffISO14443-2A.h" +#include "ISO15693.h" + +/* Timing definitions for ISO14443A */ +#define ISO14443A_SUBCARRIER_DIVIDER 16 +#define ISO14443A_BIT_GRID_CYCLES 128 +#define ISO14443A_BIT_RATE_CYCLES 128 +#define ISO14443A_FRAME_DELAY_PREV1 1236 +#define ISO14443A_FRAME_DELAY_PREV0 1172 +#define ISO14443A_RX_PENDING_TIMEOUT 4 // ms #define CODEC_BUFFER_SIZE 256 @@ -115,13 +116,14 @@ typedef enum { extern uint8_t CodecBuffer[CODEC_BUFFER_SIZE]; extern uint8_t CodecBuffer2[CODEC_BUFFER_SIZE]; -void (* volatile isr_func_TCD0_CCC_vect)(void); +/* Shared ISR pointers and handlers */ +extern void (* volatile isr_func_TCD0_CCC_vect)(void); void isr_Reader14443_2A_TCD0_CCC_vect(void); void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void); -void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void); +extern void (* volatile isr_func_CODEC_DEMOD_IN_INT0_VECT)(void); void isr_ISO14443_2A_TCD0_CCC_vect(void); void isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void); -void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void); +extern void (* volatile isr_func_CODEC_TIMER_LOADMOD_CCB_VECT)(void); void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void); void isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void); @@ -285,4 +287,7 @@ bool CodecIsReaderToBeRestarted(void); void CodecThresholdSet(uint16_t th); uint16_t CodecThresholdIncrement(void); void CodecThresholdReset(void); + +#endif /* __ASSEMBLER__ */ + #endif /* CODEC_H_ */ diff --git a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c index ddad5ce2..507347e1 100644 --- a/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/ISO14443-2A.c @@ -79,13 +79,8 @@ static void StartDemod(void) { CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; } -ISR(CODEC_DEMOD_IN_INT0_VECT) { - isr_func_CODEC_DEMOD_IN_INT0_VECT(); -} - -// ISR(CODEC_DEMOD_IN_INT0_VECT) // Find first pause and start sampling -void isr_ISO14443_2A_TCD0_CCC_vect(void) { +ISR_SHARED isr_ISO14443_2A_TCD0_CCC_vect(void) { /* This is the first edge of the first modulation-pause after StartDemod. * Now we have time to start * demodulating beginning from one bit-width after this edge. */ diff --git a/Firmware/Chameleon-Mini/Codec/ISO15693.c b/Firmware/Chameleon-Mini/Codec/ISO15693.c index 152837e5..02214847 100644 --- a/Firmware/Chameleon-Mini/Codec/ISO15693.c +++ b/Firmware/Chameleon-Mini/Codec/ISO15693.c @@ -4,6 +4,25 @@ * Created on: 25.01.2017 * Author: Phillip Nash * Modified by: ceres-c + * + * Interrupts information + * - Compare/Capture Channels are used as compare. They're used to sample the field in different moments of time + * - Reader field demodulation events are routed on Event Channel 0, card data modulation on Event Channel 6 + * - Reader field demodulation uses Compare Channel C, card data modulation Compare Channel D (PORTB in both cases, of course) + * + * Loadmod code flow: + * Loadmodulation is performed via a state machine inside a ISR, triggered by a counter's (TCD0) overflow interrupt. The interrupt + * is configured in StartISO15693Demod to have a PER (period) equal to ISO15693 t1 nominal time: 4352 carrier pulses. + * (see ISO15693-3:2009, section 9.1). + * Once a EOF is reached when demodulating data from the reader, TCD0's PERBUF register is configured with the period of + * bit transmission (32 carrier pulses). This means that, once the first period overflow is reached (t1 expiration) + * the ISR will output data at the frequency dictated by the standard. This is due to the behaviour of buffered registers, see + * 8045A-AVR-02/08 section 3.7. + * + * Once t1 is reached (the counter overflowed), transmission of data should theoretically begin, but this is not guaranteed, + * due to possible slowdowns of data generation in the currently running Application. Until the application is done, + * the state machine will be stuck in LOADMOD_WAIT state, not outputting any data. + * The ISR will now be invoked every 32 carrier pulses (see ISO15693-2:2006, section 8.2), even when waiting for data. */ #include "ISO15693.h" @@ -12,18 +31,20 @@ #include "LEDHook.h" #include "AntennaLevel.h" #include "Terminal/Terminal.h" -//#include -#include #include #define SOC_1_OF_4_CODE 0x7B #define SOC_1_OF_256_CODE 0x7E #define EOC_CODE 0xDF +#define REQ_SUBCARRIER_SINGLE 0x00 +#define REQ_SUBCARRIER_DUAL 0x01 +#define REQ_DATARATE_LOW 0x00 +#define REQ_DATARATE_HIGH 0x02 #define ISO15693_SAMPLE_CLK TC_CLKSEL_DIV2_gc // 13.56MHz #define ISO15693_SAMPLE_PERIOD 128 // 9.4us +#define ISO15693_T1_TIME 4352 - 14 /* ISO t1 time - ISR prologue compensation */ // 4192 + 128 + 128 - 1 -#define WRITE_GRID_CYCLES 4096 #define SUBCARRIER_1 32 #define SUBCARRIER_2 28 #define SUBCARRIER_OFF 0 @@ -43,7 +64,6 @@ static volatile struct { volatile bool DemodFinished; volatile bool LoadmodFinished; - volatile bool DemodAborted; } Flags = { 0 }; typedef enum { @@ -78,26 +98,22 @@ 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; /* 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: + * The relevant interrupt vector was 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. - */ +ISR_SHARED isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void) { + /* Clear Compare Channel C (CCC) interrupt Flags - From 14.12.10 [8331F–AVR–04/2013] */ 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) */ + /* Enable compare/capture for high level interrupts on Capture Channel C for TCD0 - From 14.12.7 [8331F–AVR–04/2013] */ 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 */ + /* Disable this interrupt. From now on we will sample the field using our internal clock - From 13.13.11 [8331F–AVR–04/2013] */ CODEC_DEMOD_IN_PORT.INT0MASK = 0; + } /* This function is called from isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT @@ -105,36 +121,50 @@ void isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT(void) { */ 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) + if (CodecBuffer[0] & 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; + BitRate2 = 252; /* If single subcarrier mode is requested, BitRate2 is useless, but setting it nevertheless was still faster than checking */ } else { - BitRate2 = BitRate1; + BitRate1 = 256 * 4; // Possible value: 256 * 4 - 1 + BitRate2 = 252 * 4; // Possible value: 252 * 4 - 3 } - /* Disable event action for CODEC_TIMER_LOADMOD (TCE0) as we're done receiving data */ + Flags.DemodFinished = 1; + /* Disable demodulation interrupt */ + /* Sets timer off for TCD0, disabling clock source. We're done receiving data from reader and don't need to probe the antenna anymore - From 14.12.1 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; + /* Disable event action for CODEC_TIMER_SAMPLING (TCD0) - From 14.12.4 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + /* Disable compare/capture interrupts on Channel C - From 14.12.7 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + /* Clear Compare Channel C (CCC) interrupt Flags - From 14.12.10 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; + + /* Enable loadmodulation interrupt */ + /* Disable the event action for TCE0 - From 14.12.4 [8331F–AVR–04/2013] */ 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 */ + /* Enable compare/capture for high level interrupts on channel B for TCE0 - From 14.12.7 [8331F–AVR–04/2013] */ 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. - */ + /* Clear TCE0 interrupt flags for Capture Channel B - From 14.12.10 [8331F–AVR–04/2013] */ + CODEC_TIMER_LOADMOD.INTFLAGS = TC0_CCBIF_bm; + /* Set the BUFFERED PERIOD to Bitrate - 1 (because PERBUF is 0-based). + * The current PERIOD was set in StartISO15693Demod to ISO15693_T1_TIME, once ISO15693_T1_TIME is reached, this will be the new PERIOD. + * From 3.7 [8045A-AVR-02/08] */ CODEC_TIMER_LOADMOD.PERBUF = BitRate1 - 1; +} +/* Disable data demodulation interrupt and inform the codec to restart demodulation from scratch */ +INLINE void ISO15693_GARBAGE(void) { Flags.DemodFinished = 1; - /* Sets timer off for CODEC_TIMER_SAMPLING (TCD0) disabling clock source */ + + /* Sets timer off for TCD0, disabling clock source. We have demodulated rubbish and don't need to probe the antenna anymore - From 14.12.1 [8331F–AVR–04/2013] */ CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; - /* Sets register INTCTRLB to 0 to disable all compare/capture interrupts */ - CODEC_TIMER_SAMPLING.INTCTRLB = 0; + /* Disable event action for CODEC_TIMER_SAMPLING (TCD0) - From 14.12.4 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; + /* Disable compare/capture interrupts on Channel C - From 14.12.7 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + /* Clear Compare Channel C (CCC) interrupt Flags - From 14.12.10 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; } /* This function is registered to CODEC_TIMER_SAMPLING (TCD0)'s Counter Channel C (CCC). @@ -142,10 +172,9 @@ INLINE void ISO15693_EOC(void) { * * 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 + * It disables its own interrupt when an EOF is found (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) { +ISR_SHARED 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); @@ -161,11 +190,7 @@ void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) { 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; + ISO15693_GARBAGE(); } break; @@ -248,7 +273,6 @@ void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) { 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 * @@ -256,9 +280,9 @@ void isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT(void) { * * It disables its own interrupt when all data has been sent */ -//ISR(CODEC_TIMER_LOADMOD_CCB_VECT) -void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { +ISR_SHARED isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { static void *JumpTable[] = { + [LOADMOD_WAIT] = && LOADMOD_WAIT_LABEL, [LOADMOD_START_SINGLE] = && LOADMOD_START_SINGLE_LABEL, [LOADMOD_SOF_SINGLE] = && LOADMOD_SOF_SINGLE_LABEL, [LOADMOD_BIT0_SINGLE] = && LOADMOD_BIT0_SINGLE_LABEL, @@ -272,11 +296,11 @@ void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { [LOADMOD_FINISHED] = && LOADMOD_FINISHED_LABEL }; - if ((StateRegister >= LOADMOD_START_SINGLE) && (StateRegister <= LOADMOD_FINISHED)) { - goto *JumpTable[StateRegister]; - } else { - return; - } + goto *JumpTable[StateRegister]; /* It takes 28 clock cycles to get here from function entry point */ + +LOADMOD_WAIT_LABEL: + /* ISO t1 is over, but application is not done generating data yet */ + return; LOADMOD_START_SINGLE_LABEL: /* Application produced data. With this interrupt we are aligned to the bit-grid. */ @@ -354,9 +378,7 @@ void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { if ((BitSent % 8) == 0) { /* Last bit has been put out */ StateRegister = LOADMOD_FINISHED; - } else { - StateRegister = LOADMOD_EOF_SINGLE; - } + } /* else: stay in this state. No changes needed */ return; // ------------------------------------------------------------- @@ -444,22 +466,20 @@ void isr_ISO15693_CODEC_TIMER_LOADMOD_CCB_VECT(void) { if ((BitSent % 8) == 0) { /* Last bit has been put out */ StateRegister = LOADMOD_FINISHED; - } else { - StateRegister = LOADMOD_EOF_DUAL; - } + } /* else: stay in this state. No changes needed */ 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; + /* Disable compare/capture for all level interrupts on channel B for TCE0 - From 14.12.7 [8331F–AVR–04/2013] */ + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_OFF_gc; CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, 0); Flags.LoadmodFinished = 1; return; } -/* This functions resets all global variables used in the codec and enables interrupts to wait for reader data */ +/* Reset global variables/interrupts to demodulate incoming reader data via ISRs */ void StartISO15693Demod(void) { /* Reset global variables to default values */ CodecBufferPtr = CodecBuffer; @@ -475,69 +495,85 @@ void StartISO15693Demod(void) { 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? + /* Set clock source for TCD0 to ISO15693_SAMPLE_CLK = TC_CLKSEL_DIV2_gc = System Clock / 2. + * Since the Chameleon is clocked at 13.56*2 MHz (see Makefile), this counter will hit at the same frequency of reader field. + * From 14.12.1 [8331F–AVR–04/2013] */ 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? + /* Set up TCD0 action/source: + * - Event Action: Restart waveform period (reset PER register) + * - Event Source Select: trigger on CODEC_TIMER_MODSTART_EVSEL = TC_EVSEL_CH0_gc = Event Channel 0 + * From 14.12.4 [8331F–AVR–04/2013] */ - CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_RESTART_gc | CODEC_TIMER_MODSTART_EVSEL; + /* Resets the sampling counter (TCD0) to 0 - From 14.12.12 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.CNT = 0; - /* Set event action for CODEC_TIMER_LOADMOD (TCE0) to restart and trigger CODEC_TIMER_MODSTART_EVSEL = TC_EVSEL_CH0_gc = Event Channel 0 */ + /* Set Clock Source for TCE0 to CODEC_TIMER_CARRIER_CLKSEL = TC_CLKSEL_EVCH6_gc = Event Channel 6 */ + CODEC_TIMER_LOADMOD.CTRLA = CODEC_TIMER_CARRIER_CLKSEL; + /* Set up TCE0 action/source: + * - Event Action: Restart waveform period (reset PER register) + * - Event Source Select: trigger on CODEC_TIMER_MODSTART_EVSEL = TC_EVSEL_CH0_gc = Event Channel 0 + * From 14.12.4 [8331F–AVR–04/2013] + */ 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? + /* Temporarily disable compare/capture for all level interrupts on channel B for TCE0. They'll be enabled later when load modulation will be needed. + * From 14.12.7 [8331F–AVR–04/2013] */ + CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_OFF_gc; + /* Set the period for CODEC_TIMER_LOADMOD (TCE0) ISO standard t1 time. + * Once this timer is enabled, it will wait for a time equal to t1 and then its ISR will be called. + * From 14.12.18 [8331F–AVR–04/2013] */ - 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; + CODEC_TIMER_LOADMOD.PER = ISO15693_T1_TIME; /* 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 */ + /* Clear PORTB interrupt flags - From 13.13.13 [8331F–AVR–04/2013] */ + CODEC_DEMOD_IN_PORT.INTFLAGS = PORT_INT0IF_bm; + /* Use PIN1 as a source for modulation pauses. Will trigger PORTB Interrput 0 - From 13.13.11 [8331F–AVR–04/2013] */ CODEC_DEMOD_IN_PORT.INT0MASK = CODEC_DEMOD_IN_MASK0; } +/* Configure unvarying interrupts settings. + * All configured interrupts will still be disabled once this function is done, they'll be enabled one by one as the communication flow requires them. + */ void ISO15693CodecInit(void) { CodecInitCommon(); - /* Register isr_ISO15693_CODEC_TIMER_SAMPLING_CCC_VECT function - * to CODEC_TIMER_SAMPLING (TCD0)'s Counter Channel C (CCC) - */ + /************************************************** + * Register function handlers to shared ISR * + **************************************************/ + /* 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 - */ + /* 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) - */ + /* 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; + /************************************************** + * Configure demod interrupt * + **************************************************/ + /* Configure sampling-timer free running and sync to first modulation-pause */ + /* Set the period for TCD0 to ISO15693_SAMPLE_PERIOD - 1 because PER is 0-based - From 14.12.14 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.PER = ISO15693_SAMPLE_PERIOD - 1; + /* Set Compare Channel C (CCC) period to half bit period - 1. (- 14 to compensate ISR timing overhead) - From 14.12.16 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.CCC = ISO15693_SAMPLE_PERIOD / 2 - 14 - 1; + /* Temporarily disable Compare Channel C (CCC) interrupts. + * They'll be enabled later in isr_ISO15693_CODEC_DEMOD_IN_INT0_VECT once we sensed the reader is sending data and we're in sync with the pulses. + * From 14.12.7 [8331F–AVR–04/2013] + */ + CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; + /* Clear Compare Channel C (CCC) interrupt Flags - From 14.12.10 [8331F–AVR–04/2013] */ + CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; + + /************************************************** + * Configure loadmod interrupt * + **************************************************/ + /* Disable timer error and overflow interrupts - From 14.12.6 [8331F–AVR–04/2013] */ + CODEC_TIMER_LOADMOD.INTCTRLA = 0; + + /* Activate Power for demodulator */ + CodecSetDemodPower(true); + StartISO15693Demod(); } @@ -560,21 +596,21 @@ void ISO15693CodecDeInit(void) { ShiftRegister = 0; /* Disable sample timer */ - /* Sets timer off for CODEC_TIMER_SAMPLING (TCD0) disabling clock source */ + /* Sets timer off for TCD0, disabling clock source - From 14.12.1 [8331F–AVR–04/2013] */ CODEC_TIMER_SAMPLING.CTRLA = TC_CLKSEL_OFF_gc; - /* Disable event action for CODEC_TIMER_SAMPLING (TCD0) */ + /* Disable event action for CODEC_TIMER_SAMPLING (TCD0) - From 14.12.4 [8331F–AVR–04/2013] */ CODEC_TIMER_SAMPLING.CTRLD = TC_EVACT_OFF_gc; - /* Sets register INTCTRLB to TC_CCCINTLVL_OFF_gc = (0x00<<4) to disable compare/capture C interrupts */ + /* Disable Compare Channel C (CCC) interrupts - From 14.12.7 [8331F–AVR–04/2013] */ CODEC_TIMER_SAMPLING.INTCTRLB = TC_CCCINTLVL_OFF_gc; - /* Restore Counter Channel C (CCC) interrupt mask (TC0_CCCIF_bm) */ + /* Clear Compare Channel C (CCC) interrupt Flags - From 14.12.10 [8331F–AVR–04/2013] */ CODEC_TIMER_SAMPLING.INTFLAGS = TC0_CCCIF_bm; /* Disable load modulation */ - /* Disable event action for CODEC_TIMER_LOADMOD (TCE0) */ + /* Disable the event action for TCE0 - From 14.12.4 [8331F–AVR–04/2013] */ CODEC_TIMER_LOADMOD.CTRLD = TC_EVACT_OFF_gc; - /* Sets register INTCTRLB to TC_CCBINTLVL_OFF_gc = (0x00<<2) to disable compare/capture B interrupts */ + /* Disable compare/capture for all level interrupts on channel B for TCE0 - From 14.12.7 [8331F–AVR–04/2013] */ CODEC_TIMER_LOADMOD.INTCTRLB = TC_CCBINTLVL_OFF_gc; - /* Restore Counter Channel B (CCB) interrupt mask (TC0_CCBIF_bm) */ + /* Clear TCE0 interrupt flags for Capture Channel B - From 14.12.10 [8331F–AVR–04/2013] */ CODEC_TIMER_LOADMOD.INTFLAGS = TC0_CCBIF_bm; CodecSetSubcarrier(CODEC_SUBCARRIERMOD_OFF, 0); @@ -594,7 +630,7 @@ void ISO15693CodecTask(void) { LogEntry(LOG_INFO_CODEC_RX_DATA, CodecBuffer, DemodByteCount); LEDHook(LED_CODEC_RX, LED_PULSE); - if (CodecBuffer[0] & ISO15693_REQ_SUBCARRIER_DUAL) { + if (CodecBuffer[0] & REQ_SUBCARRIER_DUAL) { bDualSubcarrier = true; } AppReceivedByteCount = ApplicationProcess(CodecBuffer, DemodByteCount); @@ -602,7 +638,13 @@ void ISO15693CodecTask(void) { /* 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); + if (AppReceivedByteCount > CODEC_BUFFER_SIZE - ISO15693_CRC16_SIZE) { /* CRC would be written outside codec buffer */ + CodecBuffer[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + CodecBuffer[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; + AppReceivedByteCount = 2; + LogEntry(LOG_INFO_GENERIC, "Too much data requested - See PR #274", 38); + } + LEDHook(LED_CODEC_TX, LED_PULSE); ByteCount = AppReceivedByteCount; @@ -617,13 +659,21 @@ void ISO15693CodecTask(void) { 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; + /* Calculate the CRC while modulation is already ongoing */ + ISO15693AppendCRC(CodecBuffer, AppReceivedByteCount); + ByteCount += ISO15693_CRC16_SIZE; /* Increase this variable as it will be read by the codec during loadmodulation */ + LogEntry(LOG_INFO_CODEC_TX_DATA, CodecBuffer, AppReceivedByteCount + ISO15693_CRC16_SIZE); + } else { + /* Overwrite the PERBUF register, which was configured in ISO15693_EOC, with the new appropriate value. + * This is expecially needed because, since load modulation has not been performed, we're jumping here straight after + * ISO15693_EOC. This implies that the data stored in the PERBUF register by ISO15693_EOC still has to be copied + * in the PER register and that will happen on the next UPDATE event. + * The next UPDATE event will be timer/counter enablement in ISO15693_EOC, which is executed after StartISO15693Demod, + * effectively overwriting PER with an incorrect value. + * See 8045A-AVR-02/08 section 3.7 for information about buffered registers. + */ + CODEC_TIMER_LOADMOD.PERBUF = ISO15693_T1_TIME; StartISO15693Demod(); } } diff --git a/Firmware/Chameleon-Mini/Codec/ISO15693.h b/Firmware/Chameleon-Mini/Codec/ISO15693.h index 6c2e01b0..0362fdcc 100644 --- a/Firmware/Chameleon-Mini/Codec/ISO15693.h +++ b/Firmware/Chameleon-Mini/Codec/ISO15693.h @@ -8,26 +8,8 @@ #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); @@ -37,6 +19,4 @@ void ISO15693CodecTask(void); 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 d88de718..5eadf5a2 100644 --- a/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/Reader14443-2A.c @@ -172,13 +172,10 @@ INLINE void BufferToSequence(void) { if (BitCount % 8) CodecBuffer[BitCount / 8] = SampleRegister >> (8 - (BitCount % 8)); } -// 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) { +// Frame Delay Time PCD to PICC ends +ISR_SHARED 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 801a610f..0fb11287 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.c @@ -56,6 +56,8 @@ static volatile uint16_t ReaderBitCount; static volatile uint16_t CardBitCount; static volatile uint16_t rawBitCount; +enum RCTraffic TrafficSource; + INLINE void CardSniffInit(void); INLINE void CardSniffDeinit(void); @@ -354,16 +356,13 @@ ISR(ACA_AC0_vect) { // this interrupt either finds the SOC or gets triggered bef StateRegister = PICC_FRAME; } -ISR(CODEC_TIMER_LOADMOD_CCB_VECT) { // pause found - isr_func_CODEC_TIMER_LOADMOD_CCB_VECT(); -} - +// Called once a pause is found // Decode the Card -> Reader signal // according to the pause and modulated period // if the half bit duration is modulated, then add 1 to buffer // if the half bit duration is not modulated, then add 0 to buffer //ISR(CODEC_TIMER_LOADMOD_CCB_VECT) // pause found -void isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void) { +ISR_SHARED isr_SniffISO14443_2A_CODEC_TIMER_LOADMOD_CCB_VECT(void) { uint8_t tmp = CODEC_TIMER_TIMESTAMPS.CNTL; CODEC_TIMER_TIMESTAMPS.CNT = 0; diff --git a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h index 0e22d464..b8616b0c 100644 --- a/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h +++ b/Firmware/Chameleon-Mini/Codec/SniffISO14443-2A.h @@ -9,7 +9,7 @@ #include "Codec.h" #include "Terminal/CommandLine.h" -enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource; +extern enum RCTraffic {TRAFFIC_READER, TRAFFIC_CARD} TrafficSource; /* Codec Interface */ void Sniff14443ACodecInit(void); void Sniff14443ACodecDeInit(void); diff --git a/Firmware/Chameleon-Mini/Common.h b/Firmware/Chameleon-Mini/Common.h index 658082ef..20c66033 100644 --- a/Firmware/Chameleon-Mini/Common.h +++ b/Firmware/Chameleon-Mini/Common.h @@ -17,6 +17,9 @@ #define ODD_PARITY(Value) OddParityBit(Value)//(parity_even_bit(Value) ? 0 : 1) +#define ISR_SHARED \ + void __attribute__((signal)) // This function type has to be used for all the interrupt handlers that have to be changed at runtime + #define INLINE \ static inline __attribute__((always_inline)) diff --git a/Firmware/Chameleon-Mini/ISRSharing.S b/Firmware/Chameleon-Mini/ISRSharing.S new file mode 100644 index 00000000..7bf3dfc3 --- /dev/null +++ b/Firmware/Chameleon-Mini/ISRSharing.S @@ -0,0 +1,49 @@ +; This file allows to share ISR at runtime with a low overhead. +; Functions that have to be shared MUST be defined as ISR_SHARED types +; (Defined in Common.h) to instruct GCC to compile them preserving the stack +; +; Created on: 2019-12-06 +; Author: ceres-c +; + +#include "Codec/Codec.h" +#include + +; Macro to call ISR functions +; For development purposes: cycles penality before landing in the Shared ISR is 10 +.macro call_isr isr_address +push r30 ; 1 +push r31 ; 1 +lds r30, \isr_address ; 3 +lds r31, \isr_address+1 ; 3 +icall ; 2 (16 bit PC) +pop r31 +pop r30 +reti +.endm + +; Shared ISR must be defined below as globals +; Example: +; +; .global +; INTERRUPT-TO-SHARE: +; call_isr POINTER-TO-VARIABLE-INTERRUPT-HANDLER +; +; Where: +; INTERRUPT-TO-SHARE +; The target interrupt which needs to be shared +; POINTER-TO-VARIABLE-INTERRUPT-HANDLER +; A pointer to the interrupt handler which can be modified at runtime. +; Must be a volatile pointer to function declared in Codec.h + +.global CODEC_DEMOD_IN_INT0_VECT +CODEC_DEMOD_IN_INT0_VECT: + call_isr isr_func_CODEC_DEMOD_IN_INT0_VECT + +.global CODEC_TIMER_SAMPLING_CCC_VECT +CODEC_TIMER_SAMPLING_CCC_VECT: + call_isr isr_func_TCD0_CCC_vect + +.global CODEC_TIMER_LOADMOD_CCB_VECT +CODEC_TIMER_LOADMOD_CCB_VECT: + call_isr isr_func_CODEC_TIMER_LOADMOD_CCB_VECT \ No newline at end of file diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index b680af4c..f67fa3be 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -108,7 +108,7 @@ F_CPU = 27120000 F_USB = 48000000 TARGET = Chameleon-RevG OPTIMIZATION = s -SRC += Chameleon-Mini.c LUFADescriptors.c System.c Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c Uart.c uartcmd.c +SRC += Chameleon-Mini.c LUFADescriptors.c System.c ISRSharing.S Configuration.c Random.c Common.c Memory.c MemoryAsm.S Button.c Log.c Settings.c LED.c Map.c AntennaLevel.c Uart.c uartcmd.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 Application/CryptoTDEA.S diff --git a/Firmware/Chameleon-Mini/System.c b/Firmware/Chameleon-Mini/System.c index a2b33ca0..30899dd3 100644 --- a/Firmware/Chameleon-Mini/System.c +++ b/Firmware/Chameleon-Mini/System.c @@ -151,4 +151,3 @@ void SystemInterruptInit(void) { PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; sei(); } - diff --git a/Firmware/Chameleon-Mini/Terminal/CommandLine.c b/Firmware/Chameleon-Mini/Terminal/CommandLine.c index 1f1e4d5d..859c5859 100644 --- a/Firmware/Chameleon-Mini/Terminal/CommandLine.c +++ b/Firmware/Chameleon-Mini/Terminal/CommandLine.c @@ -274,6 +274,13 @@ const PROGMEM CommandEntryType CommandTable[] = { .SetFunc = NO_FUNCTION, .GetFunc = NO_FUNCTION }, + { + .Command = COMMAND_CLONE_MFU, + .ExecFunc = CommandExecCloneMFU, + .ExecParamFunc = NO_FUNCTION, + .SetFunc = NO_FUNCTION, + .GetFunc = NO_FUNCTION + }, { .Command = COMMAND_IDENTIFY_CARD, .ExecFunc = CommandExecIdentifyCard, diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.c b/Firmware/Chameleon-Mini/Terminal/Commands.c index 002788b7..e16704e9 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.c +++ b/Firmware/Chameleon-Mini/Terminal/Commands.c @@ -16,6 +16,7 @@ #include "../Battery.h" #include "../Codec/Codec.h" #include "uartcmd.h" +#include "../Application/Reader14443A.h" extern Reader14443Command Reader14443CurrentCommand; extern Sniff14443Command Sniff14443CurrentCommand; @@ -491,6 +492,17 @@ CommandStatusIdType CommandExecDumpMFU(char *OutMessage) { return TIMEOUT_COMMAND; } +CommandStatusIdType CommandExecCloneMFU(char *OutMessage) { + ConfigurationSetById(CONFIG_ISO14443A_READER); + ApplicationReset(); + + Reader14443CurrentCommand = Reader14443_Clone_MF_Ultralight; + Reader14443AAppInit(); + Reader14443ACodecStart(); + CommandLinePendingTaskTimeout = &Reader14443AAppTimeout; + return TIMEOUT_COMMAND; +} + CommandStatusIdType CommandExecGetUid(char *OutMessage) { // this function is for reading the uid in reader mode if (GlobalSettings.ActiveSettingPtr->Configuration != CONFIG_ISO14443A_READER) return COMMAND_ERR_INVALID_USAGE_ID; diff --git a/Firmware/Chameleon-Mini/Terminal/Commands.h b/Firmware/Chameleon-Mini/Terminal/Commands.h index f4eebe02..ed1c1400 100644 --- a/Firmware/Chameleon-Mini/Terminal/Commands.h +++ b/Firmware/Chameleon-Mini/Terminal/Commands.h @@ -166,6 +166,9 @@ CommandStatusIdType CommandExecGetUid(char *OutMessage); #define COMMAND_DUMP_MFU "DUMP_MFU" CommandStatusIdType CommandExecDumpMFU(char *OutMessage); +#define COMMAND_CLONE_MFU "CLONE_MFU" +CommandStatusIdType CommandExecCloneMFU(char *OutMessage); + #define COMMAND_IDENTIFY_CARD "IDENTIFY" CommandStatusIdType CommandExecIdentifyCard(char *OutMessage);