摘要:
本文主要讲述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中接收的过程,如果发现其中存在错误的话,欢迎指正。