#include "cmdmain.h"
  #include "util.h"
  #include "cmdscript.h"
 +#include "cmdcrc.h"
  
  
  unsigned int current_command = CMD_UNKNOWN;
  
  static int CmdHelp(const char *Cmd);
  static int CmdQuit(const char *Cmd);
 +static int CmdRev(const char *Cmd);
  
  //For storing command that are received from the device
  #define CMD_BUFFER_SIZE 50
  
  static command_t CommandTable[] = 
  {
 -      {"help",        CmdHelp,        1, "This help. Use '<command> help' for details of a particular command."},
 -      {"data",        CmdData,        1, "{ Plot window / data buffer manipulation... }"},
 -      {"hf",          CmdHF,          1, "{ High Frequency commands... }"},
 -      {"hw",          CmdHW,          1, "{ Hardware commands... }"},
 -      {"lf",          CmdLF,          1, "{ Low Frequency commands... }"},
 -      {"script",      CmdScript,      1, "{ Scripting commands }"},
 -      {"quit",        CmdQuit,        1, "Exit program"},
 -      {"exit",        CmdQuit,        1, "Exit program"},
 -      {NULL, NULL, 0, NULL}
 +  {"help",  CmdHelp,  1, "This help. Use '<command> help' for details of a particular command."},
 +  {"data",  CmdData,  1, "{ Plot window / data buffer manipulation... }"},
 +  {"hf",    CmdHF,    1, "{ High Frequency commands... }"},
 +  {"hw",    CmdHW,    1, "{ Hardware commands... }"},
 +  {"lf",    CmdLF,    1, "{ Low Frequency commands... }"},
 +  {"reveng",CmdRev,   1, "Crc calculations from the software reveng1-30"},
 +  {"script",CmdScript,1, "{ Scripting commands }"},
 +  {"quit",  CmdQuit,  1, "Exit program"},
 +  {"exit",  CmdQuit,  1, "Exit program"},
 +  {NULL, NULL, 0, NULL}
  };
  
  command_t* getTopLevelCommandTable()
  
  int CmdQuit(const char *Cmd)
  {
-   exit(0);
-   return 0;
+   return 99;
  }
 +
 +int CmdRev(const char *Cmd)
 +{
 +  CmdCrc(Cmd);
 +  return 0;
 +}
 +
  /**
   * @brief This method should be called when sending a new command to the pm3. In case any old
   *  responses from previous commands are stored in the buffer, a call to this method should clear them.
      memcpy(destination, command, sizeof(UsbCommand));
  
      cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap
- 
  }
+ 
+ 
  /**
   * @brief getCommand gets a command from an internal circular buffer.
   * @param response location to write command
      cmd_tail = (cmd_tail +1 ) % CMD_BUFFER_SIZE;
  
      return 1;
- 
  }
  
+ 
  /**
   * Waits for a certain response type. This method waits for a maximum of
   * ms_timeout milliseconds for a specified response command.
   */
  bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
    
-   UsbCommand resp;
+       UsbCommand resp;
        
-       if (response == NULL)
-     response = &resp;
- 
- 
-   // Wait until the command is received
-   for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
+       if (response == NULL) {
+               response = &resp;
+       }
  
+       // Wait until the command is received
+       for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
                while(getCommand(response)) {
-           if(response->cmd == cmd){
-           return true;
-           }
-       }
-         msleep(10); // XXX ugh
-         if (dm_seconds == 200) { // Two seconds elapsed
-           PrintAndLog("Waiting for a response from the proxmark...");
-           PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
-         }
+                       if(response->cmd == cmd){
+                               return true;
+                       }
+               }
+               msleep(10); // XXX ugh
+               if (dm_seconds == 200) { // Two seconds elapsed
+                       PrintAndLog("Waiting for a response from the proxmark...");
+                       PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
+               }
        }
-     return false;
+       return false;
  }
  
+ 
  bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
        return WaitForResponseTimeout(cmd,response,-1);
  }
  
+ 
  //-----------------------------------------------------------------------------
  // Entry point into our code: called whenever the user types a command and
  // then presses Enter, which the full command line that they typed.
  //-----------------------------------------------------------------------------
- void CommandReceived(char *Cmd) {
-   CmdsParse(CommandTable, Cmd);
+ int CommandReceived(char *Cmd) {
+       return CmdsParse(CommandTable, Cmd);
  }
  
+ 
  //-----------------------------------------------------------------------------
  // Entry point into our code: called whenever we received a packet over USB
  // that we weren't necessarily expecting, for example a debug print.
        switch(UC->cmd) {
                // First check if we are handling a debug message
                case CMD_DEBUG_PRINT_STRING: {
-                       char s[USB_CMD_DATA_SIZE+1] = {0x00};
+                       char s[USB_CMD_DATA_SIZE+1];
+                       memset(s, 0x00, sizeof(s));
                        size_t len = MIN(UC->arg[0],USB_CMD_DATA_SIZE);
                        memcpy(s,UC->d.asBytes,len);
-                       PrintAndLog("#db# %s       ", s);
+                       PrintAndLog("#db# %s", s);
                        return;
                } break;
  
  
                case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: {
                        memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]);
+                       return;
                } break;
  
                default:
