合宙lua库详解-ril

简介

肝了这么久的讲解,一个评论和点赞都没有,没有一丝丝反馈,没有一丝丝赞扬。难受哦!!!
但是我还得肝,必须肝出一个赞。
如果大家能给点反馈,给点一键三连,我肝的更起劲。大家的评价是我前进最大的鼓舞。
好了,吐了这么多的苦水,我们接着来肝lua的库,本来今天我准备说一下短信的库的,但是短信的发送是基于AT指令的,用到了ril模块,所以我们先来说一下ril库。
ril库主要是通过虚拟通道与底层进行AT交互,什么是虚拟通道尼,可以理解为是两个队列,一个是发送,一个是接收,底层有数据的时候往接收队列里面填充并抛给lua一个消息,lua紧接着调用读队列的接口去读取数据。当lua需要发送数据的时候,就往发送队列丢数据,底层至于怎么处理不太清楚。(有可能发送一个消息给一个task。task去读取队列然后处理数据,这样就可以实现异步操作。)
下面看下lua具体是如何实现的:

注册

进入ril,拉倒最下面我们可以看到:

--注册“AT命令的虚拟串口数据接收消息”的处理函数
uart.on(uart.ATC, "receive", atcreader)

搜索一下uart.on的实现:

--- 注册串口事件的处理函数
-- @number id 串口ID: 1表示串口1,2表示串口2,uart.ATC表示虚拟AT口
-- @string event 串口事件:
-- "recieve"表示串口收到数据,注意:使用uart.setup配置串口时,第6个参数设置为nil或者0,收到数据时,才会产生"receive"事件
-- "sent"表示串口数据发送完成,注意:使用uart.setup配置串口时,第7个参数设置为1,调用uart.write接口发送数据之后,才会产生"sent"事件
-- @function[opt=nil] callback 串口事件的处理函数
-- @return nil
-- @usage
-- uart.on(1,"receive",rcvFnc)
-- uart.on(1,"sent",sentFnc)
uart.on = function(id, event, callback)
    if event == "receive" then
        uartReceiveCallbacks[id] = callback
    elseif event == "sent" then
        uartSentCallbacks[id] = callback
    end
end

注释写的已经很清楚了,uart.on的实现和前面我们说过的rtos.on的实现非常相似。主要功能就是注册底层消息回调。第一个参数是ID代表是哪个口,第二个参数event,主要是为了区分是哪个表。第三个参数callback就是相应的回调。
注意,可以看到callback是根据id进行映射的,如果设置相当的idcallback就会被覆盖。

接收指令

前面说过,开机就注册了一个回调atcreader,底层来数据了,在sys.run里面就会调用该回调进行处理,我们看下这里面做了什么吧。

--[[
函数名:atcreader
功能  :“AT命令的虚拟串口数据接收消息”的处理函数,当虚拟串口收到数据时,会走到此函数中
参数  :无
返回值:无
]]
local function atcreader()
    local s
	--这里是判断是透传模式
    if not transparentmode then readat = true end
    --循环读取虚拟串口收到的数据
    while true do
        --每次读取一行
        s = vread(uart.ATC, "*l", 0)
        if string.len(s) ~= 0 then
            if transparentmode then
                --透传模式下直接转发数据
                rcvfunc(s)
            else
                --非透传模式下处理收到的数据
                procatc(s)

                if app_rilcb ~=nil then app_rilcb(s)  end
            end
        else
            break
        end
    end
    if not transparentmode then
        readat = false
        --数据处理完以后继续执行AT命令发送
        sendat()
    end
end

上面的函数我们大体可以归纳为:

  1. 先判断是否是透传,不是就将readat置为true(我认为没这必要,本身就是消息处理,不存在被打断的情况,可能是为了兼容之前的版本)。
  2. 开始调用vread也就是uart.read循环读取数据直至没有数据退出。
  3. rcvfunc是通过setransparentmode设置的回调函数,procatc是处理函数。
  4. readat置为false,接着去sendat(查看发送缓存)。

