// // File: commander_04.twn.c // Date: 03/16/2010 // Version: 4 // // Purpose: // // This is a command interface for transponder access, which is controlled // by the host. The main idea is to provide a common command set for the // various families of transponders which are supported by TWN3 readers. // // The complete communication is done in ASCII. Therefore a simple terminal // program can be used for testing. // // This program can be run on any type of TWN3 reader without modification. // There are some commands, which only make sense to the appropriate type // of transponder reader // // Feel free to modify this program for your specific purposes! // V1: // --- // - Initial release // // V2: // --- // - Support read of transponder // - Mifare: log into variable sector // // V3: // --- // - Extended documenation for all commands // // V4: // --- // - Command for switching general purpose outputs // // **************************************************************************** // ****** COMMAND SET ****** // **************************************************************************** // // Command/Response Structure // -------------------------- // A command always consists of a single character, some hex numbers // (2 digits per number) and a final carriage return. // // For every command, the device answers with a resonse. The response is // always a string containing some data with a terminating carriage return. // If there is no data to be sent as answer, a single character 'S' is sent // in order to signal successful processing of the command. // // Available Commands // ------------------ // 's': Search for a transponder. // 'l': Special login for Mifare transponders // 'r': Read data from a transponder // 'w': Write data onto a transponder // 'e': Switch LEDs // 'b': Sound a beep // 'o': Switch outputs // 'v': Display version info. // // // Detailed description of all commands. The [] represent one parameter // The number between () specifies count of hexadecimal digits. // // ---------------------------------------------------------------------------- // Search For a Transponder // ---------------------------------------------------------------------------- // Searches for a transponder and returns the serial number if a transponder // has been found. // // Command: s // // Response: // Success: [tag type (2)][serial number (8-14)] // Failure: E // // Example, search transponder: // s // // ---------------------------------------------------------------------------- // Login for Mifare Transponders // ---------------------------------------------------------------------------- // This command is specific for TWN3 Mifare. It does a login to the specified // sector. Use this command in order to gain access for read/write operations // to a specific sector. For security reasons, the key is hard coded and should // be adapted to your specific application. // // Command: l[sector (2)] // // Response: // Success: S // Failure: E // // Example, log into sector 2: // l02 // // ---------------------------------------------------------------------------- // Read Data From a Transponder // ---------------------------------------------------------------------------- // Read data from a transponder. Please note, that the length of a data word // is different for Multi125 (4 bytes, 8 digits) and Mifare (16 bytes, 32 digits). // // Command: r[(block-)address (2)][count of bytes (2)] // // Response: // Success (Multi125): [data (8)] // Success (Mifare): [data (32)] // Failure: E // // Example, read data from Mifare block address 8: // r0810 // // ---------------------------------------------------------------------------- // Write Data To a Transponder // ---------------------------------------------------------------------------- // Write data to a transponder. Please note, that the length of a data word // is different for Multi125 (4 bytes, 8 digits) and Mifare (16 bytes, 32 digits). // // Command (Multi125): w[address (2)][data (8)] // Command (Mifare): w[block address (2)][data (32)] // // Response: // Success: S // Failure: E // // Example, write data to Mifare block address 8: // w0812345678901234567890123456789012 // // ---------------------------------------------------------------------------- // Switch LEDs // ---------------------------------------------------------------------------- // Command: e[state (2)] // // Response: // Success: S // Failure: E // // The first digit (upper 4 bits) specify the LEDs to be set, the second digit // (lower 4 bits) specify the new status for these LEDs. Please see also description // of function 'LEDSet'. // // Example, turn red LED on: // e21 // // ---------------------------------------------------------------------------- // Sound a Beep // ---------------------------------------------------------------------------- // Command: b[type (2)] // // Response: // Success: S // Failure: E // // Please see also description of function 'Beep'. // // Example, sound a standard beep: // b01 // // ---------------------------------------------------------------------------- // Switch Outputs // ---------------------------------------------------------------------------- // Command: o[state (2)] // // Response: // Success: [new state (2)] // Failure: E // // The first digit (upper 4 bits) specify the outputss to be set, the second digit // (lower 4 bits) specify the new status for these outputss. Please see also description // of function 'LEDSet'. // // Example, turn red LED on: // e21 // // ---------------------------------------------------------------------------- // Display Version Info // ---------------------------------------------------------------------------- // Command: v // // Response: // Success: [version string] // Failure: E // // Example, read version, well somewhat simple: // v // #include // I am version 4 const byte Version = 4; // Some well known factory default keys for Mifare transponders secret byte MifareKeyFF[6] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; secret byte MifareKeyAA[6] = { 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5 }; secret byte MifareKeyBB[6] = { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5 }; // Some well known factory default keys for 125kHz transponders secret byte Hitag2Key[4] = { 'M','I','K','R' }; secret byte EM4050Key[4] = { 0x00,0x00,0x00,0x00 }; const byte MAXDATABYTES = 16; const byte MAXDATABITS = MAXDATABYTES*8; byte Data[MAXDATABYTES]; byte BitCnt; byte TagType; byte ByteCnt; // Make space for a command character, address and 32 hex digits const byte MAXCMDBYTES = 1+2+32; byte Cmd[MAXCMDBYTES]; byte CmdLen; void main() { // This is the standard startup sound Beep(BEEPSUCCESS); SetVolume(4); // Turn on a LED LEDSet(GREEN,ON); // This is the main loop. MainLoop: // Wait for a command if (!HostTestCmd(Cmd,CmdLen,MAXCMDBYTES)) goto MainLoop; // We need at least a command-code character if (CmdLen < 1) goto MainLoop; // Inplace conversion of the arguments (without the command code) // from ASCII hex to raw binary CmdLen = ScanHex(Cmd[1],CmdLen-1); // The command dispatcher switch (Cmd[0]) { case 's': // Search for a transponder if (GetDeviceType() == DEVTYPE_MULTI125) { // If you need to login to a 125kHz transponder Hitag2 or // EM4050 for read/write operations, then you should use // 'Multi125SearchLogin' instead of 'TagSearch'. Please // also choose the appropriate key for login. if (!Multi125SearchLogin(Data,BitCnt,TagType,Hitag2Key)) if (!Multi125SearchLogin(Data,BitCnt,TagType,EM4050Key)) goto Error; } else { if (!TagSearch(Data,BitCnt,TagType)) goto Error; } // Send the type of transponder we found. Feel free to // comment this line out, if you are not interested in this // information. HostSendHex(TagType,8,2); // Send the serial number. Calculate the number of // necessary digits from the length (given in bits) // of the transponder ID HostSendHex(Data,BitCnt,(BitCnt+7)/8*2); HostSendChar('\r'); // ID have been sent instead of OK goto MainLoop; case 'l': // Login to a mifare transponder. Try standard keys FF and AA if (!MifareLogin(MifareKeyFF,KEYA,Cmd[1])) if (!MifareLogin(MifareKeyAA,KEYA,Cmd[1])) goto Error; break; case 'r': // Read data from a transponder if (!TagRead(Cmd[1],Cmd[2],Data)) goto Error; HostSendHex(Data,Cmd[2]*8,Cmd[2]*2); HostSendChar('\r'); // Data have been sent instead of OK goto MainLoop; case 'w': // Write data to a transponder if (!TagWrite(Cmd[1],CmdLen-1,Cmd[2])) goto Error; break; case 'e': // Switch LEDs // We need one byte as argument if (CmdLen != 1) goto Error; LEDSet(Cmd[1]>>4,Cmd[1]&0x0F); break; case 'b': // Sound a beep // We need one byte as argument if (CmdLen != 1) goto Error; Beep(Cmd[1]); break; case 'o': // Switch outputs // We need one byte as argument if (CmdLen != 1) goto Error; OutputSet(Cmd[1]>>4,Cmd[1]&0x0F); Cmd[0] = OutputGet(OUTPUT0); Cmd[0] |= OutputGet(OUTPUT1) << 4; HostSendHex(Cmd[0],8,2); HostSendChar('\r'); // No OK required, because we sent the state of the outputs goto MainLoop; case 'v': // Show version info HostSendVersion(); HostSendChar('.'); HostSendChar('0'+Version/10); HostSendChar('0'+Version%10); HostSendChar('\r'); // No OK required, because we sent the version goto MainLoop; } OK: HostSendChar('S'); HostSendChar('\r'); goto MainLoop; Error: HostSendChar('E'); HostSendChar('\r'); goto MainLoop; }