+                       storeCommand(UC);
                        break;
        }
  
-       storeCommand(UC);
  }
  
 
  #include "util.h"
  #include "nonce2key/nonce2key.h"
  #include "../common/iso15693tools.h"
+ #include "iso14443crc.h"
  #include "../common/crc16.h"
  #include "../common/crc64.h"
  #include "../common/sha1.h"
  #include "aes.h"
 +#include "cmdcrc.h"
  /**
   * The following params expected:
   *  UsbCommand c
        return 1;
  }
  
+ static int l_iso14443b_crc(lua_State *L)
+ {
+       /* void ComputeCrc14443(int CrcType,
+                      const unsigned char *Data, int Length,
+                      unsigned char *TransmitFirst,
+                      unsigned char *TransmitSecond)
+       */
+       unsigned char buf[USB_CMD_DATA_SIZE];
+       size_t len = 0;
+       const char *data = luaL_checklstring(L, 1, &len);
+       if (USB_CMD_DATA_SIZE < len)
+               len =  USB_CMD_DATA_SIZE-2;
+ 
+       for (int i = 0; i < len; i += 2) {
+               sscanf(&data[i], "%02x", (unsigned int *)&buf[i / 2]);
+       }
+       ComputeCrc14443(CRC_14443_B, buf, len, &buf[len], &buf[len+1]);
+ 
+       lua_pushlstring(L, (const char *)&buf, len+2);
+       return 1;
+ }
  /*
   Simple AES 128 cbc hook up to OpenSSL.
   params:  key, input
        return 1;
  }
  
 +static int l_reveng_models(lua_State *L){
 +
 +      char *models[80];
 +      int count = 0;
 +      int in_width = luaL_checkinteger(L, 1);
 +      
 +      if( in_width > 89 ) return returnToLuaWithError(L,"Width cannot exceed 89, got %d", in_width);
 +
 +      uint8_t width[80];
 +      width[0] = (uint8_t)in_width;
 +      int ans = GetModels(models, &count, width);
 +      if (!ans) return 0;
 +      
 +      lua_newtable(L);
 +      
 +      for (int i = 0; i < count; i++){
 +              lua_pushstring(L,  (const char*)models[i]);
 +              lua_rawseti(L,-2,i+1);
 +              free(models[i]);
 +      }
 +
 +      return 1;
 +}
 +
 +//Called with 4 parameters.
 +// inModel   ,string containing the crc model name: 'CRC-8'
 +// inHexStr  ,string containing the hex representation of the data that will be used for CRC calculations.
 +// reverse   ,int 0/1  (bool) if 1, calculate the reverse CRC
 +// endian    ,char,  'B','b','L','l','t','r' describing if Big-Endian or Little-Endian should be used in different combinations.
 +//
 +// outputs:  string with hex representation of the CRC result
 +static int l_reveng_RunModel(lua_State *L){
 +      //-c || -v
 +      //inModel = valid model name string - CRC-8
 +      //inHexStr = input hex string to calculate crc on
 +      //reverse = reverse calc option if true
 +      //endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified
 +      //          l = little endian input and output, L = little endian output only, t = left justified}
 +      //result = calculated crc hex string    
 +      char result[50];
 +      
 +      const char *inModel = luaL_checkstring(L, 1);
 +      const char *inHexStr = luaL_checkstring(L, 2);
 +      bool reverse =  lua_toboolean(L, 3);
 +      const char endian = luaL_checkstring(L, 4)[0];
 +
 +      //PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse);
 +      //int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result)
 +      int ans = RunModel( (char *)inModel, (char *)inHexStr, reverse, endian, result);
 +      if (!ans)       
 +              return returnToLuaWithError(L,"Reveng failed");
 +
 +      lua_pushstring(L, (const char*)result); 
 +      return 1;
 +}
 +
  /**
   * @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be
   * able to do "require('foobar')" if foobar.lua is within lualibs folder.
                {"clearCommandBuffer",          l_clearCommandBuffer},
                {"console",                     l_CmdConsole},
                {"iso15693_crc",                l_iso15693_crc},
+               {"iso14443b_crc",               l_iso14443b_crc},
                {"aes128_decrypt",              l_aes128decrypt_cbc},
                {"aes128_decrypt_ecb",          l_aes128decrypt_ecb},
                {"aes128_encrypt",              l_aes128encrypt_cbc},
                {"crc16",                       l_crc16},
                {"crc64",                       l_crc64},
                {"sha1",                        l_sha1},
 +              {"reveng_models",               l_reveng_models},
 +              {"reveng_runmodel",             l_reveng_RunModel},
                {NULL, NULL}
        };