繁体   English   中英

使用Java在Raspberry Pi 3上读写USB设备

[英]Read and Write to USB Device on Raspberry Pi 3 using Java

我在Raspberry Pi 3上使用Raspbian。我正在学习如何使用Java(SE运行时版本1.8.0_65)进行编码,并且我需要通过USB连接的Bill Acceptor传递原始数据。 根据制造商的文档,USB单元模拟串行类型的接口。 当我插入设备时,它会显示在/dev/serial/by-id 20多年前,我在SCO Unix设置上使用调制解调器编写了C代码。 如果有内存,我基本上将调制解调器/dev/ttyxx视为用于读取和写入的文件。 十多年前,我在Windows XP上编写了一个C ++程序,使用类似的Bill Acceptor装置(相同的制造商和型号)连接到串行端口而不是USB。 文档显示USB和串行单元都使用相同的数据字符串进行输入和输出,因此我知道SendString数据对于触发有效响应应该是正确的。 但是,我没有收到该部门的回复,所以我猜我没有正确连接到它。

这是代码...

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<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 < 0)
                    {
                        iRecvEmptyCount++;
                        Thread.sleep(5);
                    }
                } while (iRecvStringCount < 0 && iRecvEmptyCount < 100);
                if(iRecvStringCount > 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());
    }
}

这是我得到的输出...

*****************************
*****  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...

我是否遗漏了一些明显的东西,或者只是解决了所有这些错误? 感谢您的任何建议!

我能够使用RXTXComm库从Raspberry Pi 3(运行Raspbian)成功地与Bill Acceptor通信。 使用9针串行/ RS232线束从旧的Windows XP计算机与设备进行通信时,我必须使用9600/7 / E / 1。 如果我没有在setSerialPortParams中使用这些值(在我的示例代码中),那么我将无法正确发送/接收数据。 因此,您需要了解设备的预期状况,才能将此方法与通过USB连接的其他“串行”硬件一起使用。 以下是具有基本功能的代码。 我首先从RXTXComm库附带的示例程序之一开始,并从那里开始构建。 由于这是一个示例程序,因此我尚未添加逻辑来验证来自设备的数据的校验和数字。

您可能会注意到,在代码的底部,我能够使用从/dev/serial/by-id目录/文件夹中拉出的设备的规范名称来确定/ dev / ttyUSBx。 无论设备插入哪个USB端口或系统以何种顺序初始化USB设备,它都会找到正确的设备名称。 我有一个同时也是USB串行设备的自动提款机,因此我能够测试并确认此功能。

public TwoWaySerialComm()
{
    super();
}

static boolean bReadyToSend = false;

void connect ( String portName ) throws Exception
{
    CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
    if ( portIdentifier.isCurrentlyOwned() )
    {
        System.out.println("Error: " + portName + " is currently in use.");
    }
    else
    {
        CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);

        if ( commPort instanceof SerialPort )
        {
            SerialPort serialPort = (SerialPort) commPort;
            serialPort.setSerialPortParams(9600, SerialPort.DATABITS_7, SerialPort.STOPBITS_1, SerialPort.PARITY_EVEN);

            InputStream in = serialPort.getInputStream();
            OutputStream out = serialPort.getOutputStream();

            // Thread handling logic
            // https://www.javaspecialists.eu/archive/Issue056.html
            Thread readThread = new Thread(new SerialReader(in));
            readThread.start();
            Thread writeThread = new Thread(new SerialWriter(out));
            writeThread.start();

            // Running threads for 10 seconds then stopping to ensure threads are shutting down
            long threadCurrTime = System.currentTimeMillis();
            long threadStartTime = System.currentTimeMillis();
            while( (threadCurrTime - threadStartTime) < 10000)
            {
                try 
                {
                    Thread.sleep(100);
                }
                catch (InterruptedException ex)
                {
                    Logger.getLogger(TwoWaySerialComm.class.getName()).log(Level.SEVERE, null, ex); 
                }
                threadCurrTime = System.currentTimeMillis();
            }

            if(writeThread.isAlive())
            {
                //System.out.println("Sending interrupt to SerialWriter thread...");
                writeThread.interrupt();
                writeThread.join();
                //System.out.println("SerialWriter thread is shut down.");
            }
            //else
            //{
            //    System.out.println("SerialWriter thread is already shut down.");
            //}

            if(readThread.isAlive())
            {
                //System.out.println("Sending interrupt to SerialReader thread...");
                readThread.interrupt();
                readThread.join();
                //System.out.println("SerialReader thread is shut down.");
            }
            //else
            //{
            //    System.out.println("SerialReader thread is already shut down.");
            //}

            commPort.close();
        }
        else
        {
            System.out.println("Error: " + portName + " is not recognized as a valid serial device.");
        }
    }     
}

