0
votes

I have following problem:

I receive sensor data via UART (every 10ms) and I want to process this data in gtk. The idea is to process this data in specific time intervalls (e.g. every 100ms). Due to that I use the g_timeout_add() function. The called function contains the common sets for UART communication -> in my case it blocks until I receive 10 chars. And here is the problem - at my read() (-> system call) function the program hang up.

My serial settings are as follows:

struct termios oldtio,newtio;
tcgetattr(fd,&oldtio); 

bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;

// set input mode (non-canonical, no echo,...) 
newtio.c_lflag = 0;

newtio.c_cc[VTIME]    = 0;   // inter-character timer unused 
newtio.c_cc[VMIN]     = 10;  // blocking read until 10 chars received 

res = read(fd,buf,20);   // returns after 10 chars have been input 

Nothing happens, no matter how I change the interval parameter in the g_timeout_add function.

I read a lot about this issue, but I could not find any explanation for my problem. Further I could not even find threads dealing with UART - GTK combination.

The code is very long, due to that I just want to ask you for now if you think that this idea basically could work or if there is a fundamental problem in my concept?

FYI: I tested this code without GUI (->GTK) and it works perfect. In pure C I can read the data and printf it.

Im happy for any answer.

1
read is a blocking function and the main thread / main loop will freeze. You must use a non blocking functions or set the read as non blocking or use GLib/GIO Asynchronous functions. Threads can also be used if you do not update the UI from the threads. - José Fonte
Welcome to Stack Overflow, please take the tour and How to create a Minimal, Complete, and Verifiable example. Have you also tried to write a small program that only reads the UART? If the small program also fail, it could mean that you don't have permission to read from the serial interface. - Pablo
It is possible and I have done so with Gtk and Python. Jose Fonte answer explains it well. - theGtknerd

1 Answers

1
votes

GTK+ like most toolkits is event-driven. Events are dispatched and processed in a main loop, which is the main thread of your process. So you can't do blocking calls (for example a sleep(5)) and you can't do processing that takes a long time to execute in a callback.

Think of two workers (the main loop and the callback) that only have holes to dig and only one shovel (CPU time). The main loop sees there's a timeout event to process and gives the shovel to the callback so it can work. If the callback takes the shovel for 5 hours, the main loop can't do its work (like painting the UI windows) nor give the shovel to any other callback waiting for it.

In your case, you're waiting for data in a blocking way. You're waiting for 10 bytes to arrive. Event if that takes them 5 hours to arrive, you keep the shovel. To fix that, you need to:

  • do your blocking calls in a separate thread (so both workers have a shovel and can work in parallel)
  • or do that asynchronously (maybe using GTask? Never used it myself)
  • or (less efficient) do some polling, which is already what you are already doing since you are looking for data every 100ms

For the polling solution, you could probably implement the VMIN = 0 and VTIME > 0 case, but you'd need to process the fact that you'll have to rebuild the messages as you could receive more bytes than expected at once.

For the threading solution, I'd use a GThread to perform the blocking read calls like you're doing now, and remove g_timeout_add. You won't need it as you'd change from a polling model ("did I have received data?" 10 times per second) to a notification model ("you have received data!"). Instead, when in your thread you have read some bytes, send them to the main loop with g_idle_add. In the associated callback you'll receive your data and will be able to present it to the user. Please remember however that you should never call GTK+ functions from threads other than the main thread, as the toolkit is not-thread-safe. That's why we g_idle_add (wich is from the GLib, which is ok).