Thread don't always resume correctly

2 views
Skip to first unread message

mcti...@gmail.com

unread,
Sep 30, 2016, 6:16:41 AM9/30/16
to SerialPundit
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

Rishi Gupta

unread,
Oct 2, 2016, 7:06:12 AM10/2/16
to SerialPundit
I have updated the jar file. Please use latest sp-hid.jar file, latest demo app and hid api. 

mcti...@gmail.com

unread,
Oct 2, 2016, 10:47:14 AM10/2/16
to SerialPundit
never use sp-hid... i only use sp-tty.jar and sp-core.jar

Rishi Gupta

unread,
Oct 3, 2016, 9:00:52 AM10/3/16
to SerialPundit
Hi,

- What is your project'S GOAL.
- Which card and card reader you are using.
- Which operating system you are using.
- Can you please explain more about using the card. What do you mean by card is assigned and card is not assigned.
How would the user use the card and what behaviour you want.

mcti...@gmail.com

unread,
Oct 3, 2016, 4:44:57 PM10/3/16
to SerialPundit
Information about the card reader.

it's a ISO15693 card reader.

No info about the card, but i know every card have an unique UID. It's a 64bits code like: e004010024abf84a

I'm able to read this value with this code

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));
   
}
}



When I buy a card, there are already a UID. I search a way to link this UID to a member of the computer system.

There is only one card reader. In the application, there is a thread who do a blocking read. Usefull only for member who have an card assigned to them.
In the member ui, there is a button to assigned a card to the user. This button suspend the the thread who do a blocking read. 
Member pass his card to the reader and the card is assigned to him.

I tried with Windows and Linux, same result.

I tried to call  clearPortIOBuffers in the resume and suspend code, but get the same result

mcti...@gmail.com

unread,
Oct 3, 2016, 10:40:27 PM10/3/16
to SerialPundit
sometime i get an
com.serialpundit.core.SerialComException: I/O operation unblocked !

and sometime not...

Rishi Gupta

unread,
Oct 4, 2016, 6:05:45 AM10/4/16
to SerialPundit
Hi,

Sorry for asking too many questions but the application design is not correct. If you help me more I can tell you the correct design. That exception is coming due to incorrect design.

1. Leave the technical details. Just tell me step by step how user will use the card. 

2. What do you mean by assigning card to user. Do you use any database. How do you remember cards.

- Suppose I bought a new card from market, then how will i use it with your card reader.

- Suppose I have visited your office once and used my card one time. What will happen if I come to your office again with same card.

Can you upload photo of your GUI so that I can understand what you are doing.

3. Why you want to suspend/resume. There is no need of it. No need of opening/closing again and again.

4. This code is in-efficent:

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));
    }
}

Use other designs like this:

I will tell you which design will give best performance once I understood you requirements.

5. For bytesToHex conversion use:

SerialComUtil.byteArrayToHexString()

6. No need of using stringbuilder. Just buffer till 8 bytes are received and then call byteArrayToHexString()

From which country you are.

Regards,
Rishi

mcti...@gmail.com

unread,
Oct 4, 2016, 8:07:46 AM10/4/16
to SerialPundit
Hi

1-

There are 2 scenario.

A member who have his card already assigned to him (card id saved in the member table in the database), scan his card, check if in the database  if it's valid, on another serial port i send a rts signal (this part is not done, so don't know yet how i will do it).

The other is when member don't have any card aissgned to him. In the ui interface, it click Assigned card to database. That call a rest service, with is id member, that should read card id and save card it to the database. After the user can scan its card again, system will detect its valid and will send a rts signal. Otherwise, administrator can click on the button "open door" to let member pass the door.

2  I mean saved the card id in the database.


- Member information need to be entered in the system. You saved data and after you can click on the button to saved card id to the database.
- For this scenario, that why i created a thread who do a blocking read.... if you card is saved, you should be able to scan you card and the system let ou



Like I said, I created a thread to manage two different thing.

Thread do a blocking read,  its read card id and check if it's valid in the database.
Click on saved card it, call a rest service with member id who read the value of the port

How do you want to do theses scenario.

4.

Maybe

Checked your example but don't really see the link with what I need to do.

5. ok will try.

6.

You talk about your ComPollDataRead or ComListenerDataReadApplication example?


Canada

mcti...@gmail.com

unread,
Oct 17, 2016, 9:30:38 PM10/17/16
to SerialPundit
this code work


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));
    }
}

i get E004010024ABF84C

if i use something like

byte[] dataRead = {};
dataRead = scm.readBytesBlocking(handle, 8, context);
String code = SerialComUtil.byteArrayToHexString(dataRead, ""));

i get E0

if i add a loop around dataread, i get E0 and after 04010024ABF84C

Rishi Gupta

unread,
Oct 19, 2016, 3:05:06 AM10/19/16
to SerialPundit
I have written an example design https://github.com/RishiGupta12/SerialPundit/blob/master/applications/card-reader/src/reader/CardReaderApp.java

I need precise details to refine this design to meet your requirements. Datasheet describing what data will be sent to PC when card is put over reader, command and responses etc is required.

If I am mistaken please correct me.
Reply all
Reply to author
Forward
0 new messages