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());
Thread.sleep(50);
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";
// SerialComManager scm;
// scm = new SerialComManager();
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.
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