Serial and USB newbie question

26 Nov 2011

Hello, I am trying to work with serial device connected to mbed via tx and rx. Messages that serial device sends to mbed have variable length an arrives only vhen status changes, so not repeatedly.

My task is that message which arrives is processed and then sent by USB. But I found problem - If nothing arrives, nothing is sent but I want that message via USB is sent repeatedly (say about each 20 ms).

So if nothing is recieved last recieved message have to be send repeatedly until new message is recieved, processed and from this time this new values have to be send repeatedly.

I was thinking about ticker or something like that but nothing was working.

In the code I declare function to recieve message:

void retrieve_message () {
   if (serial.readable()) {
        serial.scanf("%s", &buff);
} 
}

Then function to process data:

void process (){

// process data here
}

Then I use:

int main() {

    pc.baud(115200);
    serial.baud(115200);
    
    pc.printf("/n/rHello /r/n");
    while (1) {
 retrieve_message();
 process();
hid.send(&processed_data);
}
}

There are many missing lines because I wanted to be easy to see what I do.

Everything works but only when data are recieved from serial device but my task is output data send repeatedly and message recieved from serial have to modify this repeatedly sent values.

Can anybody help me please?

26 Nov 2011

I think a tick would be your best bet,

Set a tick @ 20 mS,

Then in your main:

If ( tick **OR** RX Event)

{
build HID MESSAGE
Send HID Message.
Re-start tick
}

Hope this helps

Ceri

27 Nov 2011

Hello, still no progress. Thank You Ceri for answer but I wasn't still successfull. When I wrap hid.send(&processed_data) to

void send_rep {hid.send(&processed_data); } 

to be able to attach it to ticker, device is not enumerated on Host PC and PC says device not recognized.

Have anybody idea how to reach my goal? I just need to repeatedly send report from buffer and independently put data to this buffer when they arrives via serial rx (not repeatedly only when status on serial device changes).

I also found that data from serial can arrive up to twice per one send o output so I have to make average value of those.

Is this possible?

27 Nov 2011

Have a look at my USB HID Program, Although it does not have a ticker, USB HID does work, and I also have uploaded a simple HID viewer-graph.

Have a try of this program, even if it just tests..

your connecrions

Ceri

27 Nov 2011

Hi little,

I will investigate the problem concerning the device not enumerated. But I think that the problem is:

  • before enumeration, at the beginning "send" in the ticker handler is called.
  • "send" is blocking (in particular, this function waits that the device is ready. If the device is ready, it also waits that the message has been effectively sent. All of these mechanisms are working with interrupts), so you are blocked in an interrupt handler.
  • usb interrupts to perform the enumeration are not received
  • the device is not enumerated.

I think that I will introduce a non blocking "send" function. In the meantime, you can try to use the method configured() from USBDevice to check when the device is configured before launching your ticker. You can try something like:

int main(void) {
    while(!hid.configured());
    ticker.attach(handler, time);
    ...
}

Sam

27 Nov 2011

Thank You Ceri and Samuel, I will still try until I will be done :o) I ordered a book about programming i C++ for this Christmass. For now I learned only from internet in english and it is harder to understand than in my origin language.

I tried with mouse example too. If I placed ticker in main(void) before while(1) { rest of code here } device was not enumerated and no reports was sent (I use simpleHidWrite tool to see reports). Then I moved ticker after while(1) { } the result was that device was enumerated but ticker never started sending message (statement unreachable said compiler).

I think that problem is about sending reports before device is configured as You Samuel mentoied. I will try.

I would also ask You Ceri what program You use to view theese data in graphs for Your My USB Hid?

27 Nov 2011

Hi little,

Even if the device is enumerated, I noticed that if there is a call to "send" within an interrupt handler, the program will crash because this function is waiting for an interrupt saying that the message has been sent. For the moment, for USBHID, you can call "sendNB" which is non blocking. But you don't know if the message has been sent or not.

I tried this program and it works for me:

#include "mbed.h"
#include "USBHID.h"

//We declare a USBHID device
USBHID hid;

//This report will contain data to be sent
HID_REPORT send_report;

Ticker tic;

void tic_handler();
void tic_handler() {
    hid.sendNB(&send_report);
}

int main(void) {
    //Fill the report
    for(int i = 0; i < 64; i++)
        send_report.data[i] = i;
    send_report.length = 64;
    
    tic.attach_us(tic_handler, 20000);
    
    while (1);
}

Hope that helps

Sam

27 Nov 2011

Hello Samuel Thank You for whole example. I am going to try it now. Would I ask You please where to place function to recieve message from serial device and function to process recieved data? I declare and use functions:

void retrieve_message () {
   if (serial.readable()) {
        serial.scanf("%s", &buff);
} 
}

and

void process (){

// process data here - now thinking how
}

Have I place them in while(1){...} ?

