当前位置: 首页 > 工具软件 > oFono > 使用案例 >

oFono学习笔记——GATChat(3):接收AT命令

缪朝
2023-12-01

摘要:

本文主要讲述GAtChat库接收AT命令的过程。

1. AT命令结果接收

在创建at_chat的过程中,我们会创建一个GAtIO对象。在该对象创建之后,会向主时间循环中添加一个IO可读的监视事件。当发现IO中存在数据时,调用received_data函数来接收,并把接收到的数据上传给上层gatchat进行返回结果的解析。

 1 static GAtIO *create_io(GIOChannel *channel, GIOFlags flags)
 2 {
 3     /*...*/
 4     io->channel = channel;
 5     io->read_watch = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
 6                 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
 7                 received_data, io,
 8                 read_watcher_destroy_notify);
 9 
10     return io;
11 
12 error:
13     /*...*/
14 }
15 
16 /*创建非阻塞IO*/
17 GAtIO *g_at_io_new(GIOChannel *channel)
18 {
19     return create_io(channel, G_IO_FLAG_NONBLOCK);
20 }
21 
22 /*创建阻塞IO*/
23 GAtIO *g_at_io_new_blocking(GIOChannel *channel)
24 {
25     return create_io(channel, 0);
26 }

GAtChat通过g_at_io_set_read_handler将AT返回结果的处理函数注册到gatio模块当中来

 1 gboolean g_at_io_set_read_handler(GAtIO *io, GAtIOReadFunc read_handler,
 2                     gpointer user_data)
 3 {
 4     if (io == NULL)
 5         return FALSE;
 6 
 7     io->read_handler = read_handler;
 8     io->read_data = user_data;
 9 
10     if (read_handler && ring_buffer_len(io->buf) > 0)
11         read_handler(io->buf, user_data);
12 
13     return TRUE;
14 }

 2. received_data函数分析

当主事件循环发现IO中存在有效数据时,会自动调用received_data将串口缓存中的数据读取到内部的ring buffer中,然后传到gatchat进行结果的解码

 1 static gboolean received_data(GIOChannel *channel, GIOCondition cond,
 2                 gpointer data)
 3 {
 4   /*...*/
 5     
 6   /* 读取缓存中的全部数据*/
 7     do {
 8         toread = ring_buffer_avail_no_wrap(io->buf);
 9 
10         if (toread == 0)
11             break;
12 
13         rbytes = 0;
14         buf = ring_buffer_write_ptr(io->buf, 0);
15 
16         status = g_io_channel_read_chars(channel, (char *) buf,
17                             toread, &rbytes, NULL);
18         g_at_util_debug_chat(TRUE, (char *)buf, rbytes,
19                     io->debugf, io->debug_data);
20 
21         read_count++;
22 
23         total_read += rbytes;
24 
25         if (rbytes > 0)
26             ring_buffer_write_advance(io->buf, rbytes);
27 
28     } while (status == G_IO_STATUS_NORMAL && rbytes > 0 &&
29                     read_count < io->max_read_attempts);
30 
31   /*上传给GAtChat,进行结果分析*/
32     if (total_read > 0 && io->read_handler)
33         io->read_handler(io->buf, io->read_data);
34   /*...*/
35 
36     return TRUE;
37 }

  3. new_bytes函数分析

这个函数负责对接收进行解码

 1 static void new_bytes(struct ring_buffer *rbuf, gpointer user_data)
 2 {
 3 /*....*/
 4     GAtSyntaxResult result;
 5 
 6     p->in_read_handler = TRUE;
 7 
 8     while (p->suspended == FALSE && (p->read_so_far < len)) {
 9         gsize rbytes = MIN(len - p->read_so_far, wrap - p->read_so_far);
10 
11      /*利用ATSyntax判断当前读到的数据是否完整,以及返回结果的类型*/        
12      result = p->syntax->feed(p->syntax, (char *)buf, &rbytes);
13 
14         buf += rbytes;
15         p->read_so_far += rbytes;
16 
17         if (p->read_so_far == wrap) {
18             buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
19             wrap = len;
20         }
21 
22         if (result == G_AT_SYNTAX_RESULT_UNSURE)
23             continue;
24      /*接收数据处理部分*/
25         switch (result) {
26         case G_AT_SYNTAX_RESULT_LINE:
27         case G_AT_SYNTAX_RESULT_MULTILINE:
28      /*line数据*/
29             have_line(p, extract_line(p, rbuf));
30             break;
31 
32         case G_AT_SYNTAX_RESULT_PDU:
33      /*pdu数据*/
34             have_pdu(p, extract_line(p, rbuf));
35             break;
36 
37         case G_AT_SYNTAX_RESULT_PROMPT:
38      /*当收到来自模块的确认后,激活writer,发送剩余的AT命令*/
39             chat_wakeup_writer(p);
40             ring_buffer_drain(rbuf, p->read_so_far);
41             break;
42 
43         default:
44      /*接受到的数据有错误,忽略这一次接收结果*/
45             ring_buffer_drain(rbuf, p->read_so_far);
46             break;
47         }
48 
49         len -= p->read_so_far;
50         wrap -= p->read_so_far;
51         p->read_so_far = 0;
52     }
53 
54     p->in_read_handler = FALSE;
55 
56     if (p->destroyed)
57         g_free(p);
58 }

 当接到来自io传上来的数据后,首先使用GATSyntax来检查当前收到的数据的完整性,如果不不是完整的一包数据则继续等待。否则,可以知道收到的数据中是否包含有line数据,或pdu数据,或模块回传的提示符,或接收数据存在问题。然后将收到的数据提取出来按类型进行处理。

