oFono学习笔记——GATChat(2):发送AT命令

摘要:

本文主要描述了GAtChat如何发送AT命令的全过程

1. GAtChat AT命令发送接口

在GAtChat库当中,根据AT命令返回结果的不同,GAtChat定义了四种不同的发送接口:一般发送接口,表单发送接口,PDU表单发送接口以及等待提示发送接口。

 1 /*一般发送接口*/
 2 guint g_at_chat_send(GAtChat *chat, const char *cmd,
 3             const char **prefix_list, GAtResultFunc func,
 4             gpointer user_data, GDestroyNotify notify)
 5 {
 6     return at_chat_send_common(chat->parent, chat->group,
 7                     cmd, prefix_list, 0, NULL,
 8                     func, user_data, notify);
 9 }
10 
11 /*表单发送接口*/
12 guint g_at_chat_send_listing(GAtChat *chat, const char *cmd,
13                 const char **prefix_list,
14                 GAtNotifyFunc listing, GAtResultFunc func,
15                 gpointer user_data, GDestroyNotify notify)
16 {
17     if (listing == NULL)
18         return 0;
19 
20     return at_chat_send_common(chat->parent, chat->group,
21                     cmd, prefix_list, 0,
22                     listing, func, user_data, notify);
23 }
24 
25 /*PDU表单发送接口*/
26 guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
27                 const char **prefix_list,
28                 GAtNotifyFunc listing, GAtResultFunc func,
29                 gpointer user_data, GDestroyNotify notify)
30 {
31     if (listing == NULL)
32         return 0;
33 
34     return at_chat_send_common(chat->parent, chat->group,
35                     cmd, prefix_list,
36                     COMMAND_FLAG_EXPECT_PDU,
37                     listing, func, user_data, notify);
38 }
39 
40 /*等待提示发送接口*/
41 guint g_at_chat_send_and_expect_short_prompt(GAtChat *chat, const char *cmd,
42                         const char **prefix_list,
43                         GAtResultFunc func,
44                         gpointer user_data,
45                         GDestroyNotify notify)
46 {
47     return at_chat_send_common(chat->parent, chat->group,
48                     cmd, prefix_list,
49                     COMMAND_FLAG_EXPECT_SHORT_PROMPT,
50                     NULL, func, user_data, notify);
51 }

1.1 一般发送接口

应对绝大部分的AT命令。这类AT命令的特点是命令的回复比较简单。

比如:ATE0。关闭串口回显,这种命令只会返回OK或者ERROR。

1.2 表单发送接口

应对返回结果是表单类型的AT命令,这类AT命令的返回结果的特点是,返回的每一条表单结果都有一个固定的prefix(前缀)

比如:用AT+CPBR=1,99来读取电话本,命令的返回结果为:

AT+CPBR=1,99
+CPBR: 1,"931123456",129,"Ilkka"
+CPBR: 2,"9501234567",129,""
+CPBR: 4,"901234567",129,"Hesari"
OK

1.3 PDU表单发送接口

应对返回结果是表单并带有PDU数据的AT命令,这类AT命令的特点是返回结果不仅有固定的前缀,还有PDU信息

比如:利用AT+CMGL读取已经收到的短信,并以PDU方式显示出来。起返回结果是:

AT+CMGL=4
+CMGL: 1,0,,39
07911326040011F5240B911326880736F40000111081017362401654747A0E4ACF41F4329E0E6A97E7F3F0B90C8A01
+CMGL: 2,0,,39
07911326040011F5240B911326880736F40000111081017323401654747A0E4ACF41F4329E0E6A97E7F3F0B90C9201
OK

1.4 等待提示发送接口

应对的是AT命令发送过程中需要等待GSM/GPRS模块确认再继续发送的命令。

比如:利用AT+CMGS命令发送短信,当命令发出后,需要等待模块返回'>'确认后才能继续发送短信内容。

AT+CMGS=17
>
0891683108705505f011000b813120882624f700f1ff0361f118
+CMGS: 2
OK

2. at_chat_send_common分析

在上面说到的发送接口中,我们可以看到,四个接口都是对at_chat_send_common进行的一个封装。可见发送AT命令的核心就在这个函数中:

 1 static guint at_chat_send_common(struct at_chat *chat, guint gid,
 2                     const char *cmd,
 3                     const char **prefix_list,
 4                     guint flags,
 5                     GAtNotifyFunc listing,
 6                     GAtResultFunc func,
 7                     gpointer user_data,
 8                     GDestroyNotify notify)
 9 {
10     struct at_command *c;
11 
12     if (chat == NULL || chat->command_queue == NULL)
13         return 0;
14         
15     /*创建AT命令*/
16     c = at_command_create(gid, cmd, prefix_list, flags, listing, func,
17                 user_data, notify, FALSE);
18     if (c == NULL)
19         return 0;
20         
21     c->id = chat->next_cmd_id++;
22 
23     /*将创建好的AT命令添加到发送队尾*/
24     g_queue_push_tail(chat->command_queue, c);
25         
26     /*激活writer将AT命令发送给模块*/
27     if (g_queue_get_length(chat->command_queue) == 1)
28         chat_wakeup_writer(chat);
29 
30     return c->id;
31 }