/* SerialReader thread logic */
public static class SerialReader implements Runnable 
{
    InputStream in;
    boolean bShuttingDown = false;

    public SerialReader ( InputStream in )
    {
        this.in = in;
    }

    public void run ()
    {
        byte[] RecvString = new byte[12];
        String strResponse;
        int len = -1;
        try
        {
            while (!bShuttingDown)
            {
                len = this.in.read(RecvString);

                if( len > -1 )
                {
                    strResponse = "";
                    if(RecvString[0] == 0x02 && RecvString[9] == 0x03)
                    {
                        if(RecvString[3] == 0x00 && RecvString[4] == 0x00 && RecvString[5] == 0x00 && RecvString[6] == 0x00)
                        {
                            strResponse = "Device not ready.";
                        }
                        else
                        {
                            //-- RecvString[3]------------------
                            if(RecvString[3] == 0x01)
                                strResponse = " - Idling";
                            else
                            if(RecvString[3] == 0x02)
                                strResponse = " - Accepting";
                            else
                            if(RecvString[3] == 0x04)
                            {
                                strResponse = " - Escrowed";

                                if(RecvString[5] == 0x08)
                                    strResponse += " $1";
                                else
                                if(RecvString[5] == 0x10)
                                    strResponse += " $2";
                                else
                                if(RecvString[5] == 0x18)
                                    strResponse += " $5";
                                else
                                if(RecvString[5] == 0x20)
                                    strResponse += " $10";
                                else
                                if(RecvString[5] == 0x28)
                                    strResponse += " $20";
                                else
                                    strResponse += " unrecognized bill inserted";
                            }
                            else
                            if(RecvString[3] == 0x08)
                                strResponse = " - Stacking";
                            else
                            if(RecvString[3] == 0x10)
                                strResponse = " - Stacked";
                            else
                            if(RecvString[3] == 0x11)
                                strResponse = " - Returning";
                            else
                            if(RecvString[3] == 0x12)
                                strResponse = " - Returned";

                            //-- RecvString[4]------------------
                            if(RecvString[4] == 0x01)
                                strResponse += " - Cheated";
                            else
                            if(RecvString[4] == 0x02)
                                strResponse += " - Rejected";
                            else
                            if(RecvString[4] == 0x04)
                                strResponse += " - Jammed";
                            else
                            if(RecvString[4] == 0x08)
                                strResponse += " - Bill Stacker Full";
                            else
                            if(RecvString[4] == 0x10)
                                strResponse += " - Removable Cassette Installed";
                            else
                            if(RecvString[4] == 0x11)
                                strResponse += " - Reserved";
                            else
                            if(RecvString[4] == 0x12)
                                strResponse += " - Calibration mode";

                            //-- RecvString[5]------------------
                            if(RecvString[5] == 0x01)
                                strResponse += " - Power Up Reset";
                            else
                            if(RecvString[5] == 0x02)
                                strResponse += " - Invalid Command";
                            else
                            if(RecvString[5] == 0x04)
                                strResponse += " - Non-recoverable fault";
                        }
                        if(!strResponse.contains("Idling"))
                            System.out.println("Recv: " + DatatypeConverter.printHexBinary(RecvString) + strResponse);
                    }
                    else
                    {
                        System.out.println("Recv (invalid): " + DatatypeConverter.printHexBinary(RecvString));
                    }

                    try
                    {
                        Thread.sleep(100); // need this delay before we send next polling message, otherwise the data doesn't come in correctly
                        bReadyToSend = true;
                    }
                    catch (InterruptedException ex)
                    {
                        Thread.currentThread().interrupt();
                        //System.out.println("Shut down SerialReader thread.");
                        bShuttingDown = true;
                        break;
                    }
                }
            }
        }
        catch ( IOException ex )
        {
            System.out.println("Recv exception: " + ex.toString());
        }            
    }
}

