RishiGupta12 / SerialPundit

Serial port communication in Java - FTDI D2XX, HID API, X/Y modem
GNU Affero General Public License v3.0
125 stars 56 forks source link

Thread don't resume correctly #14

Closed mctdi closed 7 years ago

mctdi commented 7 years ago

I created an web apps with spring boot. When application start, I start to do a blocking read on the serial port. I use serialPundit library.

  @Component
    public class ScanApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
        @Autowired
        public ScanRead scanRead;

        @Override
        public void onApplicationEvent(final ApplicationReadyEvent event) {
            scanRead.run();
        }
    }

My thread code

@Component
    public class ScanRead implements Runnable {

        @Autowired
        private SerialComManager scm;

        private long handle;
        private long context;

        Thread thrd;
        boolean suspended;
        boolean stopped;

        String port = "/dev/ttyUSB0";

        final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

        public String bytesToHex(byte[] bytes) {
            char[] hexChars = new char[bytes.length * 2];
            for (int j = 0; j < bytes.length; j++) {
                int v = bytes[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        }

        @Override
        public void run() {
            System.out.println("run");
            try {

                handle = scm.openComPort(port, true, false, true);
                scm.configureComPortData(handle, DATABITS.DB_8, STOPBITS.SB_1, PARITY.P_NONE, BAUDRATE.B9600, 0);
                scm.configureComPortControl(handle, FLOWCONTROL.NONE, 'x', 'x', false, false);
                context = scm.createBlockingIOContext();

                while (true) {

                    StringBuilder sb = new StringBuilder();

                    byte[] dataRead = {};

                    for (int x = 0; x < 8; x++) {
                        dataRead = scm.readBytesBlocking(handle, 1, context);
                        if (dataRead != null) {
                            sb.append(bytesToHex(dataRead));
                        }
                    }

                    System.out.println("run" + sb.toString());

                    synchronized (this) {
                        while (suspended) {
                            wait();
                        }
                        if (stopped) {
                            break;
                        }
                    }

                }
            } catch (InterruptedException exc) {
                System.out.println(thrd.getName() + " interrupted.");
                System.out.println("run 1: " + exc.getMessage());
            } catch (IOException ex) {
                Logger.getLogger(ScanRead.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("run 2: " + ex.getMessage());
            }
        }

        public synchronized void stop() {
            System.out.println("stop");
            stopped = true;
            suspended = false;
            notify();
        }

        public synchronized void suspend() throws SerialComException {
            suspended = true;
            System.out.println("suspend");
            scm.unblockBlockingIOOperation(context);
            scm.destroyBlockingIOContext(context);
            scm.closeComPort(handle);
        }

        public synchronized void resume() throws SerialComException {
            System.out.println("resume");
            suspended = false;
            handle = scm.openComPort(port, true, false, true);
            scm.configureComPortData(handle, DATABITS.DB_8, STOPBITS.SB_1, PARITY.P_NONE, BAUDRATE.B9600, 0);
            scm.configureComPortControl(handle, FLOWCONTROL.NONE, 'x', 'x', false, false);
            context = scm.createBlockingIOContext();
            notify();
        }

    }

If a member don't have a card assigned, I don't want to suspend the thread, do another process on the serial port and resume the thread.

When a user don't have a card assigned, I have this code who need to be called.

 @GetMapping(value = "/members/{memberId}/card")
        public ResponseEntity<Void> updateMemberCardId(@PathVariable("memberId") Long memberId) {

            System.out.println("updateCardId");
            StringBuilder sb = new StringBuilder();
            try {
                String port = "/dev/ttyUSB0";

                scanRead.suspend();

                long handle = scm.openComPort(port, true, false, true);
                byte[] dataRead = {};

                scm.configureComPortData(handle, SerialComManager.DATABITS.DB_8, SerialComManager.STOPBITS.SB_1, SerialComManager.PARITY.P_NONE, SerialComManager.BAUDRATE.B9600, 0);
                scm.configureComPortControl(handle, SerialComManager.FLOWCONTROL.NONE, 'x', 'x', false, false);

                long context = scm.createBlockingIOContext();

                for (int x = 0; x < 8; x++) {
                    dataRead = scm.readBytesBlocking(handle, 1, context);
                    if (dataRead != null) {
                        sb.append(bytesToHex(dataRead));
                    }
                }

                System.out.println(sb.toString());

                scm.unblockBlockingIOOperation(context);
                scm.destroyBlockingIOContext(context);
                scm.closeComPort(handle);

                scanRead.resume();

                memberService.updateMemberCardId(sb.toString(), memberId);

            } catch (IOException ex) {
                Logger.getLogger(MemberController.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("updated " + ex.getMessage());
            }
            return new ResponseEntity<>(HttpStatus.NO_CONTENT);
        }

It's seem to have an issue about the thread.

When I start the application,

run is displayed.

I do a call to this URL: http://localhost:8080/members/1/card No card assigned.

theses string are displayed

updatedCardId suspend

run 2: I/O operation unblocked !

I pass a card over the scanner

theses string are displayed id resume

Thread don't seem to run anymore because if I try to scan the card again, nothing happen. Nothing is displayed. Just don't understand because there is only one who have access to serial port.

Sometime get another result

run run before read updateCardId suspend updateCardId: before read

scan the card, but nothing happen, scan the card again and get

updateCardId: after read updateCardId: E00124ABF84CE001 resume

Card id should be E004010024ABF84C, seem like some issue can happen with the read

RishiGupta12 commented 7 years ago

I have updated the jar file. Please use latest sp-hid.jar file, latest demo app and hid api. In case you still face any issue let us track and solve at google group.