4.接收完毕

当new_bytes函数收到一行数据时,他会调用have_line来处理,在have_line中会检查AT结果是否为完整一行,接着调用at_chat_handle_command_response判断这一行响应是否是AT命令返回结果的结束标志,如果是,则调用at_chat_finish_command将刚刚发送的AT命令从发送队列中删除。

  1 static void have_line(struct at_chat *p, char *str)
  2 {
  3     /* We're not going to copy terminal <CR><LF> */
  4     struct at_command *cmd;
  5 
  6     if (str == NULL)
  7         return;
  8 
  9     /* Check for echo, this should not happen, but lets be paranoid */
 10     if (!strncmp(str, "AT", 2) == TRUE)
 11         goto done;
 12 
 13     cmd = g_queue_peek_head(p->command_queue);
 14 
 15     if (cmd && p->cmd_bytes_written > 0) {
 16         char c = cmd->cmd[p->cmd_bytes_written - 1];
 17      /*如果收到了完整的一行cmd响应*/
 18         if ((c == '\r' || c == 26) &&
 19                 at_chat_handle_command_response(p, cmd, str))
 20             return;
 21     }
 22 
 23     if (at_chat_match_notify(p, str) == TRUE)
 24         return;
 25 
 26 done:
 27     /* No matches & no commands active, ignore line */
 28     g_free(str);
 29 }
 30 
 31 static gboolean at_chat_handle_command_response(struct at_chat *p,
 32                             struct at_command *cmd,
 33                             char *line)
 34 {
 35     int i;
 36     int size = sizeof(terminator_table) / sizeof(struct terminator_info);
 37     int hint;
 38     GSList *l;
 39 
 40    /*查找这一行响应是不是AT命令的结尾,如果是则将对应CMD从命令队列里删除*/
 41     for (i = 0; i < size; i++) {
 42         struct terminator_info *info = &terminator_table[i];
 43         if (check_terminator(info, line) &&
 44                 (p->terminator_blacklist & 1 << i) == 0) {
 45             at_chat_finish_command(p, info->success, line);
 46             return TRUE;
 47         }
 48     }
 49 
 50     for (l = p->terminator_list; l; l = l->next) {
 51         struct terminator_info *info = l->data;
 52         if (check_terminator(info, line)) {
 53             at_chat_finish_command(p, info->success, line);
 54             return TRUE;
 55         }
 56     }
 57 
 58     if (cmd->prefixes) {
 59         int i;
 60 
 61         for (i = 0; cmd->prefixes[i]; i++)
 62             if (g_str_has_prefix(line, cmd->prefixes[i]))
 63                 goto out;
 64 
 65         return FALSE;
 66     }
 67 
 68 /*...*/
 69 }
 70 
 71 static void at_chat_finish_command(struct at_chat *p, gboolean ok, char *final)
 72 {
 73    /*将发送的命令从发送队列中删除*/
 74     struct at_command *cmd = g_queue_pop_head(p->command_queue);
 75     GSList *response_lines;
 76 
 77     /* Cannot happen, but lets be paranoid */
 78     if (cmd == NULL)
 79         return;
 80 
 81     p->cmd_bytes_written = 0;
 82   /*  */
 83     if (g_queue_peek_head(p->command_queue))
 84         chat_wakeup_writer(p);
 85 
 86     response_lines = p->response_lines;
 87     p->response_lines = NULL;
 88   /*AT命令结束回调处理函数*/
 89     if (cmd->callback) {
 90         GAtResult result;
 91 
 92         response_lines = g_slist_reverse(response_lines);
 93 
 94         result.final_or_pdu = final;
 95         result.lines = response_lines;
 96 
 97         cmd->callback(ok, &result, cmd->user_data);
 98     }
 99 
100     g_slist_foreach(response_lines, (GFunc)g_free, NULL);
101     g_slist_free(response_lines);
102 
103     g_free(final);
104     at_command_destroy(cmd);
105 }

 5.总结

以上就是AT命令在GATChat中接收的过程,如果发现其中存在错误的话,欢迎指正。

 

 

转载于:https://www.cnblogs.com/zhx831/p/3167162.html

 类似资料: