GTK非阻塞暂停

时间:2016-04-22 00:21:59

标签: c gtk

我有一个用C语言编写的gtk + -3.0应用程序,当前(gcc)在Windows 7 / msys64下编译和运行,它通过串行接口与定制设备通信。

它需要在写入器件和读取器件的回复之间暂停(几分之一秒),以便让设备有时间返回数据,否则串行输入缓冲器中没有可用的数据。

如果我使用sleep(1),应用程序会以某种方式工作,但由于重复睡眠而对用户事件没有响应。

使用g_timeout_add或g_timeout_add_seconds似乎没有帮助,因为第一次调用该函数发生在第一个间隔结束时,此时串行读取尝试已执行,没有找到数据。

感谢您的建议。

//   P O L L   C O N T R O L L E R   F O R   I T S   S E T T I N G S
    network->poll_event_source_id = gdk_threads_add_timeout(POLL_INTERVAL, zf_controller_poll, network);  // will use G_PRIORITY_DEFAULT

...

gint zf_controller_poll(gpointer data)  // thread to obtain controller settings at regular intervals
{
    gboolean res = FALSE;
    t_network *network;

    network = data;

    poll_iteration = (poll_iteration + 1);

    printf("zf_controller_poll iteration %d\n", poll_iteration);

    if (connection_running == FALSE)
    {
        printf("Not connected to controller\n");
        error_popup(network->main_window, "Not connected to controller!");
        return(0);
    }

    if (poll_running)  // only poll again after previous poll ended
    {
      printf("poll still running\n");
      return(1);
    }

    busy_state = TRUE;  // prepare to activate "busy..." timeout
    g_timeout_add_seconds(2, zf_progress_update, network);  // activate "busy..." timeout

    res = timer_read(network);  // ***
    if (res)
    {
      printf("obtained controller settings\n");
    }
    else
    {
      printf("Failed to obtain controller settings\n");
    }

    busy_state = FALSE;  // terminate "busy..." timeout

    return(1);  // if thread returns false (zero), timeout will be automatically destroyed and function won't be called again
}

...

gboolean timer_read (gpointer data)
{
    t_network *network;
    gint i, val, err;
    gdouble val_double;
    gchar text[10];

    network = data;
    i=0; val = 0; val_double = 0; err = 0;

    poll_running = TRUE;  // only poll again after previous poll ended, 

    for (i = 0; i<MAX_CHANNELS; i++)
    {

        if (gtk_switch_get_active(GTK_SWITCH(network->entry_toggle_mode[i])) == TRUE)
        {
            err = controller_send(get_channels[i], &val, network);  // ***

            if ((err == NO_CONNECTION) || (err == RECONNECTION_FAIL))
            {
                send_fail_action(network);
                network->tag_timer_read = 0; /*set tag to zero because time out will be destroyed here*/
                poll_running = FALSE;  // allow poll again after previous poll ended
                return(FALSE);
            }
            sprintf(text, "%d", val);
            gtk_entry_set_text (GTK_ENTRY(network->output_channel_array[i]), text);
            val = 0; err = 0;
        }else
            gtk_entry_set_text (GTK_ENTRY(network->output_channel_array[i]), "0");
    }

    poll_running = FALSE;  // only poll again after previous poll ended, 
    return(TRUE);
}

...