/* SerialWriter thread logic */
public static class SerialWriter implements Runnable 
{
    OutputStream out;
    long lastSendTime = System.currentTimeMillis() - 1001;
    long currSendTime;
    byte[] SendString = new byte[8];
    byte CheckDigit;
    int iSendStringCount;
    boolean bOddCount = true;
    boolean bShuttingDown = false;

    public SerialWriter ( OutputStream out )
    {
        this.out = out;
    }

    public void run ()
    {
        while(!bShuttingDown)
        {
            currSendTime = System.currentTimeMillis();
            if(currSendTime - lastSendTime > 1000) // if it's been more than a second, send query string
                bReadyToSend = true;

            if(bReadyToSend)
            {
                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) 0x7F;
                SendString[4] = (byte) 0x1C;
                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
                {
                    lastSendTime = System.currentTimeMillis();
                    this.out.write(SendString);
                    //System.out.println("Sent: " + DatatypeConverter.printHexBinary(SendString));
                }
                catch ( IOException ex )
                {
                    System.out.println("Send exception: " + ex.toString());
                }

                try
                { 
                    Thread.sleep(1); // this is hear simply to catch an external interrupt
                }
                catch (InterruptedException ex)
                {
                    Thread.currentThread().interrupt();
                    //System.out.println("Shut down SerialWriter thread.");
                    bShuttingDown = true;
                    break;
                }
                bReadyToSend = false;
            }
        }
    }
}

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<myUsbDevices.length; i++)
           {
               if(myUsbDevices[i].contains("EBDS_over_USB"))
               {
                   File tempFile = new File(strUsbDeviceDir + "/" + myUsbDevices[i]);
                   String usbCanonicalName = tempFile.getCanonicalFile().toString(); //gives me /dev/ttyUSBx where 'x' is the USB device number
                   System.out.println("Connecting to " + usbCanonicalName + " (" + myUsbDevices[i] + ")");
                   (new TwoWaySerialComm()).connect(usbCanonicalName);
               }
               else
               {
                   System.out.println("Not using " + myUsbDevices[i]);
               }
           }
        }
    }
    catch ( Exception ex )
    {
        System.out.println("Connect exception: " + ex.toString());
    }

    System.out.println("*****************************");
    System.out.println("***** Program Finished ******");
    System.out.println("*****************************");
}

当我放入一张1美元的钞票时输出(我正在Windows 10 Pro上从NetBeans IDE 8.2开发/编译,并在RPi3上使用远程调试运行。我猜这是RXTX版本不匹配警告的来源):

*****************************
*****  Starting Program *****
*****************************
Connecting to /dev/ttyUSB0 (usb-Silicon_Labs_Series_2000_Bill_Acceptor__EBDS_over_USB__46580120748-if00-port0)
Stable Library
=========================================
Native lib Version = RXTX-2.2pre2
Java lib Version   = RXTX-2.1-7
WARNING:  RXTX Version mismatch
    Jar version = RXTX-2.1-7
    native lib Version = RXTX-2.2pre2
Recv (invalid): 020000000000000000000000
Recv (invalid): 0B2001100800503603540000
Recv: 020B20041008005036035100 - Escrowed $1 - Removable Cassette Installed
*****************************
***** Program Finished ******
*****************************

我希望此描述和示例代码可以对其他人有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM