+       CmdsParse(CommandTable15, Cmd);
+       return 0;
+}
+
+int CmdHF15Help(const char *Cmd)
+{
+       CmdsHelp(CommandTable15);
+       return 0;
+}
+
+
+// "HF 15 Cmd" Interface
+// Allows direct communication with the tag on command level
+
+int CmdHF15CmdInquiry(const char *Cmd) 
+{
+       UsbCommand *r;  
+       uint8_t *recv;
+       UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
+       uint8_t *req=c.d.asBytes;
+       int reqlen=0;
+       
+       req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | 
+               ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
+       req[1]=ISO15_CMD_INVENTORY;
+       req[2]=0; // mask length
+       reqlen=AddCrc(req,3);
+       c.arg[0]=reqlen;
+
+       SendCommand(&c);
+       
+       r=WaitForResponseTimeout(CMD_ACK,1000);
+       
+       if (r!=NULL) {
+               if (r->arg[0]>=12) {
+                  recv = r->d.asBytes;
+                  PrintAndLog("UID=%s",sprintUID(NULL,&recv[2]));
+                  PrintAndLog("Tag Info: %s",getTagInfo(&recv[2]));    
+               } else {
+                       PrintAndLog("Response to short, just %i bytes. No tag?\n",r->arg[0]);           
+               }
+       } else {
+               PrintAndLog("timeout.");
+       }
+       return 0;
+}
+
+
+// Turns debugging on(1)/off(0)
+int CmdHF15CmdDebug( const char *cmd) {
+       int debug=atoi(cmd);
+       if (strlen(cmd)<1) {
+               PrintAndLog("Usage: hf 15 cmd debug  <0/1>");
+               PrintAndLog("   0..no debugging output  1..turn debugging on"); 
+               return 0;
+       }
+
+       UsbCommand c = {CMD_ISO_15693_DEBUG, {debug, 0, 0}};
+       SendCommand(&c);
+       return 0;
+}
+
+
+int CmdHF15CmdRaw (const char *cmd) {
+       UsbCommand *r;  
+       uint8_t *recv;
+       UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
+       int reply=1;
+       int fast=1;     
+       int crc=0;
+       char buf[5]="";
+       int i=0;
+       uint8_t data[100];
+       unsigned int datalen=0, temp;
+
+       
+       if (strlen(cmd)<3) {
+               PrintAndLog("Usage: hf 15 cmd raw  [-r] [-2] [-c] <0A 0B 0C ... hex>");
+               PrintAndLog("       -r    do not read response");
+               PrintAndLog("       -2    use slower '1 out of 256' mode");
+               PrintAndLog("       -c    calculate and append CRC");
+               PrintAndLog(" Tip: turn on debugging for verbose output");              
+               return 0;       
+       }
+
+       // strip
+       while (*cmd==' ' || *cmd=='\t') cmd++;
+       
+       while (cmd[i]!='\0') {
+               if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; }
+               if (cmd[i]=='-') {
+                       switch (cmd[i+1]) {
+                               case 'r': 
+                               case 'R': 
+                                       reply=0;
+                                       break;
+                               case '2':
+                                       fast=0;
+                                       break;
+                               case 'c':
+                               case 'C':                               
+                                       crc=1;
+                                       break;
+                               default:
+                                       PrintAndLog("Invalid option");
+                                       return 0;
+                       }
+                       i+=2;
+                       continue;
+               }
+               if ((cmd[i]>='0' && cmd[i]<='9') ||
+                   (cmd[i]>='a' && cmd[i]<='f') ||
+                   (cmd[i]>='A' && cmd[i]<='F') ) {
+                   buf[strlen(buf)+1]=0;
+                   buf[strlen(buf)]=cmd[i];
+                   i++;
+                   
+                   if (strlen(buf)>=2) {
+                       sscanf(buf,"%x",&temp);
+                       data[datalen]=(uint8_t)(temp & 0xff);
+                       datalen++;
+                       *buf=0;
+                   }
+                   continue;
+               }
+               PrintAndLog("Invalid char on input");
+               return 0;
+       }
+       if (crc) datalen=AddCrc(data,datalen);
+       
+       c.arg[0]=datalen;
+       c.arg[1]=fast;
+       c.arg[2]=reply;
+       memcpy(c.d.asBytes,data,datalen);
+       
+       SendCommand(&c);
+       
+       if (reply) {
+               r=WaitForResponseTimeout(CMD_ACK,1000);
+       
+               if (r!=NULL) {
+                       recv = r->d.asBytes;
+                       PrintAndLog("received %i octets",r->arg[0]);
+                       // TODO: output
+               } else {
+                       PrintAndLog("timeout while waiting for reply.");
+               }
+               
+       } // if reply
+       return 0;
+}
+
+
+int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
+       int temp;
+       uint8_t *req=c->d.asBytes, uid[8];
+       uint32_t reqlen=0;
+
+       // strip
+       while (**cmd==' ' || **cmd=='\t') (*cmd)++;
+       
+       if (strstr(*cmd,"-2")==*cmd) {
+               c->arg[1]=0; // quse 1of256
+               (*cmd)+=2;
+       }
+
+       // strip
+       while (**cmd==' ' || **cmd=='\t') (*cmd)++;
+       
+       if (strstr(*cmd,"-o")==*cmd) {
+               req[reqlen]=ISO15_REQ_OPTION;
+               (*cmd)+=2;
+       }
+       
+       // strip
+       while (**cmd==' ' || **cmd=='\t') (*cmd)++;
+       
+       switch (**cmd) {
+               case 0:
+                       PrintAndLog("missing addr");
+                       return 0;
+                       break;
+               case 's':
+               case 'S':
+                       // you must have selected the tag earlier
+                       req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | 
+                      ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT;
+                  memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
+                       reqlen+=iso15cmdlen;               
+                  break;
+               case 'u':
+               case 'U':
+                       // unaddressed mode may not be supported by all vendors
+                       req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | 
+                      ISO15_REQ_NONINVENTORY;
+                  memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
+                       reqlen+=iso15cmdlen;               
+                  break;
+               case '*':
+                       req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | 
+                      ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
+                  memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
+                       reqlen+=iso15cmdlen;               
+                  if (!getUID(uid)) {
+                       PrintAndLog("No Tag found");
+                       return 0;
+                  }
+                  memcpy(req+reqlen,uid,8);
+                  PrintAndLog("Detected UID %s",sprintUID(NULL,uid));
+                  reqlen+=8;
+                       break;                  
+               default:
+                       req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | 
+                      ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
+                       memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
+                       reqlen+=iso15cmdlen;               
+                  
+/*                     sscanf(cmd,"%hX%hX%hX%hX%hX%hX%hX%hX",
+                               (short unsigned int *)&uid[7],(short unsigned int *)&uid[6],
+                               (short unsigned int *)&uid[5],(short unsigned int *)&uid[4],
+                               (short unsigned int *)&uid[3],(short unsigned int *)&uid[2],
+                               (short unsigned int *)&uid[1],(short unsigned int *)&uid[0]); */
+                       for (int i=0;i<8 && (*cmd)[i*2] && (*cmd)[i*2+1];i++) { // parse UID
+                               sscanf((char[]){(*cmd)[i*2],(*cmd)[i*2+1],0},"%X",&temp);
+                               uid[7-i]=temp&0xff;
+                       }                               
+                               
+                       PrintAndLog("Using UID %s",sprintUID(NULL,uid));
+                       memcpy(&req[reqlen],&uid[0],8);            
+                  reqlen+=8;
+       }
+       // skip to next space           
+       while (**cmd!=' ' && **cmd!='\t') (*cmd)++;
+       // skip over the space
+       while (**cmd==' ' || **cmd=='\t') (*cmd)++;
+       
+       c->arg[0]=reqlen;       
+       return 1;
+}
+
+
+
+int CmdHF15CmdRead(const char *Cmd) {
+       UsbCommand *r;  
+       uint8_t *recv;
+       UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
+       uint8_t *req=c.d.asBytes;
+       int reqlen=0, pagenum;
+       char cmdbuf[100];
+       char *cmd=cmdbuf;
+       char output[100]="";
+       
+       strncpy(cmd,Cmd,99);
+
+       // usage:
+       if (strlen(cmd)<3) {
+               PrintAndLog("Usage:  hf 15 cmd read    [options] <uid|s|*> <page#>");
+               PrintAndLog("           options:");
+               PrintAndLog("               -2        use slower '1 out of 256' mode");
+               PrintAndLog("           uid (either): ");
+               PrintAndLog("               <8B hex>  full UID eg E011223344556677");
+               PrintAndLog("               s         selected tag");
+               PrintAndLog("               u         unaddressed mode");
+               PrintAndLog("               *         scan for tag");
+               PrintAndLog("           page#:        page number 0-255");  
+               return 0;
+       }       
+       
+       prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READ},1); 
+       reqlen=c.arg[0];
+
+       pagenum=strtol(cmd,NULL,0);
+       /*if (pagenum<0) {
+               PrintAndLog("invalid pagenum");
+               return 0;
+       }       */
+       
+       req[reqlen++]=(uint8_t)pagenum;
+       
+       reqlen=AddCrc(req,reqlen);
+       
+       c.arg[0]=reqlen;
+
+       SendCommand(&c);
+
+       r=WaitForResponseTimeout(CMD_ACK,1000);
+       
+       if (r!=NULL && r->arg[0]>2) {
+               recv = r->d.asBytes;
+               if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) {
+                       if (!(recv[0] & ISO15_RES_ERROR)) {
+                               *output=0; // reset outputstring
+                               //sprintf(output, "Block %2i   ",blocknum);
+                               for ( int i=1; i<r->arg[0]-2; i++) {
+                                       sprintf(output+strlen(output),"%02hX ",recv[i]);                                        
+                               }                                       
+                               strcat(output,"   ");
+                               for ( int i=2; i<r->arg[0]-2; i++) {
+                                       sprintf(output+strlen(output),"%c",recv[i]>31 || recv[i]<127?recv[i]:'.');                                      
+                               }                                       
+                               PrintAndLog("%s",output);       
+                       } else {
+                               PrintAndLog("Tag returned Error %i: %s",recv[0],TagErrorStr(recv[0])); 
+                       }                  
+               } else {
+                       PrintAndLog("CRC failed");
+               }
+       } else {
+               PrintAndLog("no answer");
+       }
+       
+       return 0;