通过分析这个函数我们可以知道AT命令是如何发送到BP中去的。首先,会创建一个AT命令结构体。如果结构体成功创建了,就把它添加到命令发送队列的尾部。这个命令发送队列,就是上一篇文章中提到的command_queue。最后,检查发送队列,如果队列中又且只有一个命令等待发送就激活writer将AT命令发送给BP,否则说明现在writer已经在激活状态,无需激活。可见command_queue的长度是激活writer的一个关键。

2.1 struct at_command

 1 struct at_command {
 2     char *cmd;
 3     char **prefixes;
 4     guint flags;
 5     guint id;
 6     guint gid;
 7     GAtResultFunc callback;
 8     GAtNotifyFunc listing;
 9     gpointer user_data;
10     GDestroyNotify notify;
11 };

这里对at_command中的字段做一些说明:

cmd存储AT命令
prefixesAT命令返回结果的前缀
flags
AT命令的返回类型,一般情况下为0。
当返回结果中包含PDU时,flags=COMMAND_FLAG_EXPECT_PDU。                 
当返回包含提示符时, flag=COMMAND_FLAG_EXPECT_SHORT_PROMPT。
id
AT命令的ID(1~(2^16 - 1)),用来唯一标识每一条命令。
当id=0时,说明这是一条weakup AT命令。
gidAT命令的组ID,表明该AT命令属于那一个GAtChat
callback一般AT命令返回结果的处理回调函数
listing表单AT命令的返回结果处理回调函数
user_data用于装载AT发送/返回的数据
notifyAT命令被GAtChat从队列中删除后的通知函数

3.chat_wakeup_writer

下面我们来分析writer是如何weakup。代码比较长,一下代码只截取重要的部分进行说明

gatchat.c

1 static gboolean can_write_data(gpointer data);
2 
3 static void chat_wakeup_writer(struct at_chat *chat)
4 {
5     g_at_io_set_write_handler(chat->io, can_write_data, chat);
6 }

gatio.c

 1 gboolean g_at_io_set_write_handler(GAtIO *io, GAtIOWriteFunc write_handler,
 2                     gpointer user_data)
 3 {
 4         /*...*/
 5     io->write_handler = write_handler;
 6     io->write_data = user_data;
 7 
 8     if (io->use_write_watch == TRUE)
 9         io->write_watch = g_io_add_watch_full(io->channel,
10                 G_PRIORITY_HIGH,
11                 G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
12                 can_write_data, io,
13                 write_watcher_destroy_notify);
14     else
15         io->write_watch = g_idle_add(call_blocking_read, io);
16 
17     return TRUE;
18 }
19 
20 static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
21                 gpointer data)
22 {
23     GAtIO *io = data;
24 
25     if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR))
26         return FALSE;
27 
28     if (io->write_handler == NULL)
29         return FALSE;
30 
31     return io->write_handler(io->write_data);
32 }

 当调用chat_wakeup_writer时,GAtChat会将具体的AT命令发送函数通过g_at_io_set_write_handler注册到GAtIO模块当中。在g_at_io_set_write_handler之中,gatio会向主事件循环中添加一个写监控(watch),当指定io口可以写的时候,系统会自动调用gatio.c中的can_write_data函数,通过这个函数调用,GAtChat所定义的AT命令发送函数。

3.1 can_write_data 分析

