使用Java

时间:2018-05-23 17:43:19

标签: java linux usb raspberry-pi3 raspbian

我在Raspberry Pi 3上使用Raspbian。我正在学习如何使用Java编写代码(SE运行时版本1.8.0_65),我需要使用USB连接的Bill Acceptor传送原始数据。根据制造商的文档,USB单元模仿串行接口。当我插入设备时,它会显示在/dev/serial/by-id中。我20多年前在SCO Unix设置上使用调制解调器编写了C代码。如果内存服务,我基本上将调制解调器/dev/ttyxx视为用于读写的文件。我在10年前在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...

我是否遗漏了一些显而易见的事情,或者只是错过了这一切?谢谢你的任何建议!

1 个答案:

答案 0 :(得分:0)

我能够使用RXTXComm library成功地与Raspberry Pi 3(运行Raspbian)的Bill Acceptor进行通信。使用9针串行/ RS232线束从旧的Windows XP计算机与设备通信时,我不得不使用9600/7 / E / 1。如果我没有将这些值用于setSerialPortParams(在我的示例代码中),我就无法正确发送/接收数据。因此,您需要知道设备的期望,以便将此方法与其他&#34; serial&#34;硬件通过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 ******
*****************************

我希望这个描述和示例代码可以帮助其他人。