diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index 6fca8b6..af0dd2a 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -20,7 +20,7 @@ #include "Sl2s2002.h" #include "TITagitstandard.h" #include "Sniff14443A.h" - +#include "EM4233.h" /* Function wrappers */ INLINE void ApplicationInit(void) { diff --git a/Firmware/Chameleon-Mini/Application/EM4233.c b/Firmware/Chameleon-Mini/Application/EM4233.c new file mode 100644 index 0000000..a2fb430 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/EM4233.c @@ -0,0 +1,241 @@ +/* + * EM4233.c + * + * Created on: 12-05-2018 + * Author: ceres-c & MrMoDDoM + */ + +#include "ISO15693-A.h" +#include "EM4233.h" + +static enum { + STATE_READY, + STATE_SELECTED, + STATE_QUIET +} State; + +CurrentFrame FrameInfo; + +uint64_t EM4233_FactoryLockBits_Mask = 0; /* Holds lock state of blocks */ +uint64_t EM4233_UserLockBits_Mask = 0; /* Holds lock state of blocks */ + +//uint8_t EM4233_Lock_Status[64] = { 1 }; + + +void EM4233AppInit(void) +{ + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + + //MemoryReadBlock(EM4233_Lock_Status, EM4233_MEM_LSM_ADDRESS, 64); + //MemoryReadBlock(&EM4233_FactoryLockBits_Mask, EM4233_MEM_FLM_ADDRESS, 8); +} + +void EM4233AppReset(void) +{ + State = STATE_READY; + + FrameInfo.Flags = NULL; + FrameInfo.Command = NULL; + FrameInfo.Parameters = NULL; + FrameInfo.ParamLen = 0; + FrameInfo.Addressed = false; + + //MemoryReadBlock(&EM4233_UserLockBits_Mask, EM4233_MEM_ULM_ADDRESS, 8); + //MemoryReadBlock(&EM4233_FactoryLockBits_Mask, EM4233_MEM_FLM_ADDRESS, 8); +} + + +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 PageAddress = *FrameInfo.Parameters; + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (PageAddress > EM4233_NUMBER_OF_BLCKS) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = 2; + return ResponseByteCount; /* malformed: trying to lock a non-existing block */ + } + + if ((EM4233_FactoryLockBits_Mask & (uint64_t)(1 << PageAddress)) || (EM4233_UserLockBits_Mask & (uint64_t)(1 << PageAddress))) { /* if already locked */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_BLK_ALRD_LKD; + ResponseByteCount = 2; + } else { + EM4233_UserLockBits_Mask |= (uint64_t)(1 << PageAddress); /* write the lock status in mask */ + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_NO_ERROR; + ResponseByteCount = 1; + } + + return ResponseByteCount; +} + +uint16_t EM4233_Write_Single(uint8_t* FrameBuf, uint16_t FrameBytes) +{ + uint16_t ResponseByteCount = ISO15693_APP_NO_RESPONSE; + uint8_t* Dataptr; + uint8_t PageAddress = *FrameInfo.Parameters; + + if (FrameInfo.ParamLen != 5) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (PageAddress > EM4233_NUMBER_OF_BLCKS) { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_OPT_NOT_SUPP; + ResponseByteCount = 2; /* malformed: trying to write in a non-existing block */ + return ResponseByteCount; + } + + Dataptr = PageAddress + 0x01; + + if (EM4233_FactoryLockBits_Mask & (uint64_t)(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 (EM4233_UserLockBits_Mask & (uint64_t)(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 * 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 PageAddress = *FrameInfo.Parameters; + uint8_t LockStatus = 0; + + if (FrameInfo.ParamLen != 1) + return ISO15693_APP_NO_RESPONSE; /* malformed: not enough or too much data */ + + if (PageAddress >= EM4233_NUMBER_OF_BLCKS) { /* 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; + return ResponseByteCount; + } + + if (FrameBuf[ISO15693_ADDR_FLAGS] & ISO15693_REQ_FLAG_OPTION) { /* request with option flag set */ + MemoryReadBlock(&LockStatus, (EM4233_MEM_LSM_ADDRESS + PageAddress), 1); + if (LockStatus & ISO15693_MASK_FACTORY_LOCK) { /* 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 (LockStatus & ISO15693_MASK_USER_LOCK) { /* 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 * EM4233_BYTES_PER_BLCK, EM4233_BYTES_PER_BLCK); + + 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 (!ISO15693PrepareFrame(FrameBuf, FrameBytes, &FrameInfo, Uid)) + 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) { + 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 { + FrameBuf[ISO15693_ADDR_FLAGS] = ISO15693_RES_FLAG_ERROR; + FrameBuf[ISO15693_RES_ADDR_PARAM] = ISO15693_RES_ERR_NOT_SUPP; + ResponseByteCount = 2; + } + break; + + case STATE_SELECTED: + /* TO-DO */ + break; + + case STATE_QUIET: + if (*FrameInfo.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; + } + + break; + + default: + break; + } + + if (ResponseByteCount > 0) { + /* There is data to be sent. 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..9e75160 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/EM4233.h @@ -0,0 +1,60 @@ +/* + * 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 256 // Bytes +#define EM4233_BYTES_PER_BLCK 4 +#define EM4233_BLCKS_PER_PAGE 4 +#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_USR_MEM_SIZE 64 // Bytes, guessed, not described anywere +#define EM4233_MEM_UID_ADDRESS 0x0100 // From 0x0100 to 0x0107 - UID +#define EM4233_MEM_LSM_ADDRESS 0x0108 // From 0x0108 to 0x014F - Lock status masks +#define EM4233_MEM_PSW_ADDRESS 0x0150 // From 0x0118 to 0x011F - Password +#define EM4233_MEM_KEY_ADDRESS 0x0120 // From 0x0120 to 0x0127 - Encryption Key + +#define EM4233_MASK_READ_PROT ( 1 << 2 ) // For lock status byte +#define EM4233_MASK_WRITE_PROT ( 1 << 3 ) + +#define EM4233_TOT_MEM_SIZE ( EM4233_STD_MEM_SIZE + EM4233_USR_MEM_SIZE ) + +/* 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_LOGIN 0xE4 + + +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.h b/Firmware/Chameleon-Mini/Application/ISO15693-A.h index 936dbe4..72e0d9f 100644 --- a/Firmware/Chameleon-Mini/Application/ISO15693-A.h +++ b/Firmware/Chameleon-Mini/Application/ISO15693-A.h @@ -68,10 +68,17 @@ #define ISO15693_GENERIC_UID_SIZE 0x08 #define ISO15693_GENERIC_MEM_SIZE 8192 -#define ISO15693_CRC16_SIZE 2 /* Bytes */ +#define ISO15693_CRC16_SIZE 0x2 /* Bytes */ #define ISO15693_CRC16_POLYNORMAL 0x8408 #define ISO15693_CRC16_PRESET 0xFFFF +/* + * The byte used for the lock status has its bits addressed as follow: + * + */ +#define ISO15693_MASK_FACTORY_LOCK ( 1 << 0 ) +#define ISO15693_MASK_USER_LOCK ( 1 << 1 ) + typedef struct { uint8_t* Flags; uint8_t* Command; diff --git a/Firmware/Chameleon-Mini/Application/TITagitstandard.c b/Firmware/Chameleon-Mini/Application/TITagitstandard.c index f5618f5..80ae1a2 100644 --- a/Firmware/Chameleon-Mini/Application/TITagitstandard.c +++ b/Firmware/Chameleon-Mini/Application/TITagitstandard.c @@ -114,10 +114,12 @@ uint16_t TITagitstandardAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) if (FrameInfo.ParamLen != 5) break; /* malformed: not enough or too much data */ - if (PageAddress > TITAGIT_NUMBER_OF_SECTORS) + 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; @@ -141,11 +143,12 @@ uint16_t TITagitstandardAppProcess(uint8_t* FrameBuf, uint16_t FrameBytes) if (FrameInfo.ParamLen != 1) break; /* malformed: not enough or too much data */ - if (PageAddress > TITAGIT_NUMBER_OF_SECTORS) + 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; diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index 2731cfc..35b0de5 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -46,10 +46,12 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { #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 */ @@ -297,7 +299,6 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .TagFamily = TAG_FAMILY_ISO15693 }, #endif - #ifdef CONFIG_TITAGITSTANDARD_SUPPORT [CONFIG_TITAGITSTANDARD] = { .CodecInitFunc = ISO15693CodecInit, @@ -316,6 +317,24 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .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 }; ConfigurationType ActiveConfiguration; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 7f8b91a..9d53936 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -54,6 +54,9 @@ typedef enum { #endif #ifdef CONFIG_TITAGITSTANDARD_SUPPORT CONFIG_TITAGITSTANDARD, +#endif +#ifdef CONFIG_EM4233_SUPPORT + CONFIG_EM4233, #endif /* This HAS to be the last element */ CONFIG_COUNT 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 441e7a9..5e61f05 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -16,6 +16,7 @@ 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 @@ -99,7 +100,7 @@ SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Termina SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c SRC += Codec/ISO15693.c -SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/ISO15693-A.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)