通过上面的分析,发送和AT命令发送相关的细节集中在gatchat.c当中的can_write_data之中。所以下面对这个函数的关键部分做简要分析:

 1 static gboolean can_write_data(gpointer data)
 2 {
 3     cmd = g_queue_peek_head(chat->command_queue);
 4 
 5     /*...*/
 6 
 7     if (chat->wakeup) {
 8         if (chat->wakeup_timer == NULL) {
 9             wakeup_first = TRUE;
10             chat->wakeup_timer = g_timer_new();
11 
12         } else if (g_timer_elapsed(chat->wakeup_timer, NULL) >
13                 chat->inactivity_time)
14             wakeup_first = TRUE;
15     }
16 
17     if (chat->cmd_bytes_written == 0 && wakeup_first == TRUE) {
18         cmd = at_command_create(0, chat->wakeup, none_prefix, 0,
19                     NULL, wakeup_cb, chat, NULL, TRUE);
20         if (cmd == NULL)
21             return FALSE;
22 
23         g_queue_push_head(chat->command_queue, cmd);
24 
25         len = strlen(chat->wakeup);
26 
27         chat->timeout_source = g_timeout_add(chat->wakeup_timeout,
28                         wakeup_no_response, chat);
29     }
30     /*...*/
31 
32     bytes_written = g_at_io_write(chat->io,
33                     cmd->cmd + chat->cmd_bytes_written,
34                     towrite);
35      /*...*/
36     /*
37      * If we're expecting a short prompt, set the hint for all lines
38      * sent to the modem except the last
39      */
40     if ((cmd->flags & COMMAND_FLAG_EXPECT_SHORT_PROMPT) &&
41             chat->cmd_bytes_written < len &&
42             chat->syntax->set_hint)
43         chat->syntax->set_hint(chat->syntax,
44                     G_AT_SYNTAX_EXPECT_SHORT_PROMPT);
45 
46     /* Full command submitted, update timer */
47     /*...*/
48 
49     return FALSE;
50 }    

当发现IO可写时,Chat会从command_queue中取出AT命令(但不删除),紧接着检查模块是否需要weakup,如果需要weakup操作,就自动生成一个weakup AT命令,然后将这条命令添加到发送队列的队头位置,优先发送weakup命令激活模块,否则发送一开始选中的AT命令。接下来进入真正的发送部分,将选定的AT命令通过g_at_io_write发送出去。最后,根据AT命令的返回类型,设置相对应的hint,完成AT命令的发送。

4.总结

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

 

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575898.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

archery集成ldap无法登陆

archery配置ldap之后,浏览器提示用户名或密码错误,请重新输入,去ldap日志查看,用户已经认证成功。 archery服务报错如下: [2022-06-16 14:00:03,221][MainThread:140070598219584][task_id:django_auth_ldap][backend.py:368][WARNING]- Caught LDAPError while authenti…

mysql存储过程输入参数拆分_一文看懂mysql数据库存储过程、函数、视图、触发器、表...

概述抽空总结一下mysql的一些概念性内容&#xff0c;涉及存储过程、函数、视图、触发器等。一、查看存储过程、函数、视图、触发器、表1、存储过程select * from mysql.proc where typePROCEDURE;show procedure status; show create procedure proc_name; //存储过程定义2、函…

文本框内容改变触发事件

input 在IE中有onchange事件&#xff0c;但是这个事件所表现的效果不是我们想要的&#xff0c;它所表现的效果为&#xff1a;当input内的内容发现更改时&#xff0c;并不会触发你所指定的方法&#xff08;函数&#xff09;&#xff0c;所以一般的人不用使用这个事件&#xff0c…

oracle vm发现无效设置_Oracle数据库编译失效对象相关命令总结大全,值得收藏

概述在日常数据库维护过程中&#xff0c;我们会发现数据库中一些对象(包Package、存储过程Procedure、函数Function、视图View、同义词.....)会失效,呈现无效状态(INVALID)。有时候需要定期检查数据库中存在哪些失效对象&#xff0c;对于存在异常的对象需要重新编译&#xff0c…

WCF-001:WCF的发布

随着“云”时代的到来&#xff0c;“云”已经无处不在了。什么是“云”&#xff0c;无非就是利用互联网强大的功能建立多个服务器&#xff0c;然后再利用互联网的传输数据的特点将数据从某个服务器中读取出来或者将你的数据上传上去。当然这个服务器不是一定就是传统意义的服务…

在线编辑_水墨-在线 Markdown 编辑器

水墨-在线 Markdown 编辑器基于 Spring-boot、FreeMarker、layui、Vditor 构建的一款在线 所见即所得的 Markdown 编辑器。水墨-在线 Markdown 编辑器。本人使用 Vditor 编辑器时日已久&#xff0c;眼看着其功能日益强大&#xff0c;特此基于 Vditor 构建一款 Web 编辑器&#…

(转载)mysql 用drop和delete方法删除用户的区别

&#xff08;转载&#xff09;http://hi.baidu.com/yymagento/item/56c3f6184bce8347e75e06db在学习drop方法删除用户时&#xff0c;按照书上讲的一直没操作成功&#xff0c;后来到网上查了点其他资料&#xff0c;才弄明白drop的方法&#xff0c;贴出来和大家分享一下。 &#…

退出出库复核是什么意思_细思极恐!为什么是黄晓明退出而不是李菲儿?因为女方是芒果艺人...

本文转载自&#xff1a;娱评人吴清功序言&#xff1a;《乘风破浪的姐姐》第二季即将接档《姐姐的爱乐之程》&#xff0c;于每周五晚上十点档播出。2021年1月5日&#xff0c;《乘风破浪的姐姐2》第一次公演举行&#xff0c;选手李菲儿和发起人黄晓明有亲密互动&#xff0c;李菲儿…

