Gtk 3 integrate serial port read write

Hi,
I’m developing a GUI for linux using Gtk 3; i have successfully created a main window, some buttons, and be able to get function for button clicked, open a second window and hiding the main one; i have created a " g_timeout_add_seconds(1, update_label, GTK_LABEL(win->label_Time));" to update the label displaying the time.
Now i have the necessity to read from a serial port (RS485 protocol) and update the gui based on data bytes received.
I have do some research and i understand that is not recomended to do it on the main gtk thread but instead use a GThread to read from the serial (async read preferred) and then pass the received data to the main gtk thread.
I have tried to search for some example but i cannot figure out anything, could somebody please give me some advice to start?
In my main.c i’m starting the gtk with this :
int res = g_application_run (G_APPLICATION (app_new ()), argc, argv);
Where do i start the GThread and how to comunicate with the Gtk main thread to pass data read from the serial port?
Thank you for any advice

You can wrap the file descriptor of the serial port into an GUnixInputStream and a GUnixOutputStream, then you can use the async read/write operations on that and do not need a thread at all.

See for example Sellerie/src/serial-port.c at master · phako/Sellerie · GitHub

1 Like

Hello,

Thank you very much for your reply; I really appreciate it! I didn’t see your hint and proceeded to accomplish something usable using libserialport.c to configure, open and obtain the file descriptor of the serial port. Then, I used:

g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)on_serial_data, data);

to link data on the port to the method: on_serial_data. The method is like this:

gboolean on_serial_data(GIOChannel *channel, GIOCondition condition, gpointer user_data)
{
  if(condition & G_IO_IN)
  {
    char buffer[1024];


    ssize_t bytes_read = sp_nonblocking_read(m_pSerialeRx, buffer, sizeof(buffer));

    g_info("Read: %d bytes", (int)bytes_read);

    if(bytes_read > 0)
    {
      gchar  msg[2*bytes_read];

      for (size_t i = 0; i < bytes_read; i++)
      {
        unsigned char tmpVal = buffer[i];
        sprintf(&msg[i*2], "%02x", tmpVal);
      }
      

      WriteTextConsole(msg);

      //g_free(msg);

      // HANDLE DATA
      //int retVal = (int)sp_nonblocking_write(m_pSerialeTx, buffer, bytes_read);

     // g_info("Write response: %d", retVal);
    }
    else if(bytes_read == SP_ERR_ARG)
    {
      g_error("on_serial_data() - Bytes read equals to SP_ERR_ARG");
    }
  }
  else
  {
    g_error("Event not enterred");
  }


  g_io_add_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc)on_serial_data, NULL);
}

I will look at your example link to understand your suggestion. At first sight, I’m feeling a little too noob for that implementation, but thanks again!!!
I know for sure that my version is not good, but could you please give me some advice on the method used?

Have a nice day!

This is fine, it is just the “old” way of doing this, before the async-style functions were introduced.

But you should be returning something in on_serial_data and if you return TRUE, there is no need to keep on calling g_io_add_watch there, just once after set-up. See GLib.IOFunc

1 Like

Thank you very much for your advice, it was causing troubles after some packets received…i don’t know why but in the first place the event was fired just one time (maybe not returning anything was catched as a FALSE), then i added the signal again in the end and it start “work” but not like it was intended…return TRUE was the answer! Thanks again

i read your link and the file-transfer class and i think i’m getting the main concept…my firt approach was bare metal style but i have to start to use the framework.
I want to implement a sort of state machine to process this data coming from the serial. this process must be unrelated with the GUI, ocasionally update but for the most part just log. I search from GTHread again :sweat_smile: but again the first page of gnome documentation disguraged me

Do not use threads if at all possible.

and

When writing projects using GLib, the default approach should be to never use threads. Instead, make proper use of the GLib main context which, through the use of asynchronous operations, allows most blocking I/O operations to continue in the background while the main context continues to process other events

So i’m asking what is the best approach to do this?

i’m not too fast in my “state machine” to do all the work in the method called by the signal on the serial port. I have to separate. Maybe a GTask? when data arrive at the serial port i start a GTask and go back to sleep. What happen if another data arrive and my first GTask has not completed his job?
how can i send a gtask only if the other one is completed without waiting for it?

EDIT: Maybe i can just put aflag and when data arrives on the serial method check the flag and start a GTask only if negative…And store the data in queues and give thi queue to the task

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.