diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4d6b6a0d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +.DS_Store +*.pyc diff --git a/Firmware/Chameleon-Mini/Application/Application.h b/Firmware/Chameleon-Mini/Application/Application.h index 92639945..5f6fbf33 100644 --- a/Firmware/Chameleon-Mini/Application/Application.h +++ b/Firmware/Chameleon-Mini/Application/Application.h @@ -21,6 +21,7 @@ #include "TITagitstandard.h" #include "Sniff14443A.h" #include "EM4233.h" +#include "NTAG215.h" /* Function wrappers */ INLINE void ApplicationInit(void) { diff --git a/Firmware/Chameleon-Mini/Application/NTAG215.c b/Firmware/Chameleon-Mini/Application/NTAG215.c new file mode 100644 index 00000000..c7bb0e1b --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/NTAG215.c @@ -0,0 +1,438 @@ +/* + * NTAG215.c + * + * Created on: 20.02.2019 + * Author: Giovanni Cammisa (gcammisa) + * Still missing support for: + * - The management of both static and dynamic lock bytes + * - Bruteforce protection (AUTHLIM COUNTER) + * Thanks to skuser for the MifareUltralight code used as a starting point + */ + +#include "ISO14443-3A.h" +#include "../Codec/ISO14443-2A.h" +#include "../Memory.h" +#include "NTAG215.h" + +// DEFINE ATQA and SAK +#define ATQA_VALUE 0x0044 +#define SAK_VALUE 0x00 + +#define SAK_CL1_VALUE ISO14443A_SAK_INCOMPLETE +#define SAK_CL2_VALUE ISO14443A_SAK_COMPLETE_NOT_COMPLIANT + +// ACK and NACK +#define ACK_VALUE 0x0A +#define ACK_FRAME_SIZE 4 /* Bits */ +#define NAK_INVALID_ARG 0x00 +#define NAK_CRC_ERROR 0x01 +#define NAK_NOT_AUTHED 0x04 +#define NAK_EEPROM_ERROR 0x05 +#define NAK_FRAME_SIZE 4 + +// DEFINING COMMANDS +/* ISO commands */ +#define CMD_HALT 0x50 +// NTAG COMMANDS +#define CMD_GET_VERSION 0x60 +#define CMD_READ 0x30 +#define CMD_FAST_READ 0x3A +#define CMD_WRITE 0xA2 +#define CMD_COMPAT_WRITE 0xA0 +#define CMD_READ_CNT 0x39 +#define CMD_PWD_AUTH 0x1B +#define CMD_READ_SIG 0x3C + +// MEMORY LAYOUT STUFF, addresses and sizes in bytes +// UID stuff +#define UID_CL1_ADDRESS 0x00 +#define UID_CL1_SIZE 3 +#define UID_BCC1_ADDRESS 0x03 +#define UID_CL2_ADDRESS 0x04 +#define UID_CL2_SIZE 4 +#define UID_BCC2_ADDRESS 0x08 +// LockBytes stuff +#define STATIC_LOCKBYTE_0_ADDRESS 0x0A +#define STATIC_LOCKBYTE_1_ADDRESS 0x0B +// CONFIG stuff +#define CONFIG_AREA_START_ADDRESS NTAG215_PAGE_SIZE * 0x83 +#define CONFIG_AREA_SIZE 8 +// CONFIG offsets, relative to config start address +#define CONF_AUTH0_OFFSET 0x03 +#define CONF_ACCESS_OFFSET 0x04 +#define CONF_PASSWORD_OFFSET 0x08 +#define CONF_PACK_OFFSET 0x0C + +// WRITE STUFF +#define BYTES_PER_WRITE 4 +#define PAGE_WRITE_MIN 0x02 + +// CONFIG masks to check individual needed bits +#define CONF_ACCESS_PROT 0x80 + +#define VERSION_INFO_LENGTH 8 //8 bytes info lenght + crc + +#define BYTES_PER_READ NTAG215_PAGE_SIZE * 4 + +// SIGNATURE Lenght +#define SIGNATURE_LENGTH 32 + + +static enum { + STATE_HALT, + STATE_IDLE, + STATE_READY1, + STATE_READY2, + STATE_ACTIVE +} State; + +static bool FromHalt = false; +static uint8_t PageCount; +static bool ArmedForCompatWrite; +static uint8_t CompatWritePageAddress; +static bool Authenticated; +static uint8_t FirstAuthenticatedPage; +static bool ReadAccessProtected; +static uint8_t Access; + + +void NTAG215AppInit(void) +{ + + State = STATE_IDLE; + FromHalt = false; + ArmedForCompatWrite = false; + Authenticated = false; + PageCount = NTAG215_PAGES; + + /* Fetch some of the configuration into RAM */ + MemoryReadBlock(&FirstAuthenticatedPage, CONFIG_AREA_START_ADDRESS + CONF_AUTH0_OFFSET, 1); + MemoryReadBlock(&Access, CONFIG_AREA_START_ADDRESS + CONF_ACCESS_OFFSET, 1); + ReadAccessProtected = !!(Access & CONF_ACCESS_PROT); +} + +void NTAG215AppReset(void) +{ + State = STATE_IDLE; +} + +void NTAG215AppTask(void) +{ + +} + +// Verify authentication +static bool VerifyAuthentication(uint8_t PageAddress) +{ + /* If authenticated, no verification needed */ + if (Authenticated) { + return true; + } + /* Otherwise, verify the accessed page is below the limit */ + return PageAddress < FirstAuthenticatedPage; +} + +// Writes a page +static uint8_t AppWritePage(uint8_t PageAddress, uint8_t* const Buffer) +{ + if (!ActiveConfiguration.ReadOnly) { + MemoryWriteBlock(Buffer, PageAddress * NTAG215_PAGE_SIZE, NTAG215_PAGE_SIZE); + } else { + /* If the chameleon is in read only mode, it silently + * ignores any attempt to write data. */ + } + return 0; +} + +// Basic sketch of the command handling stuff +static uint16_t AppProcess(uint8_t* const Buffer, uint16_t ByteCount) +{ + uint8_t Cmd = Buffer[0]; + + /* Handle the compatibility write command */ + if (ArmedForCompatWrite) { + ArmedForCompatWrite = false; + + AppWritePage(CompatWritePageAddress, &Buffer[2]); + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } + + switch (Cmd) { + case CMD_GET_VERSION: { + /* Provide hardcoded version response */ //VERSION RESPONSE FOR NTAG 215 + Buffer[0] = 0x00; + Buffer[1] = 0x04; + Buffer[2] = 0x04; + Buffer[3] = 0x02; + Buffer[4] = 0x01; + Buffer[5] = 0x00; + Buffer[6] = 0x11; + Buffer[7] = 0x03; + ISO14443AAppendCRCA(Buffer, VERSION_INFO_LENGTH); + return (VERSION_INFO_LENGTH + ISO14443A_CRCA_SIZE) * 8; + } + + case CMD_READ: { + uint8_t PageAddress = Buffer[1]; + uint8_t PageLimit; + uint8_t Offset; + + PageLimit = PageCount; + + /* if protected and not autenticated, ensure the wraparound is at the first protected page */ + if (ReadAccessProtected && !Authenticated) { + PageLimit = FirstAuthenticatedPage; + } + else { + PageLimit = PageCount; + } + + /* Validation */ + if (PageAddress >= PageLimit) { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + /* Read out, emulating the wraparound */ + for (Offset = 0; Offset < BYTES_PER_READ; Offset += 4) { + MemoryReadBlock(&Buffer[Offset], PageAddress * NTAG215_PAGE_SIZE, NTAG215_PAGE_SIZE); + PageAddress++; + if (PageAddress == PageLimit) { // if arrived ad the last page, start reading from page 0 + PageAddress = 0; + } + } + ISO14443AAppendCRCA(Buffer, BYTES_PER_READ); + return (BYTES_PER_READ + ISO14443A_CRCA_SIZE) * 8; + } + + case CMD_FAST_READ: { + uint8_t StartPageAddress = Buffer[1]; + uint8_t EndPageAddress = Buffer[2]; + /* Validation */ + if ((StartPageAddress > EndPageAddress) || (StartPageAddress >= PageCount) || (EndPageAddress >= PageCount)) { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + + /* Check authentication only if protection is read&write (instead of only write protection) */ + if (ReadAccessProtected) { + if (!VerifyAuthentication(StartPageAddress) || !VerifyAuthentication(EndPageAddress)) { + Buffer[0] = NAK_NOT_AUTHED; + return NAK_FRAME_SIZE; + } + } + + ByteCount = (EndPageAddress - StartPageAddress + 1) * NTAG215_PAGE_SIZE; + MemoryReadBlock(Buffer, StartPageAddress * NTAG215_PAGE_SIZE, ByteCount); + ISO14443AAppendCRCA(Buffer, ByteCount); + return (ByteCount + ISO14443A_CRCA_SIZE) * 8; + } + + case CMD_PWD_AUTH: { + uint8_t Password[4]; + + /* For now I don't care about bruteforce protection, so: */ + /* TODO: IMPLEMENT COUNTER AUTHLIM */ + + /* Read and compare the password */ + MemoryReadBlock(Password, CONFIG_AREA_START_ADDRESS + CONF_PASSWORD_OFFSET, 4); + if (Password[0] != Buffer[1] || Password[1] != Buffer[2] || Password[2] != Buffer[3] || Password[3] != Buffer[4]) { + Buffer[0] = NAK_NOT_AUTHED; + return NAK_FRAME_SIZE; + } + /* Authenticate the user */ + //RESET AUTHLIM COUNTER, CURRENTLY NOT IMPLEMENTED + Authenticated = 1; + /* Send the PACK value back */ + MemoryReadBlock(Buffer, CONFIG_AREA_START_ADDRESS + CONF_PACK_OFFSET, 2); + ISO14443AAppendCRCA(Buffer, 2); + return (2 + ISO14443A_CRCA_SIZE) * 8; + } + + case CMD_WRITE: { + /* This is a write command containing 4 bytes of data that + * should be written to the given page address. */ + uint8_t PageAddress = Buffer[1]; + /* Validation */ + if ((PageAddress < PAGE_WRITE_MIN) || (PageAddress >= PageCount)) { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + if (!VerifyAuthentication(PageAddress)) { + Buffer[0] = NAK_NOT_AUTHED; + return NAK_FRAME_SIZE; + } + AppWritePage(PageAddress, &Buffer[2]); + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } + + case CMD_COMPAT_WRITE: { + uint8_t PageAddress = Buffer[1]; + /* Validation */ + if ((PageAddress < PAGE_WRITE_MIN) || (PageAddress >= PageCount)) { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + if (!VerifyAuthentication(PageAddress)) { + Buffer[0] = NAK_NOT_AUTHED; + return NAK_FRAME_SIZE; + } + /* CRC check passed and page-address is within bounds. + * Store address and proceed to receiving the data. */ + CompatWritePageAddress = PageAddress; + ArmedForCompatWrite = true; //TODO:IMPLEMENT ARMED COMPAT WRITE + Buffer[0] = ACK_VALUE; + return ACK_FRAME_SIZE; + } + + + case CMD_READ_SIG: { + /* Hardcoded response */ + memset(Buffer, 0xCA, SIGNATURE_LENGTH); + ISO14443AAppendCRCA(Buffer, SIGNATURE_LENGTH); + return (SIGNATURE_LENGTH + ISO14443A_CRCA_SIZE) * 8; + } + + //PART OF ISO STANDARD, NOT OF NTAG DATASHEET + case CMD_HALT: { + /* Halts the tag. According to the ISO14443, the second + * byte is supposed to be 0. */ + if (Buffer[1] == 0) { + /* According to ISO14443, we must not send anything + * in order to acknowledge the HALT command. */ + State = STATE_HALT; + return ISO14443A_APP_NO_RESPONSE; + } else { + Buffer[0] = NAK_INVALID_ARG; + return NAK_FRAME_SIZE; + } + } + + + default: { + break; + } + + } + /* Command not handled. Switch to idle. */ + + State = STATE_IDLE; + return ISO14443A_APP_NO_RESPONSE; + +} + + +// FINITE STATE MACHINE STUFF, SHOULD BE THE VERY SIMILAR TO Mifare Ultralight +uint16_t NTAG215AppProcess(uint8_t* Buffer, uint16_t BitCount) +{ + uint8_t Cmd = Buffer[0]; + uint16_t ByteCount; + + switch(State) { + case STATE_IDLE: + case STATE_HALT: + FromHalt = State == STATE_HALT; + if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) { + /* We received a REQA or WUPA command, so wake up. */ + State = STATE_READY1; + return BitCount; + } + break; + + case STATE_READY1: + if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) { + State = FromHalt ? STATE_HALT : STATE_IDLE; + return ISO14443A_APP_NO_RESPONSE; + } else if (Cmd == ISO14443A_CMD_SELECT_CL1) { + /* Load UID CL1 and perform anticollision. Since + * MF Ultralight use a double-sized UID, the first byte + * of CL1 has to be the cascade-tag byte. */ + uint8_t UidCL1[ISO14443A_CL_UID_SIZE] = { [0] = ISO14443A_UID0_CT }; + + MemoryReadBlock(&UidCL1[1], UID_CL1_ADDRESS, UID_CL1_SIZE); + + if (ISO14443ASelect(Buffer, &BitCount, UidCL1, SAK_CL1_VALUE)) { + /* CL1 stage has ended successfully */ + State = STATE_READY2; + } + + return BitCount; + } else { + /* Unknown command. Enter halt state */ + State = STATE_IDLE; + } + break; + + case STATE_READY2: + if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) { + State = FromHalt ? STATE_HALT : STATE_IDLE; + return ISO14443A_APP_NO_RESPONSE; + } else if (Cmd == ISO14443A_CMD_SELECT_CL2) { + /* Load UID CL2 and perform anticollision */ + uint8_t UidCL2[ISO14443A_CL_UID_SIZE]; + + MemoryReadBlock(UidCL2, UID_CL2_ADDRESS, UID_CL2_SIZE); + + if (ISO14443ASelect(Buffer, &BitCount, UidCL2, SAK_CL2_VALUE)) { + /* CL2 stage has ended successfully. This means + * our complete UID has been sent to the reader. */ + State = STATE_ACTIVE; + } + + return BitCount; + } else { + /* Unknown command. Enter halt state */ + State = STATE_IDLE; + } + break; + + // Only ACTIVE state, no AUTHENTICATED state, PWD_AUTH is handled in commands. + case STATE_ACTIVE: + /* Preserve incoming data length */ + ByteCount = (BitCount + 7) >> 3; + if (ISO14443AWakeUp(Buffer, &BitCount, ATQA_VALUE, FromHalt)) { + State = FromHalt ? STATE_HALT : STATE_IDLE; + return ISO14443A_APP_NO_RESPONSE; + } + /* At the very least, there should be 3 bytes in the buffer. */ + if (ByteCount < (1 + ISO14443A_CRCA_SIZE)) { + State = STATE_IDLE; + return ISO14443A_APP_NO_RESPONSE; + } + /* All commands here have CRCA appended; verify it right away */ + ByteCount -= 2; + if (!ISO14443ACheckCRCA(Buffer, ByteCount)) { + Buffer[0] = NAK_CRC_ERROR; + return NAK_FRAME_SIZE; + } + return AppProcess(Buffer, ByteCount); + + default: + /* Unknown state? Should never happen. */ + break; + } + + /* No response has been sent, when we reach here */ + return ISO14443A_APP_NO_RESPONSE; +} + +// HELPER FUNCTIONS +void NTAG215GetUid(ConfigurationUidType Uid) +{ + /* Read UID from memory */ + MemoryReadBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE); + MemoryReadBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE); +} + +void NTAG215SetUid(ConfigurationUidType Uid) +{ + /* Calculate check bytes and write everything into memory */ + uint8_t BCC1 = ISO14443A_UID0_CT ^ Uid[0] ^ Uid[1] ^ Uid[2]; + uint8_t BCC2 = Uid[3] ^ Uid[4] ^ Uid[5] ^ Uid[6]; + + MemoryWriteBlock(&Uid[0], UID_CL1_ADDRESS, UID_CL1_SIZE); + MemoryWriteBlock(&BCC1, UID_BCC1_ADDRESS, ISO14443A_CL_BCC_SIZE); + MemoryWriteBlock(&Uid[UID_CL1_SIZE], UID_CL2_ADDRESS, UID_CL2_SIZE); + MemoryWriteBlock(&BCC2, UID_BCC2_ADDRESS, ISO14443A_CL_BCC_SIZE); +} diff --git a/Firmware/Chameleon-Mini/Application/NTAG215.h b/Firmware/Chameleon-Mini/Application/NTAG215.h new file mode 100644 index 00000000..77c1cc54 --- /dev/null +++ b/Firmware/Chameleon-Mini/Application/NTAG215.h @@ -0,0 +1,27 @@ +/* + * NTAG215.h + * + * Created on: 20.02.2019 + * Author: gcammisa + */ + +#ifndef NTAG215_H_ +#define NTAG215_H_ + +#include "Application.h" +#include "ISO14443-3A.h" + +#define NTAG215_UID_SIZE ISO14443A_UID_SIZE_DOUBLE // 7 bytes UID +#define NTAG215_PAGE_SIZE 4 // bytes per page +#define NTAG215_PAGES 135 // 135 pages total, from 0 to 134 +#define NTAG215_MEM_SIZE ( NTAG215_PAGE_SIZE * NTAG215_PAGES ) + +void NTAG215AppInit(void); +void NTAG215AppReset(void); +void NTAG215AppTask(void); + +uint16_t NTAG215AppProcess(uint8_t* Buffer, uint16_t BitCount); + +void NTAG215GetUid(ConfigurationUidType Uid); +void NTAG215SetUid(ConfigurationUidType Uid); +#endif diff --git a/Firmware/Chameleon-Mini/Configuration.c b/Firmware/Chameleon-Mini/Configuration.c index b0e855ec..74f89dab 100644 --- a/Firmware/Chameleon-Mini/Configuration.c +++ b/Firmware/Chameleon-Mini/Configuration.c @@ -51,6 +51,9 @@ static const MapEntryType PROGMEM ConfigurationMap[] = { #ifdef CONFIG_ISO14443A_READER_SUPPORT { .Id = CONFIG_ISO14443A_READER, .Text = "ISO14443A_READER" }, #endif +#ifdef CONFIG_NTAG215_SUPPORT + { .Id = CONFIG_NTAG215, .Text = "NTAG215" }, +#endif #ifdef CONFIG_VICINITY_SUPPORT { .Id = CONFIG_VICINITY, .Text = "VICINITY" }, #endif @@ -478,6 +481,24 @@ static const PROGMEM ConfigurationType ConfigurationTable[] = { .TagFamily = TAG_FAMILY_ISO15693 }, #endif +#ifdef CONFIG_NTAG215_SUPPORT + [CONFIG_NTAG215] = { + .CodecInitFunc = ISO14443ACodecInit, + .CodecDeInitFunc = ISO14443ACodecDeInit, + .CodecTaskFunc = ISO14443ACodecTask, + .ApplicationInitFunc = NTAG215AppInit, + .ApplicationResetFunc = NTAG215AppReset, + .ApplicationTaskFunc = NTAG215AppTask, + .ApplicationTickFunc = ApplicationTickDummy, + .ApplicationProcessFunc = NTAG215AppProcess, + .ApplicationGetUidFunc = NTAG215GetUid, + .ApplicationSetUidFunc = NTAG215SetUid, + .UidSize = NTAG215_UID_SIZE, + .MemorySize = NTAG215_MEM_SIZE, + .ReadOnly = false, + .TagFamily = TAG_FAMILY_ISO14443A + }, +#endif }; ConfigurationType ActiveConfiguration; diff --git a/Firmware/Chameleon-Mini/Configuration.h b/Firmware/Chameleon-Mini/Configuration.h index 0d5377e8..0cfd2648 100644 --- a/Firmware/Chameleon-Mini/Configuration.h +++ b/Firmware/Chameleon-Mini/Configuration.h @@ -57,6 +57,9 @@ typedef enum { #ifdef CONFIG_ISO14443A_READER_SUPPORT CONFIG_ISO14443A_READER, #endif +#ifdef CONFIG_NTAG215_SUPPORT + CONFIG_NTAG215, +#endif #ifdef CONFIG_VICINITY_SUPPORT CONFIG_VICINITY, #endif diff --git a/Firmware/Chameleon-Mini/Makefile b/Firmware/Chameleon-Mini/Makefile index 065c93f4..cc7184eb 100644 --- a/Firmware/Chameleon-Mini/Makefile +++ b/Firmware/Chameleon-Mini/Makefile @@ -17,6 +17,7 @@ SETTINGS += -DCONFIG_MF_CLASSIC_4K_7B_SUPPORT SETTINGS += -DCONFIG_MF_ULTRALIGHT_SUPPORT SETTINGS += -DCONFIG_ISO14443A_SNIFF_SUPPORT SETTINGS += -DCONFIG_ISO14443A_READER_SUPPORT +SETTINGS += -DCONFIG_NTAG215_SUPPORT SETTINGS += -DCONFIG_VICINITY_SUPPORT SETTINGS += -DCONFIG_SL2S2002_SUPPORT SETTINGS += -DCONFIG_TITAGITSTANDARD_SUPPORT @@ -113,7 +114,7 @@ SRC += Terminal/Terminal.c Terminal/Commands.c Terminal/XModem.c Termina SRC += Codec/Codec.c Codec/ISO14443-2A.c Codec/Reader14443-2A.c Codec/SniffISO14443-2A.c Codec/Reader14443-ISR.S SRC += Application/MifareUltralight.c Application/MifareClassic.c Application/ISO14443-3A.c Application/Crypto1.c Application/Reader14443A.c Application/Sniff14443A.c Application/CryptoTDEA.S SRC += Codec/ISO15693.c -SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/ISO15693-A.c Application/EM4233.c +SRC += Application/Vicinity.c Application/Sl2s2002.c Application/TITagitstandard.c Application/ISO15693-A.c Application/EM4233.c Application/NTAG215.c SRC += $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) LUFA_PATH = ../LUFA CC_FLAGS = -flto -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/Software/Chameleon/Device.py b/Software/Chameleon/Device.py index 6aae7d57..4629fcb6 100644 --- a/Software/Chameleon/Device.py +++ b/Software/Chameleon/Device.py @@ -28,6 +28,7 @@ class Device: COMMAND_RED_LED = "LEDRED" COMMAND_THRESHOLD = "THRESHOLD" COMMAND_UPGRADE = "upgrade" + COMMAND_CLEAR = "CLEAR" STATUS_CODE_OK = 100 STATUS_CODE_OK_WITH_TEXT = 101 @@ -207,6 +208,9 @@ def cmdDownloadLog(self, dataStream): def cmdClearLog(self): return self.execCmd(self.COMMAND_LOG_CLEAR) + + def cmdClear(self): + return self.execCmd(self.COMMAND_CLEAR) def cmdLogMode(self, newLogMode): return self.getSetCmd(self.COMMAND_LOGMODE, newLogMode) diff --git a/Software/chamtool.py b/Software/chamtool.py index 8a1203f5..1b8790b7 100755 --- a/Software/chamtool.py +++ b/Software/chamtool.py @@ -182,6 +182,10 @@ def cmdUpgrade(chameleon, arg): print ("Device changed into Upgrade Mode") exit(0) +def cmdClear(chameleon, arg): + chameleon.cmdClear() + return "Slot has been cleared" + # Custom class for argparse class CmdListAction(argparse.Action): def __init__(self, option_strings, dest, default=False, required=False, @@ -224,6 +228,7 @@ def main(): cmdArgGroup.add_argument("-rl", "--rled", dest="rled", action=CmdListAction, metavar="FUNCTION", nargs='?', help="retrieve or set the current red led function") cmdArgGroup.add_argument("-th", "--threshold", dest="threshold", action=CmdListAction, nargs='?', help="retrieve or set the threshold") cmdArgGroup.add_argument("-ug", "--upgrade", dest="upgrade", action=CmdListAction, nargs=0, help="set the micro Controller to upgrade mode") + cmdArgGroup.add_argument("-cl", "--clear", dest="clear", action=CmdListAction, nargs=0, help="clear the slot") args = argParser.parse_args() @@ -258,6 +263,7 @@ def main(): "rled" : cmdRedLED, "threshold" : cmdThreshold, "upgrade" : cmdUpgrade, + "clear" : cmdClear, } if hasattr(args, "cmdList"):