gint controller_send (const gchar *message, gint *valptr, gpointer main_data)
{
    gchar reply[2000] = {'\0'};
    unsigned char reply_s[4096];
    gint err = 0;
    gint val = 0;
    FILE *fileptr;
    t_network *network = main_data;
    int i, j;
    const char *message_s;
    char controller_cmd[25];

      j = strlen(message);
      if (j > 25)
        j = 25;
      for(i = 0; i < j; i++)
      {
        controller_cmd[i] = message[i];  // copy contents of wifi IP gchar buffer to intermediate buffer
      }
    message_s = controller_cmd;  // copy contents of intermediate buffer to serial char buffer

    time_t t = time (NULL);
    struct tm tm = *localtime(&t);

    if (connection_running == FALSE)
    {
        printf("Not connected to controller\n");
        fileptr = fopen("logfile.txt", "a");
        fprintf(fileptr, "%d.%d.%d %d:%d:%d\t Not connected to controller\n", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
        fclose(fileptr);
        return(NO_CONNECTION);
    }

    /*send message to controller*/
    if(network->comm_serial)  //  send via serial port if connected
    {
      err = zf_serial_send(network->comport_num, message_s);  // ***
    }
    else                      //  send via wifi IP
    {
      err = func_socket_send(network->s, message);
    }
    printf("error value: %d\n", err);

    /*if message send fails then: */
    if(err != 0)
    {
      if(network->comm_ip)  //  try to re-establish TCP/IP session
      {
        network->connect_thread = g_thread_new("id_reconnect", func_reconnect_after_failPtr, network);  /*call connect function in separate thread to keep GUI responsive*/
        g_thread_unref (network->connect_thread);
      }
        connection_running = FALSE;
        fileptr = fopen("logfile.txt", "a");
        fprintf(fileptr, "%d.%d.%d %d:%d:%d\t Error occurred on send, socket closed, trying to reconnect \n", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
        fclose(fileptr);
        /*print error value*/
        printf("error value %d\n", err);
        return (NO_CONNECTION);
    }

    err = 0;

    if(network->comm_serial)  //  receive via serial port if connected
    {
      err = zf_serial_recv(network->comport_num, reply_s);  // ***
      j = strlen(reply_s);
      if (j > 2000)
        j = 2000;  // don't write beyond length of destination buffer
      for(i = 0; i < j; i++)
      {
        reply[i] = reply_s[i];  // copy contents of serial char buffer to wifi IP gchar buffer
      }
    }
    else                      // receive via wifi IP
    {
      err = func_socket_receive(network->s, reply);
    }

    if (err != 0)
    {
        fileptr = fopen("logfile.txt", "a");
        fprintf(fileptr, "%d.%d.%d %d:%d:%d\t Error occurred on receive, socket closed, trying to reconnect \n", tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
        fclose(fileptr);
        connection_running = FALSE;
      if(network->comm_ip)  //  try to re-establish TCP/IP session
      {
        network->connect_thread = g_thread_new("id_reconnect", func_reconnect_after_failPtr, network);  /*call re connect function in separate thread to keep GUI responsive*/
        g_thread_unref(network->connect_thread);
      }
        /*print error value*/
        printf("error value %d\n", err);
        return (NO_CONNECTION);

    }else
    {
        val = get_extract_value(reply);
        *valptr = val;
    }

    return(0);
}

...

gint zf_serial_recv(int comport_num, unsigned char *reply)
{
    int recv_size = 0;

    recv_size = Serial_PollComport(comport_num, reply, 4095);

    reply[recv_size] = 0;  // terminate string with null

    if (recv_size <= 0)
    {
        printf("Serial reception failed: %d\n", recv_size);
        Serial_CloseComport(comport_num);
        return(1);
    }

    printf("\nreceived serial %dbytes\n", recv_size);
    printf("serial reply: %s\n", reply);

    return (0);
}

...

gint zf_serial_send(int comport_num, const char *message)
{
    gint bytes_send;
    gboolean res;

    bytes_send = Serial_SendBuf(comport_num, message, strlen(message));  // ***

    if( bytes_send < 0)
    {
        printf("Serial send failed: %d\n", bytes_send);
        Serial_CloseComport(comport_num);
        return (1);
    }

    printf("Serial send string: %s\n", message);

//  g_timeout_add_seconds(serial_wr_pause, zf_serial_wr_pause, (gpointer) bytes_send);
// next line does not delay - (first) execution will be in (approx) 1 second
//  res = g_timeout_add_seconds(1, zf_serial_wr_pause, (gpointer) bytes_send);

    sleep(1);  // allow time for controller response to arrive in serial read buffer

    return(0);
}

...

int Serial_PollComport(int comport_number, unsigned char *buf, int size)
{
  int n;

  ReadFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL);

  return(n);
}

...

int Serial_SendBuf(int comport_number, unsigned char *buf, int size)
{
  int n;

  if(WriteFile(Cport[comport_number], buf, size, (LPDWORD)((void *)&n), NULL))
  {
    return(n);
  }

  return(-1);
}
//...
// snippet of serial port initialisation:
//...
  COMMTIMEOUTS Cptimeouts;

/* A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no bytes have been received. */
  Cptimeouts.ReadIntervalTimeout         = MAXDWORD;
  Cptimeouts.ReadTotalTimeoutMultiplier  = 0;
  Cptimeouts.ReadTotalTimeoutConstant    = 0;
  Cptimeouts.WriteTotalTimeoutMultiplier = 0;
  Cptimeouts.WriteTotalTimeoutConstant   = 0;

  if(!SetCommTimeouts(Cport[comport_number], &Cptimeouts))
  {
    printf("unable to set comport time-out settings\n");
    CloseHandle(Cport[comport_number]);
    return(1);
  }

0 个答案:

没有答案