ie6 ie7下使用clear不能将浮动的元素换行问题

在主流浏览器中使用clear方法可以轻松完成浮动元素的换行。 例如&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.o…

传值类型_Java内存管理:Stackoverflow问答-Java是传值还是传引用(十一)

勿在流沙筑高台&#xff0c;出来混迟早要还的。做一个积极的人编码、改bug、提升自己我有一个乐园&#xff0c;面向编程&#xff0c;春暖花开&#xff01;本文导图&#xff1a;一、由一个提问引发的思考在Stack Overflow 看到这样一个问题&#xff1a;Is Java “pass-by-refere…

java位运算(转)

位移动运算符: <<表示左移, 左移一位表示原来的值乘2. 例如&#xff1a;3 <<2(3为int型) 1&#xff09;把3转换为二进制数字0000 0000 0000 0000 0000 0000 0000 0011&#xff0c; 2&#xff09;把该数字高位(左侧)的两个零移出&#xff0c;其他的数字都朝左平移2位…

android图片的缩放、圆角处理

android中图片缩放方法有三种&#xff1a;1&#xff0c;bitmapFactory&#xff1b;2&#xff0c;bitmapmetrix&#xff1b;3&#xff0c;thumbUtil 方法一&#xff1a;bitmapFactory&#xff1a; public static Bitmap resizeBitmapByFactory(String path, int w, int h) {Bitm…

Navicat for MySQL介绍以及Navicat for MySQL基本使用方法

Navicat for MySQL是一款流行的MySQL图形化管理工具。 如何使用Navicat for MySQL连接MySQL服务器&#xff1f; 1.单击“连接”按钮&#xff0c;出现“新建连接”窗口。 2.分别输入连接名、MySQL 服务器主机地址、服务 端口号、用户名和密码&#xff0c;单击“确定” 按钮。…

python正则表达式怎么用_Python如何使用正则表达式

1. Python与正则表达式开始查看python当前如何通过使用re模式来支持正则表达式&#xff0c;re模式在古老的Python1.5版本中引入&#xff0c;用于替换哪些已经过时的regex模块和regsub模块---这两个模块在Python2.5版本中被移除&#xff0c;并且此后导入这两个模块中的任意一个都…

MySQL小白飞速成长记-运算符篇

运算符连接表达式中的各个操作数&#xff0c;其作用是指明对操作数所进行的运算。常见的运算有数学运算&#xff0c;比较运算和逻辑运算。运算符可以更加灵活地使用表中地数据&#xff0c;常见的运算符类型&#xff1a;算术运算符&#xff0c;比较运算符和逻辑运算符。 上面说…

批处理通过字符串截取得到文件名

当有一个完整的文件路径时&#xff0c;如何截取文件名呢&#xff0c;可以使用 echo 命令。 如下代码&#xff1a; echo off set a"E:\Program Files\Image-Line\FL Studio 9\FL.exe" set b"E:\Program Files\Image-Line\FL Studio 9\Plugins\VST\Revitar20\Effe…

可以批量转modis投影_SNAP批量处理Sentinel2数据

Sentinel-2数据以其高时空分辨率获得了越来越多的应用&#xff0c;然而由于Sentinel-2数据空间分辨率高&#xff0c;光谱分辨率高&#xff0c;数据量也较Landsat数据大幅上升。好在ESA SNAP软件批处理功能也很强大&#xff0c;可以支撑起大数据量的应用。下面就介绍一下如何使用…

MySQL表结构管理

今天我们来介绍一下MySQL数据类型&#xff0c;任何数据库中数据表的每个字段都必须设定数据类型&#xff0c;合适的数据类型可以有效的节省存储空间&#xff0c;有效的提升数据的计算性能&#xff0c;那么常见的数据类型有哪些呢&#xff0c;一起来看看吧 类型分类 类型 取值…

清空文件夹里面的所有文件和文件夹

private void deletefileOrDic(System.IO.DirectoryInfo path){try{foreach (System.IO.DirectoryInfo d in path.GetDirectories()){d.Delete(true);}foreach (System.IO.FileInfo f in path.GetFiles()){f.Delete();}}catch (Exception ex){}} 转载于:https://www.cnblogs.co…

涡轮增压扫地机器人_帮着做家务,好坏在哪里,科沃斯T5扫地机器人

小家电中要说对自己家里最有用的&#xff0c;其中之一就是扫地机器人&#xff0c;自从三年多前开始用了扫地机器人后&#xff0c;家里的地面是大为改观&#xff0c;劳动强度大为下降&#xff0c;可谓朕心甚慰。从此之后&#xff0c;一发不可收拾&#xff0c;用过也有20台以上的…