title: Read and Write to USB Device on Raspberry Pi 3 using Java
body: <p>I'm using Raspbian on a Raspberry Pi 3. I'm learning how to code in Java (SE runtime version 1.8.0_65), and I need to communicate raw data with a USB connected Bill Acceptor. According to the manufacturer's documentation, the USB unit mimics a serial-type interface. When I plug the device in, it appears in <code>/dev/serial/by-id</code>. I wrote C code 20+ years ago using modems on SCO Unix setups. If memory serves, I basically treated the modems <code>/dev/ttyxx</code> as a file for reading and writing. I wrote a C++ program 10+ years ago on Windows XP using a similar Bill Acceptor unit (same manufacturer and model) connected to a serial port instead of USB. The documentation shows both USB and serial units use the same data strings for input and output, so I know the SendString data should be correct for triggering a valid response.  However, I'm not getting a reply from the unit, so I'm guessing I'm not connecting properly to it.</p>
  
  <p>Here is the code...</p>
  
  <pre><code>public static void main(String[] args) {
      try
      {
          System.out.println("*****************************");
          System.out.println("*****  Starting Program *****");
          System.out.println("*****************************");
          String strUsbDeviceDir = "/dev/serial/by-id";
          File myUsbDeviceDir = new File(strUsbDeviceDir);
          if(myUsbDeviceDir.exists())
          {
             String[] myUsbDevices = myUsbDeviceDir.list();
             for(int i=0; i&lt;myUsbDevices.length; i++)
             {
                 if(myUsbDevices[i].contains("EBDS_over_USB"))
                 {
                     System.out.println("Connecting to " + myUsbDevices[i]);
                     funcBillAcceptor(strUsbDeviceDir + "/" + myUsbDevices[i]);
                 }
                 else
                 {
                     System.out.println("Not using " + myUsbDevices[i]);
                 }
             }
          }
      }
      catch (Exception ex)
      {
          System.err.println(ex.toString());
      }
  }
  
  public static void funcBillAcceptor(String strBillAcceptor)
  {
      boolean bOddCount = false;
      byte[] SendString = new byte[8];
      byte[] RecvString = new byte[10];
      byte CheckDigit;
      int iSendStringCount, iRecvStringCount, iRecvEmptyCount;
  
      try
      {
          File fBillAcceptor = new File(strBillAcceptor);
          if(!fBillAcceptor.canRead())
          {
              System.out.println("No Read Permission for " + strBillAcceptor);
              return;
          }
          if(!fBillAcceptor.canWrite())
          {
              System.out.println("No Write Permission for " + strBillAcceptor);
              return;
          }
  
          RandomAccessFile rafBillAcceptor = new RandomAccessFile(strBillAcceptor, "rwd");
          if(rafBillAcceptor != null)
          {
              System.out.println("Successfully opened " + strBillAcceptor);
          }
  
          while(fBillAcceptor.exists())
          {
              SendString[0] = (byte) 0x02; //STX
              SendString[1] = (byte) 0x08;
              if(bOddCount)
              {
                  SendString[2] = (byte) 0x10;
                  bOddCount = false;
              }
              else
              {
                  SendString[2] = (byte) 0x11;
                  bOddCount = true;
              }
              SendString[3] = (byte) 0x1F;
              SendString[4] = (byte) 0x0C;
              SendString[5] = (byte) 0x00;
              SendString[6] = (byte) 0x03; //ETX
  
              //CheckDigit skips STX (byte 0) with byte 1 as seed/initial value
              //To calculate the check digit, start with next byte (2)
              CheckDigit = SendString[1];
              iSendStringCount = 2;
              while(SendString[iSendStringCount] != 0x03)
              {
                  CheckDigit = (byte) (SendString[iSendStringCount]^CheckDigit); //XOR current CheckDigit value with next byte
                  iSendStringCount++;
              }
              iSendStringCount++; //advance one more so we don't overwrite ETX
              SendString[iSendStringCount] = (byte) CheckDigit;
  
              try
              {
                  rafBillAcceptor.write(SendString);
                  System.out.println("Sent: " + DatatypeConverter.printHexBinary(SendString));
              }
              catch (Exception ex)
              {
                  System.err.println("Write exception: " + ex.toString());
              }
  
              System.out.println("Reading...");
              iRecvStringCount = iRecvEmptyCount = 0;
              try
              {
                  do
                  {
                      iRecvStringCount = rafBillAcceptor.read(RecvString);
                      System.out.println("Read " + iRecvStringCount + " bytes.");
                      if(iRecvStringCount &lt; 0)
                      {
                          iRecvEmptyCount++;
                          Thread.sleep(5);
                      }
                  } while (iRecvStringCount &lt; 0 &amp;&amp; iRecvEmptyCount &lt; 100);
                  if(iRecvStringCount &gt; 0)
                  {
                      System.out.println("Received: " + DatatypeConverter.printHexBinary(RecvString));
                  }
              }
              catch (Exception ex)
              {
                  System.err.println("Read exception: " + ex.toString());
              }
          }
      }
      catch (Exception ex)
      {
          System.err.println(ex.toString());
      }
  }
  </code></pre>
  
  <p>Here is the output I'm getting...</p>
  
  <pre><code>*****************************
  *****  Starting Program *****
  *****************************
  Connecting to usb-Silicon_Labs_Series_2000_Bill_Acceptor__EBDS_over_USB__46580120748-if00-port0
  Successfully opened /dev/serial/by-id/usb-Silicon_Labs_Series_2000_Bill_Acceptor__EBDS_over_USB__46580120748-if00-port0
  Sent: 0208111F0C00030A
  Reading...
  </code></pre>
  
  <p>Am I missing something obvious, or just going about this all wrong?  Thanks for any suggestions!</p>