I use parametr %s as I understand it reads until /n (or /r) is recieved from serial device at end of message (messages can have different length (say up to 20 bytes) and store them in array named buff.

My last question is - If I recieve one message and then second one before ticker sends data from this buffer(for example I will send one message each 20ms but I can recieve 0, 1 or 2 messages each 20ms - they are recieved only when status changes on serial device) does it mean that ticker sends values from buffer which are actually in?

So first message is stored, then second one arrives and rewrite first one and right now ticker is reading buffer and sending values which are actually in buffer?

27 Nov 2011

Hi little,

You don't need to check that serial is readable. scanf will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab).

Then, you should pass buff as argument for scanf as I assume that it's already an address. If you declare an array as: uint8_t buff[50], buff is an address.

You can do like this:

char buf[max_of_your_msg];

int main(void) {
   while(1){
      serial.scanf("%s", buf);
      process();
   }
}

Yes, you are right, the ticker will send the last message received. If you don't want this behavior, you have to store messages in a queue for instance. The ticker will dequeue each messages one by one.

Hope that helps.

Sam

27 Nov 2011

Hello Samuel, You are really awesome, I feel this all is what I need for my project. I am now really interested in storing messages in queue. The best result for me is if arrives two messages before ticker sends result to make average result to send. If I simplify it when arrives 5 in first message and 7 in second message and I store them independently I would be able to make average result 7+5 / 2 = 6 and send six via ticker. And if arrives only one message pass only this as result. And if no message arrives, data from previous reading will be sent until new is recieved and processed. Do I understand it?

Is this possible by adding second serial.scanf("%s", buf2); with pointer to buf2 under statement serial.scanf("%s", buf); ?

I understand that answering is very time consuming so I am very appreciative to You.

27 Nov 2011

My HID program was written with Delphi, (pascal)

You need the .exe & the .dll

If you would like me to modify it a bit, so it displays a bar graph, Or similar, Send me drawing, and how you would like it to operate, As well as 8, 16 bit numbers, min max values etc. Etc. Etc.

Ceri

27 Nov 2011

@little: I think that you can use arrays with two dimensions: char buf[10][max_of_your_msg]. With that, you have a matrix: each line will represent one message. With this example, you will be able to store 10 messages. buf[i] will be a pointer on one of your messages.

So when you have a new message, you do a scanf on "the good buf[i]" and when you send a message, you send "the good buf[j]". You can have two variables which represent the first free space when you can store a new message and another which represents the next message to send. You can have the number of messages available by doing the difference between your two pointers to see how many messages have been stored since the last ticker event.(maybe the modulo function will be useful ;) ). For more information, you can search circular buffer on the Internet.

@ceri: Good to be able to communicate in Delphi. For the moment I was just able to communicate with a python script. Feel free to add your example in the USBHID bindings webpage.

Sam

27 Nov 2011

Hello Ceri, it is nice from You. Was it hard to do in delphi? As I can see You use four graphs to show data sended from mbed and it matches my goals. (for now not sure if I will use 8 bit or 16 bit for higher precision I can choice so I will. I would also ask You if is it possible use 5 line with 8 status lines. I would like to use this line to demask one byte data (&&1, &&2, &&4...) to show something like 8 buttons status in time (on or off)?

Thank You for Your interest

28 Nov 2011

Delphi is by far the most easiest, and user friendly package I have ever used.

I can usually get something working in Delphi, in 20 minuets,

whereas using builder, it could take half a day, or a week with Visual Studio.

Generally, it now takes me longer to pick ICONS, and arrange buttons, than it takes to write an APP.

......

Do you mean 8 "LED's" to monitor one BYTE/CHAR

Please make a simple drawing of what you would like,

And any text labels

Thanks

Ceri

24 Oct 2012

Hi Sam,

how can I detect if the last report was sent out to the host with sendNB??? If i send out reports too fast, it happens that the host can't keep up receiving the reports and looses some!

Thanks for your help!

Stefan.

Samuel Mokrani wrote:

Hi little,

Even if the device is enumerated, I noticed that if there is a call to "send" within an interrupt handler, the program will crash because this function is waiting for an interrupt saying that the message has been sent. For the moment, for USBHID, you can call "sendNB" which is non blocking. But you don't know if the message has been sent or not.

I tried this program and it works for me:

#include "mbed.h"
#include "USBHID.h"

//We declare a USBHID device
USBHID hid;

//This report will contain data to be sent
HID_REPORT send_report;

Ticker tic;

void tic_handler();
void tic_handler() {
    hid.sendNB(&send_report);
}

int main(void) {
    //Fill the report
    for(int i = 0; i < 64; i++)
        send_report.data[i] = i;
    send_report.length = 64;
    
    tic.attach_us(tic_handler, 20000);
    
    while (1);
}

Hope that helps

Sam

24 Oct 2012

The result of hid.sendNB(&send_report);

will tell you if it got sent.

bool Sent;

Sent = hid.sendNB(&send_report);

if (Sent) 
{
  pc.printf ("Gone :)\r\n");
}
else
{
  pc.printf ("Sorry i lost one :(\r\n");
}

Hope this was usefull ..

Ceri

25 Oct 2012

Hi Ceri,

thanks for this information. In fact, the HID Device (mbed) seems to never loose any reports when writing them out via sendNB. It always returns "true".

Problem is that when the PC software can't keep up processing these reports, they get lost without the HID Device noticing it. So I've to implement some sort of handshaking protocol.

Any hints about how to avoid these report losses are highly appreciated :o)

Stefan.

25 Oct 2012

you could probably add a counter byte to each message, and the PC will need to buffer messages,

possibly, from PC, send a message, containing an array of 'I got it'

[yes] [yes] [no] [yes] [yes] [yes] [yes] [yes] [yes] [no] [yes] [yes] [yes] [yes] [yes] [yes] [yes] [yes] [yes] [yes]

so ..

message 3 & 10 needs to be re sent.

Hope this was interesting

Ceri

25 Oct 2012

Hi Ceri,

yes, I've implemented a simple report-counter. However, by using a simple software buffer on the PC, the missed reports are gone :o)

Can you recommend a good C/C++ library for accessing a USB HID device? Currently, I'm experimenting with HIDAPI from signal11 (http://www.signal11.us/oss/hidapi/) which is easy to use and available for free. Unfortunately, it crashes from time to time (Win7x64).

Again, many thanks for your valuable help!

Stefan.

25 Oct 2012

Sorry I only use DELPHI for my windows programs,

but if you do use Delphi, then i will gladly send you my copy of .DLL

and some example code to get you started.

Ceri

25 Oct 2012

I've used the free version of this driver. Give it a try.

http://basic.io/index.php/supportdownloads

Mike