透传我们这里不讲解,透传基本也不需要讲解,直接给上层回调处理的。

  1. 刚开始判断是否是多行字符串的格式,如果是就进行拼接并且中间加上\r\n,直至匹配到OK\r\n结束。
  2. 第二部分是判断是否有数据过滤器。所谓数据过滤器就是通过regUrc接口注册的主动上报处理回调。
  3. 第三部分主要判断指令的返回类型cmdtype,这个类型是有字符串,多行,数字啊等等.
    这个类型是在sendat的时候调用getcmd,在RILCMD表有注册相应的类型,通过AT指令的前缀进行匹配的。这个前缀是通过
    local head = string.match(cmd, "AT([%+%*%^]*%u+)")进行匹配获取的。
    如果RILCMD表中没有注册相应的AT指令,就赋值为NORESULT

发送指令

发送指令就是调用底层的一个接口,像通道里面发送数据,看具体的实现函数sendat

local function sendat()
    --AT通道未准备就绪、正在读取虚拟串口数据、有AT命令在执行或者队列无命令、正延时发送某条AT
    if not radioready or readat or currcmd ~= nil or delaying then
        return
    end

    local item

    while true do
        --队列无AT命令
        if #cmdqueue == 0 then
            return
        end
        --读取第一条命令
        item = table.remove(cmdqueue, 1)
        --解析命令
        getcmd(item)
        --需要延迟发送
        if curdelay then
            --启动延迟发送定时器
            sys.timerStart(delayfunc, curdelay)
            --清除全局变量
            currcmd, currarg, currsp, curdelay, cmdhead, cmdtype, rspformt = nil
            item.delay = nil
            --设置延迟发送标志
            delaying = true
            --把命令重新插入命令队列的队首
            table.insert(cmdqueue, 1, item)
            return
        end

        if currcmd ~= nil then
            break
        end
    end
    --启动AT命令应答超时定时器
    sys.timerStart(atimeout, TIMEOUT)

    log.info("ril.sendat", currcmd)
    --向虚拟串口中发送AT命令
    if currcmd:match("^AT%+POC=") then
        vwrite(uart.ATC, currcmd .. "\r\n")
    else
        vwrite(uart.ATC, currcmd .. "\r")
    end
end

从上面可以看出发送的主要步骤有:

  1. 移出cmdqueue表的第一个指令。
  2. 解析指令getcmd,主要是赋值--当前正在执行的AT命令,参数,反馈回调,延迟执行时间,命令头,类型,反馈格式 local currcmd, currarg, currsp, curdelay, cmdhead, cmdtype, rspformt
  3. 如果需要延迟发送就追加到发送缓存中cmdqueue,这个表在接收的时候也说过
  4. 启动超时定时器,调用vwrite进行发送。

但是我们上层一般调用的函数是:ril.request

--- 发送AT命令到底层软件
-- @param cmd   AT命令内容
-- @param arg   AT命令参数,例如AT+CMGS=12命令执行后,接下来会发送此参数;AT+CIPSEND=14命令执行后,接下来会发送此参数
-- @param onrsp AT命令应答的处理函数,只是当前发送的AT命令应答有效,处理之后就失效了
-- @param delay 延时delay毫秒后,才发送此AT命令
-- @return 无
-- @usage ril.request("AT+CENG=1,1")
-- @usage ril.request("AT+CRSM=214,28539,0,0,12,\"64f01064f03064f002fffff\"", nil, crsmResponse)
function request(cmd, arg, onrsp, delay)
    if transparentmode then return end
    --插入缓冲队列
    if arg or onrsp or delay or formt then
        table.insert(cmdqueue, {cmd = cmd, arg = arg, rsp = onrsp, delay = delay})
    else
        table.insert(cmdqueue, cmd)
    end
    --执行AT命令发送
    sendat()
end

可以看出这个函数主要功能也就是将一些参数插入到cmdqueue发送缓存中,如果需要回调或者一些其它参数的,则传入表,否则直接传入指令。
最后还是调用sendat,进行AT指令的发送处理。


至此,ril库的大概逻辑已经说完了,有问题的可以留言讨论

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值