Просмотр исходного кода

Merge branch 'master' of https://gitee.com/openLuat/LuatOS

alienwalker 5 лет назад
Родитель
Сommit
ac1fccf6e9

+ 2 - 1
README.md

@@ -78,7 +78,8 @@ sys.run()
 
 ## 免费服务
 
-* [NetLab](https://netlab.vue2.cn) TCP/UDP透传调试,公网IP, HEX值收发, Tab式多客户端
+* [NetLab](https://netlab.luatos.io/index.html) TCP/UDP透传调试,公网IP, HEX值收发, Tab式多客户端. [备用地址](https://netlab.luatos.io/index.html)
+* [DevLog](udp://devlog.luatos.io:9072) 设备日志记录,格式兼容errDump.lua 查看日志请登录LuatOS官网.
 
 ## 更多项目
 

+ 274 - 0
bsp/air302/lib/mqtt2.lua

@@ -0,0 +1,274 @@
+--[[
+异步MQTT客户端
+1. 自动重连
+2. 异步收发信息
+
+暂不支持的特性:
+1. qos 2的消息不被支持,以后也不会添加
+2. 不支持取消订阅(也许会添加,也许不会)
+
+用法请参考demo
+
+]]
+
+-- MQTT 指令id
+local CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+local CLIENT_COMMAND_TIMEOUT = 60000
+
+local packCONNECT = mqttcore.packCONNECT
+local packPUBLISH = mqttcore.packPUBLISH
+local packSUBSCRIBE = mqttcore.packSUBSCRIBE
+local packACK = mqttcore.packACK
+local packZeroData = mqttcore.packZeroData
+
+
+local mclog = log.debug
+
+local function unpack(s) -- TODO 做成纯C实现
+    if #s < 2 then return end
+    --mclog("mqtt", "unpack", #s, string.toHex(string.sub(s, 1, 50)))
+
+    -- read remaining length
+    local len = 0
+    local multiplier = 1
+    local pos = 2
+
+    repeat
+        if pos > #s then return end
+        local digit = string.byte(s, pos)
+        len = len + ((digit % 128) * multiplier)
+        multiplier = multiplier * 128
+        pos = pos + 1
+    until digit < 128
+
+    if #s < len + pos - 1 then return end
+
+    local header = string.byte(s, 1)
+
+    --local packet = {id = (header - (header % 16)) / 16, dup = ((header % 16) - ((header % 16) % 8)) / 8, qos = bit.band(header, 0x06) / 2, retain = bit.band(header, 0x01)}
+    local packet = {id = (header - (header % 16)) >> 4, dup = ((header % 16) - ((header % 16) % 8)) >> 3, qos = (header & 0x06) >> 1, retain = (header & 0x01)}
+    local nextpos
+
+    if packet.id == CONNACK then
+        nextpos, packet.ackFlag, packet.rc = pack.unpack(s, "bb", pos)
+    elseif packet.id == PUBLISH then
+        nextpos, packet.topic = pack.unpack(s, ">P", pos)
+        if packet.qos > 0 then
+            nextpos, packet.packetId = pack.unpack(s, ">H", nextpos)
+        end
+        packet.payload = string.sub(s, nextpos, pos + len - 1)
+    elseif packet.id ~= PINGRESP then
+        if len >= 2 then
+            nextpos, packet.packetId = pack.unpack(s, ">H", pos)
+        else
+            packet.packetId = 0
+        end
+    end
+
+    return packet, pos + len
+end
+
+local mqtt2 = {}
+
+local mqttc = {}
+mqttc.__index = mqttc
+
+function mqtt2.new(clientId, keepAlive, username, password, cleanSession, host, port, topics, cb, ckey)
+    local c = {
+        clientId = clientId,
+        keepAlive = keepAlive or 300,
+        username = username or "",
+        password = password or "",
+        cleanSession = cleanSession == nil and 1 or 0,
+        host = host,
+        port = port,
+        lping = 0,
+        stat = 0, -- 状态 0, 未连接, 1 已连接成功
+        nextid = 0, -- pkg的ID
+        running = false,
+        inpkgs = {},
+        outpkgs = {},
+        buff = "",
+        topics = topics or {},
+        cb = cb,
+        ckey = ckey or ""
+    }
+    if c.ckey == "" then c.ckey = "mqtt_" .. tostring(c) end
+    --mclog("mqtt", "MQTT Client Key", c.ckey)
+    setmetatable(c, mqttc)
+    return c
+end
+
+-- 内部方法, 用于获取下一个pkg的id
+function mqttc:genId()
+    self.nextid = self.nextid == 65535 and 1 or (self.nextid + 1)
+    --mclog("mqtt", "next packet id", self.nextid)
+    return self.nextid
+end
+
+-- 内部方法,用于处理待处理的数据包
+function mqttc:handle(netc)
+    local mc = self
+    -- 先处理服务器下发的数据包
+    if #mc.inpkgs > 0 then
+        --mclog("mqtt", "inpkgs count", #mc.inpkgs)
+        while 1 do
+            local pkg = table.remove( mc.inpkgs, 1 )
+            if pkg == nil then
+                break
+            end
+            -- 处理服务器下发的包
+            --mclog("mqtt", "handle pkg", json.encode(pkg))
+            if pkg.id == CONNACK then
+                mc.stat = 1
+                mc.lping = os.time()
+                --mclog("mqtt", "GOT CONNACK")
+                for k, v in pairs(mc.topics) do
+                    --mclog("mqtt", "sub topics", json.encode(mc.topics))
+                    netc:send(packSUBSCRIBE(0, mc:genId(), mc.topics))
+                    break
+                end
+            elseif pkg.id == PUBACK then
+                --mclog("mqtt", "GOT PUBACK")
+                sys.publish(mc.ckey .. "PUBACK")
+            elseif pkg.id == SUBACK then
+                --mclog("mqtt", "GOT SUBACK")
+                sys.publish(mc.ckey .. "SUBACK")
+            elseif pkg.id == PINGRESP then
+                mc.lping = os.time()
+                --mclog("mqtt", "GOT PINGRESP", mc.lping)
+            elseif pkg.id == UNSUBACK then
+                --mclog("mqtt", "GOT UNSUBACK")
+            elseif pkg.id == DISCONNECT then
+                --mclog("mqtt", "GOT DISCONNECT")
+            elseif pkg.id == PUBLISH then
+                --mclog("mqtt", "GOT PUBLISH", pkg.topic, pkg.qos)
+                if pkg.packetId then
+                    -- 发送PUBACK
+                    --mclog("mqtt", "send back PUBACK")
+                    table.insert( mc.outpkgs, packACK(PUBACK, 0, pkg.packetId))
+                end
+                if mc.cb then
+                    --mclog("mqtt", "Callback for PUBLISH", mc.cb)
+                    mc.cb(pkg)
+                end
+            end
+        end
+    end
+    -- 处理需要上报的数据包
+    if #mc.outpkgs > 0 then
+        --mclog("mqtt", "outpkgs count", #mc.outpkgs)
+        while 1 do
+            local buff = table.remove( mc.outpkgs, 1)
+            if buff == nil then
+                break
+            end
+            --mclog("mqtt", "netc send", buff:toHex())
+            netc:send(buff)
+        end
+    end
+    -- 是否需要发心跳
+    if mc.lping > 0 and os.time() - mc.lping > mc.keepAlive * 0.75 then
+        --mclog("mqtt", "time for ping", mc.lping)
+        mc.lping = os.time()
+        netc:send(packZeroData(PINGREQ)) -- 发送心跳包
+    end
+end
+
+-- 启动mqtt task, 要么在task里面执行, 要么新建一个task执行本方法
+function mqttc:run()
+    local mc = self
+    mc.running = true
+    while mc.running do
+        if socket.isReady() then
+            -- 先复位全部临时对象
+            mc.buff = ""
+            mc.inpkgs = {}
+            mc.outpkgs = {}
+            -- 建立socket对象
+            --mclog("mqtt", "try connect")
+            local netc = socket.tcp()
+            netc:host(mc.host)
+            netc:port(mc.port)
+            netc:on("connect", function(id, re)
+                --mclog("mqtt", "connect", id , re)
+                if re then
+                    -- 发送CONN包
+                    table.insert(mc.outpkgs, packCONNECT(mc.clientId, mc.keepAlive, mc.username, mc.password, mc.cleanSession, {topic="",payload="",qos=0,retain=0,flag=0}))
+                    sys.publish(mc.ckey)
+                end
+            end)
+            netc:on("recv", function(id, data)
+                --mclog("mqtt", "recv", id , data:sub(1, 10):toHex())
+                mc.buff = mc.buff .. data
+                while 1 do
+                    local packet, nextpos = unpack(mc.buff)
+                    mc.buff = mc.buff:sub(nextpos)
+                    if not packet then
+                        if packet > 4096 then
+                            log.warn("mqtt", "packet is too big!!!")
+                            netc:close()
+                        end
+                        break
+                    else
+                        --mclog("mqtt", "recv new pkg", json.encode(packet))
+                        table.insert( mc.inpkgs, packet)
+                        if #mc.buff < 2 then
+                            break
+                        end
+                    end
+                end
+                if #mc.inpkgs > 0 then
+                    sys.publish(mc.ckey)
+                end
+            end)
+            if netc:start() == 0 then
+                --mclog("mqtt", "start success")
+                local endTopic = "NETC_END_" .. netc:id()
+                while (netc:closed()) == 0 do
+                    mc:handle(netc)
+                    sys.waitUntil({endTopic, mc.ckey}, 30000)
+                    if not mc.running then netc:close() end
+                    --mclog("mqtt", "handle/timeout/ping", (netc:closed()))
+                end
+            end
+            -- 清理socket上下文
+            mclog("mqtt", "clean up")
+            netc:clean()
+            netc:close()
+            -- 将所有状态复位
+            mc.stat = 0
+
+            mclog("mqtt", "wait 5s for next loop")
+            sys.wait(5*1000) -- TODO 使用级数递增进行延时
+        else
+            sys.wait(1000)
+        end
+    end
+    -- 线程退出, 只可能是用户主动shutdown
+    mclog("mqtt", self.ckey, "exit")
+end
+
+-- 订阅topic, table形式
+function mqttc:sub(topics)
+    table.insert(self.outpkgs, packSUBSCRIBE(0, self:genId(), topics))
+    sys.publish(self.ckey)
+    return sys.waitUntil(self.ckey .. "SUBACK", 30000)
+end
+
+-- 上报数据
+function mqttc:pub(topic, qos, payload)
+    -- local function packPUBLISH(dup, qos, retain, packetId, topic, payload)
+    table.insert(self.outpkgs, packPUBLISH(0, qos, 0, qos and self:genId() or 0, topic, payload))
+    sys.publish(self.ckey)
+    if qos then
+        return sys.waitUntil(self.ckey .. "PUBACK", 30000)
+    end
+end
+
+function mqttc:shutdown()
+    self.running = 0
+    sys.publish(self.ckey)
+end
+
+return mqtt2

+ 110 - 0
bsp/air640w/demo/73.mqtt2/main.lua

@@ -0,0 +1,110 @@
+--[[
+demo说明:
+1. 演示wifi联网操作
+2. 演示长连接操作
+3. 演示简易的网络状态灯
+]]
+_G.sys = require("sys")
+_G.mqtt2 = require("mqtt2")
+_G.mine = require("my_demo")
+
+log.info("main", "simple mqtt2 demo")
+
+-- //////////////////////////////////////////////////////////////////////////////////////
+-- wifi 相关的代码
+if wlan ~= nil then
+    log.info("mac", wlan.get_mac())
+    local ssid = mine.wifi_ssid
+    local password = mine.wifi_passwd
+    -- 方式1 直接连接, 简单快捷
+    wlan.connect(ssid, password) -- 直接连
+    -- 方式2 先扫描,再连接. 例如根据rssi(信号强度)的不同, 择优选择ssid
+    -- sys.taskInit(function()
+    --     wlan.scan()
+    --     sys.waitUntil("WLAN_SCAN_DONE", 30000)
+    --     local re = wlan.scan_get_info()
+    --     log.info("wlan", "scan done", #re)
+    --     for i in ipairs(re) do
+    --         log.info("wlan", "info", re[i].ssid, re[i].rssi)
+    --     end
+    --     log.info("wlan", "try connect to wifi")
+    --     wlan.connect(ssid, password)
+    --     sys.waitUntil("WLAN_READY", 15000)
+    --     log.info("wifi", "self ip", socket.ip())
+    -- end)
+    -- 方法3 airkiss配网, 可参考 app/playit/main.lua
+end
+
+-- airkiss.auto(27) -- 预留的功能,未完成 
+-- //////////////////////////////////////////////////////////////////////////////////////
+
+--- 从这里开始, 代码与具体网络无关
+
+-- 联网后自动同步时间
+-- sys.subscribe("NET_READY", function ()
+--     log.info("net", "!!! network ready event !!! send ntp")
+--     sys.taskInit(function()
+--         sys.wait(2000)
+--         socket.ntpSync()
+--     end)
+-- end)
+
+gpio.setup(21, 0)
+_G.use_netled = 1 -- 启用1, 关闭0
+sys.taskInit(function()
+    while 1 do
+        --log.info("wlan", "ready?", wlan.ready())
+        if socket.isReady() then
+            --log.info("netled", "net ready, slow")
+            gpio.set(21, 1 * use_netled)
+            sys.wait(1900)
+            gpio.set(21, 0)
+            sys.wait(100)
+        else
+            --log.info("netled", "net not ready, fast")
+            gpio.set(21, 1 * use_netled)
+            sys.wait(100)
+            gpio.set(21, 0)
+            sys.wait(100)
+        end
+        --log.info("mem", rtos.meminfo())
+    end
+end)
+
+-- 声明几个topic
+
+local host, port, clientId = "lbsmqtt.airm2m.com", 1884, wlan.getMac():lower()
+
+local topic_req = string.format("/device/%s/req", clientId)
+local topic_report = string.format("/device/%s/report", clientId)
+local topic_resp = string.format("/device/%s/resp", clientId)
+
+uart.setup(1)
+uart.on(1, "recv", function(id, len)
+    local data = uart.read(1, 1024)
+    if _G.mqttc and _G.mqttc.stat == 1 then
+        sys.taskInit(function()
+            _G.mqttc:pub(topic_resp, 1, data)
+        end)
+    end
+end)
+
+sys.taskInit(function()
+
+    local sub_topics = {}
+    sub_topics[topic_req] = 1
+
+    _G.mqttc = mqtt2.new(clientId, 300, "wendal", "123456", 1, host, port, sub_topics, function(pkg)
+        log.info("mqtt", "Oh", json.encode(pkg))
+    end, "mqtt_airm2m")
+
+    --log.info("mqtt", json.encode(mqttc))
+
+    while not socket.isReady() do sys.waitUntil("NET_READY", 1000) end
+    sys.wait(3000)
+    log.info("go", "GoGoGo")
+    mqttc:run() -- 会一直阻塞在这里
+end)
+
+
+sys.run()

+ 274 - 0
bsp/air640w/lib/mqtt2.lua

@@ -0,0 +1,274 @@
+--[[
+异步MQTT客户端
+1. 自动重连
+2. 异步收发信息
+
+暂不支持的特性:
+1. qos 2的消息不被支持,以后也不会添加
+2. 不支持取消订阅(也许会添加,也许不会)
+
+用法请参考demo
+
+]]
+
+-- MQTT 指令id
+local CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+local CLIENT_COMMAND_TIMEOUT = 60000
+
+local packCONNECT = mqttcore.packCONNECT
+local packPUBLISH = mqttcore.packPUBLISH
+local packSUBSCRIBE = mqttcore.packSUBSCRIBE
+local packACK = mqttcore.packACK
+local packZeroData = mqttcore.packZeroData
+
+
+local mclog = log.debug
+
+local function unpack(s) -- TODO 做成纯C实现
+    if #s < 2 then return end
+    --mclog("mqtt", "unpack", #s, string.toHex(string.sub(s, 1, 50)))
+
+    -- read remaining length
+    local len = 0
+    local multiplier = 1
+    local pos = 2
+
+    repeat
+        if pos > #s then return end
+        local digit = string.byte(s, pos)
+        len = len + ((digit % 128) * multiplier)
+        multiplier = multiplier * 128
+        pos = pos + 1
+    until digit < 128
+
+    if #s < len + pos - 1 then return end
+
+    local header = string.byte(s, 1)
+
+    --local packet = {id = (header - (header % 16)) / 16, dup = ((header % 16) - ((header % 16) % 8)) / 8, qos = bit.band(header, 0x06) / 2, retain = bit.band(header, 0x01)}
+    local packet = {id = (header - (header % 16)) >> 4, dup = ((header % 16) - ((header % 16) % 8)) >> 3, qos = (header & 0x06) >> 1, retain = (header & 0x01)}
+    local nextpos
+
+    if packet.id == CONNACK then
+        nextpos, packet.ackFlag, packet.rc = pack.unpack(s, "bb", pos)
+    elseif packet.id == PUBLISH then
+        nextpos, packet.topic = pack.unpack(s, ">P", pos)
+        if packet.qos > 0 then
+            nextpos, packet.packetId = pack.unpack(s, ">H", nextpos)
+        end
+        packet.payload = string.sub(s, nextpos, pos + len - 1)
+    elseif packet.id ~= PINGRESP then
+        if len >= 2 then
+            nextpos, packet.packetId = pack.unpack(s, ">H", pos)
+        else
+            packet.packetId = 0
+        end
+    end
+
+    return packet, pos + len
+end
+
+local mqtt2 = {}
+
+local mqttc = {}
+mqttc.__index = mqttc
+
+function mqtt2.new(clientId, keepAlive, username, password, cleanSession, host, port, topics, cb, ckey)
+    local c = {
+        clientId = clientId,
+        keepAlive = keepAlive or 300,
+        username = username or "",
+        password = password or "",
+        cleanSession = cleanSession == nil and 1 or 0,
+        host = host,
+        port = port,
+        lping = 0,
+        stat = 0, -- 状态 0, 未连接, 1 已连接成功
+        nextid = 0, -- pkg的ID
+        running = false,
+        inpkgs = {},
+        outpkgs = {},
+        buff = "",
+        topics = topics or {},
+        cb = cb,
+        ckey = ckey or ""
+    }
+    if c.ckey == "" then c.ckey = "mqtt_" .. tostring(c) end
+    --mclog("mqtt", "MQTT Client Key", c.ckey)
+    setmetatable(c, mqttc)
+    return c
+end
+
+-- 内部方法, 用于获取下一个pkg的id
+function mqttc:genId()
+    self.nextid = self.nextid == 65535 and 1 or (self.nextid + 1)
+    --mclog("mqtt", "next packet id", self.nextid)
+    return self.nextid
+end
+
+-- 内部方法,用于处理待处理的数据包
+function mqttc:handle(netc)
+    local mc = self
+    -- 先处理服务器下发的数据包
+    if #mc.inpkgs > 0 then
+        --mclog("mqtt", "inpkgs count", #mc.inpkgs)
+        while 1 do
+            local pkg = table.remove( mc.inpkgs, 1 )
+            if pkg == nil then
+                break
+            end
+            -- 处理服务器下发的包
+            --mclog("mqtt", "handle pkg", json.encode(pkg))
+            if pkg.id == CONNACK then
+                mc.stat = 1
+                mc.lping = os.time()
+                --mclog("mqtt", "GOT CONNACK")
+                for k, v in pairs(mc.topics) do
+                    --mclog("mqtt", "sub topics", json.encode(mc.topics))
+                    netc:send(packSUBSCRIBE(0, mc:genId(), mc.topics))
+                    break
+                end
+            elseif pkg.id == PUBACK then
+                --mclog("mqtt", "GOT PUBACK")
+                sys.publish(mc.ckey .. "PUBACK")
+            elseif pkg.id == SUBACK then
+                --mclog("mqtt", "GOT SUBACK")
+                sys.publish(mc.ckey .. "SUBACK")
+            elseif pkg.id == PINGRESP then
+                mc.lping = os.time()
+                --mclog("mqtt", "GOT PINGRESP", mc.lping)
+            elseif pkg.id == UNSUBACK then
+                --mclog("mqtt", "GOT UNSUBACK")
+            elseif pkg.id == DISCONNECT then
+                --mclog("mqtt", "GOT DISCONNECT")
+            elseif pkg.id == PUBLISH then
+                --mclog("mqtt", "GOT PUBLISH", pkg.topic, pkg.qos)
+                if pkg.packetId then
+                    -- 发送PUBACK
+                    --mclog("mqtt", "send back PUBACK")
+                    table.insert( mc.outpkgs, packACK(PUBACK, 0, pkg.packetId))
+                end
+                if mc.cb then
+                    --mclog("mqtt", "Callback for PUBLISH", mc.cb)
+                    mc.cb(pkg)
+                end
+            end
+        end
+    end
+    -- 处理需要上报的数据包
+    if #mc.outpkgs > 0 then
+        --mclog("mqtt", "outpkgs count", #mc.outpkgs)
+        while 1 do
+            local buff = table.remove( mc.outpkgs, 1)
+            if buff == nil then
+                break
+            end
+            --mclog("mqtt", "netc send", buff:toHex())
+            netc:send(buff)
+        end
+    end
+    -- 是否需要发心跳
+    if mc.lping > 0 and os.time() - mc.lping > mc.keepAlive * 0.75 then
+        --mclog("mqtt", "time for ping", mc.lping)
+        mc.lping = os.time()
+        netc:send(packZeroData(PINGREQ)) -- 发送心跳包
+    end
+end
+
+-- 启动mqtt task, 要么在task里面执行, 要么新建一个task执行本方法
+function mqttc:run()
+    local mc = self
+    mc.running = true
+    while mc.running do
+        if socket.isReady() then
+            -- 先复位全部临时对象
+            mc.buff = ""
+            mc.inpkgs = {}
+            mc.outpkgs = {}
+            -- 建立socket对象
+            --mclog("mqtt", "try connect")
+            local netc = socket.tcp()
+            netc:host(mc.host)
+            netc:port(mc.port)
+            netc:on("connect", function(id, re)
+                --mclog("mqtt", "connect", id , re)
+                if re then
+                    -- 发送CONN包
+                    table.insert(mc.outpkgs, packCONNECT(mc.clientId, mc.keepAlive, mc.username, mc.password, mc.cleanSession, {topic="",payload="",qos=0,retain=0,flag=0}))
+                    sys.publish(mc.ckey)
+                end
+            end)
+            netc:on("recv", function(id, data)
+                --mclog("mqtt", "recv", id , data:sub(1, 10):toHex())
+                mc.buff = mc.buff .. data
+                while 1 do
+                    local packet, nextpos = unpack(mc.buff)
+                    mc.buff = mc.buff:sub(nextpos)
+                    if not packet then
+                        if packet > 4096 then
+                            log.warn("mqtt", "packet is too big!!!")
+                            netc:close()
+                        end
+                        break
+                    else
+                        --mclog("mqtt", "recv new pkg", json.encode(packet))
+                        table.insert( mc.inpkgs, packet)
+                        if #mc.buff < 2 then
+                            break
+                        end
+                    end
+                end
+                if #mc.inpkgs > 0 then
+                    sys.publish(mc.ckey)
+                end
+            end)
+            if netc:start() == 0 then
+                --mclog("mqtt", "start success")
+                local endTopic = "NETC_END_" .. netc:id()
+                while (netc:closed()) == 0 do
+                    mc:handle(netc)
+                    sys.waitUntil({endTopic, mc.ckey}, 30000)
+                    if not mc.running then netc:close() end
+                    --mclog("mqtt", "handle/timeout/ping", (netc:closed()))
+                end
+            end
+            -- 清理socket上下文
+            mclog("mqtt", "clean up")
+            netc:clean()
+            netc:close()
+            -- 将所有状态复位
+            mc.stat = 0
+
+            mclog("mqtt", "wait 5s for next loop")
+            sys.wait(5*1000) -- TODO 使用级数递增进行延时
+        else
+            sys.wait(1000)
+        end
+    end
+    -- 线程退出, 只可能是用户主动shutdown
+    mclog("mqtt", self.ckey, "exit")
+end
+
+-- 订阅topic, table形式
+function mqttc:sub(topics)
+    table.insert(self.outpkgs, packSUBSCRIBE(0, self:genId(), topics))
+    sys.publish(self.ckey)
+    return sys.waitUntil(self.ckey .. "SUBACK", 30000)
+end
+
+-- 上报数据
+function mqttc:pub(topic, qos, payload)
+    -- local function packPUBLISH(dup, qos, retain, packetId, topic, payload)
+    table.insert(self.outpkgs, packPUBLISH(0, qos, 0, qos and self:genId() or 0, topic, payload))
+    sys.publish(self.ckey)
+    if qos then
+        return sys.waitUntil(self.ckey .. "PUBACK", 30000)
+    end
+end
+
+function mqttc:shutdown()
+    self.running = 0
+    sys.publish(self.ckey)
+end
+
+return mqtt2

+ 41 - 1
bsp/air640w/rtt/applications/luat_init_w60x.c

@@ -3,22 +3,62 @@
 #include "luat_msgbus.h"
 #include "luat_timer.h"
 #include "luat_gpio.h"
+#include "luat_fs.h"
 
 #include "rtthread.h"
 #include <rtdevice.h>
 
 #ifdef RT_USING_WIFI
 #include "wlan_mgnt.h"
+#endif
 
 #define DBG_TAG           "w60x.init"
 #define DBG_LVL           DBG_LOG
 #include <rtdbg.h>
 
 #ifdef BSP_USING_WM_LIBRARIES
+
+static int w60x_read_cfg(void *buff, int len) {
+  int fd = luat_fs_fopen("/wlan.cfg", "rb");
+  if (fd) {
+    luat_fs_fread(buff, 1, len, fd);
+    luat_fs_fclose(fd);
+    return len;
+  }
+  return 0;
+};
+static int w60x_get_len(void) {
+  return luat_fs_fsize("/wlan.cfg");
+};
+static int w60x_write_cfg(void *buff, int len) {
+  int fd = luat_fs_fopen("/wlan.cfg", "w");
+  if (fd) {
+    luat_fs_fwrite(buff, 1, len, fd);
+    luat_fs_fclose(fd);
+    return len;
+  }
+  return 0;
+};
+
+static struct rt_wlan_cfg_ops cfg_ops = {
+  w60x_read_cfg,
+  w60x_get_len,
+  w60x_write_cfg
+};
+
+
+static rt_err_t w600_bt(void *context) {
+  rt_kprintf("\r\nFUCK!!\r\n");
+  return 0;
+} 
 static int rtt_w60x_init() {
+  #ifdef RT_USING_WIFI
   rt_wlan_set_mode("wlan0", RT_WLAN_STATION);
+  rt_wlan_cfg_set_ops(&cfg_ops);
+  rt_wlan_cfg_cache_refresh();
+  #endif
+  rt_hw_exception_install(w600_bt);
   return RT_EOK;
 }
 INIT_COMPONENT_EXPORT(rtt_w60x_init);
 #endif
-#endif

+ 1 - 0
lua/include/llimits.h

@@ -305,6 +305,7 @@ typedef unsigned long Instruction;
 /*
 ** macro to control inclusion of some hard tests on stack reallocation
 */
+#define HARDSTACKTESTS
 #if !defined(HARDSTACKTESTS)
 #define condmovestack(L,pre,pos)	((void)0)
 #else

+ 4 - 0
lua/src/lauxlib.c

@@ -558,6 +558,10 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
 
 LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
   if (l > 0) {  /* avoid 'memcpy' when 's' can be NULL */
+    if(l>100)
+    {
+      lua_gc(B->L, LUA_GCCOLLECT, 0);
+    }
     char *b = luaL_prepbuffsize(B, l);
     memcpy(b, s, l * sizeof(char));
     luaL_addsize(B, l);

+ 85 - 12
lua/src/lstrlib.c

@@ -1616,28 +1616,101 @@ static int str_toValue (lua_State *L) {
   return 2;
 }
 
+/*
+  将字符串进行url编码转换
+  @api string.urlEncode("123 abc")
+  @string 需要转换的字符串
+  @int	mode:url编码的转换标准,
+  			-1:自定义标准.为-1时,才会有后面的space和str_check
+  			 0:默认标准php
+  			 1:RFC3986标准,和默认的相比就是' '的转换方式不一样
+  			 这个参数不存在,按0:默认标准php处理
+  @int	space:' '空格的处理方式
+  			 0:' '转化为'+'
+  			 1:' '转换为"%20"
+  @string	str_check:不需要转换的字符,组成的字符串
+  @return string 返回转换后的字符串
+  @usage
+  -- 将字符串进行url编码转换
+  log.info(string.urlEncode("123 abc+/"))			-->> "123+abc%2B%2F"
+  
+  log.info(string.urlEncode("123 abc+/",1))			-->> "123%20abc%2B%2F"
+  
+  log.info(string.urlEncode("123 abc+/",-1,1,"/"))	-->> "123%20abc%2B/"
+  log.info(string.urlEncode("123 abc+/",-1,0,"/"))	-->> "123+abc%2B/"
+  log.info(string.urlEncode("123 abc+/",-1,0,"/ "))	-->> "123 abc%2B/"
+*/
 static int str_urlEncode (lua_State *L) {
-  size_t len;
+  int argc = lua_gettop(L);
+  int mode = 0;		//转换模式,-1:自定义标准,0:默认标准php,1:RFC3986标准,和默认的相比就是' '的转换方式不一样
+  int space = 0;	//0:' '转化为'+', 1:' '转换为"%20"
+  size_t len_check = 0;
+  const char *str_check = NULL;		//不需要转换的字符
+  size_t len = 0;
   const char *str = luaL_checklstring(L, 1, &len);
+  if(argc == 1)
+  {
+  	mode = 0;	
+  }
+  else{
+  	mode = luaL_checkinteger(L, 2);
+  }
+  if(mode == -1)
+  {
+  	/* 自定义模式 */
+  	space = luaL_checkinteger(L, 3);
+  	str_check = luaL_checklstring(L, 4, &len_check);
+  }
+  if(mode == 1)
+  {
+  	/* RFC3986 */
+  	space = 1;
+  	str_check = ".-_";
+    len_check = 3;
+  }
   luaL_Buffer buff;
-  luaL_buffinitsize(L, &buff, len + 16); // 预留几个字节就够了吧
-
+  luaL_buffinitsize(L, &buff, len + 16);
+  if(str_check == NULL)
+  {
+    str_check = ".-*_";
+    len_check = 4;
+  }
   for (size_t i = 0; i < len; i++)
   {
     char ch = *(str+i);
     if((ch >= 'A' && ch <= 'Z') ||
-			(ch >= 'a' && ch <= 'z') ||
-			(ch >= '0' && ch <= '9') ||
-			ch == '.' || ch == '-' || ch == '*' || ch == '_') {
+  		(ch >= 'a' && ch <= 'z') ||
+  		(ch >= '0' && ch <= '9')) {
       luaL_addchar(&buff, ch);
     }
-    else if (ch == ' ') {
-      luaL_addchar(&buff, '+');
-    }
     else {
-      luaL_addchar(&buff, '%');
-      luaL_addchar(&buff, hexchars[(unsigned char)ch >> 4]);
-      luaL_addchar(&buff, hexchars[(unsigned char)ch & 0x0F]);
+      char result = 0;
+      for(size_t j = 0; j < len_check; j++)
+      {
+        if(ch == str_check[j])
+        {
+          result = 1;
+          break;
+        }
+      }
+      if(result == 1)
+      {
+        luaL_addchar(&buff, str[i]);
+      }
+      else
+      {
+        if(ch == ' ')
+        {
+          if(space == 0)
+          {
+            luaL_addchar(&buff, '+');
+            continue;
+          }
+        }
+        luaL_addchar(&buff, '%');
+        luaL_addchar(&buff, hexchars[(unsigned char)str[i] >> 4]);
+        luaL_addchar(&buff, hexchars[(unsigned char)str[i] & 0x0F]);
+      }
     }
   }
   luaL_pushresult(&buff);

+ 14 - 7
luat/modules/luat_lib_i2c.c

@@ -55,7 +55,7 @@ i2c发送数据
 @int 设备id, 例如i2c1的id为1, i2c2的id为2
 @int I2C子设备的地址, 7位地址
 @string 待发送的数据
-@return nil 无返回值
+@return true/false 发送是否成功
 @usage
 -- 往i2c1发送2个字节的数据
 i2c.send(1, 0x5C, string.char(0x0F, 0x2F))
@@ -64,9 +64,10 @@ static int l_i2c_send(lua_State *L) {
     int id = luaL_checkinteger(L, 1);
     int addr = luaL_checkinteger(L, 2);
     size_t len;
+    int result;
     if (lua_isstring(L, 3)) {
         const char* buff = luaL_checklstring(L, 3, &len);
-        luat_i2c_send(id, addr, (char*)buff, len);
+        result = luat_i2c_send(id, addr, (char*)buff, len);
     }
     else if (lua_isinteger(L, 3)) {
         len = lua_gettop(L) - 2;
@@ -75,9 +76,10 @@ static int l_i2c_send(lua_State *L) {
         {
             buff[i] = lua_tointeger(L, 3+i);
         }
-        luat_i2c_send(id, addr, buff, len);
+        result = luat_i2c_send(id, addr, buff, len);
     }
-    return 0;
+    lua_pushboolean(L, result == 0);
+    return 1;
 }
 
 /*
@@ -96,7 +98,11 @@ static int l_i2c_recv(lua_State *L) {
     int addr = luaL_checkinteger(L, 2);
     int len = luaL_checkinteger(L, 3);
     char buf[len];
-    luat_i2c_recv(id, addr, &buf[0], len);
+    int result = luat_i2c_recv(id, addr, &buf[0], len);
+    if(result!=0){//如果返回值不为0,说明收失败了
+        len = 0;
+        LLOGD("i2c receive result %d", result);
+    }
     lua_pushlstring(L, buf, len);
     return 1;
 }
@@ -108,7 +114,7 @@ i2c写寄存器数据
 @int I2C子设备的地址, 7位地址
 @int 寄存器地址
 @string 待发送的数据
-@return int 发送数据的结果,0为成功
+@return true/false 发送是否成功
 @usage
 -- 从i2c1的地址为0x5C的设备的寄存器0x01写入2个字节的数据
 i2c.writeReg(1, 0x5C, 0x01, string.char(0x00, 0xF2))
@@ -124,7 +130,8 @@ static int l_i2c_write_reg(lua_State *L) {
     memcpy(buff+1,lb,sizeof(char)+len+1);
     int result = luat_i2c_send(id, addr, buff, len+1);
     luat_heap_free(buff);
-    return result;
+    lua_pushboolean(L, result == 0);
+    return 1;
 }
 
 /*

+ 9 - 1
luat/modules/luat_lib_socket.c

@@ -91,7 +91,7 @@ static int luat_lib_netc_msg_handler(lua_State* L, void* ptr) {
         }
         goto exit;
     }
-    LLOGD("luat_lib_netc_msg_handler event=%ld lua_ref=%ld", ent->event, ent->lua_ref);
+    LLOGD("netc[%ld] event=%ld lua_ref=%ld", ent->netc_id, ent->event, ent->lua_ref);
     if (ent->lua_ref == 0) {
         goto exit;
     }
@@ -114,6 +114,10 @@ static int luat_lib_netc_msg_handler(lua_State* L, void* ptr) {
     //    lua_call(L, 1, 0);
     //    break;
     case NETC_EVENT_RECV:
+        if(ent->len > 100)
+	    {
+	    	lua_gc(L, LUA_GCCOLLECT, 0);
+	    }
         lua_pushlstring(L, ent->buff, ent->len);
         //lua_pushliteral(L, "");
         lua_call(L, 2, 0);
@@ -299,6 +303,10 @@ static int netc_send(lua_State *L) {
     const char* data = luaL_checklstring(L, 2, &len);
     int flags = luaL_optinteger(L, 3, 0);
     if (len > 0) {
+        if(len > 100)
+    	{
+    		lua_gc(L, LUA_GCCOLLECT, 0);
+    	}
         int32_t re = netclient_send(netc, (void*)data, len, flags);
         lua_pushboolean(L, re == len ? 1 : 0);
     }

+ 1 - 2
luat/rtt/luat_lib_wlan.c

@@ -101,6 +101,7 @@ static join_info_t jinfo = {0};
 
 
 static void _wlan_connect(void* params) {
+    rt_wlan_config_autoreconnect(1);
     rt_wlan_connect(jinfo.ssid, jinfo.passwd);
 }
 
@@ -143,8 +144,6 @@ static int l_wlan_connect(lua_State *L) {
     }
     // 自动重连
     
-    rt_wlan_config_autoreconnect(1);
-    
     return 0;
 }
 

+ 3 - 1
luat/rtt/luat_msgbus_rtt.c

@@ -13,7 +13,7 @@
 
 ALIGN(RT_ALIGN_SIZE)
 static rt_uint8_t msg_pool[4*1024];
-static struct rt_messagequeue mq;
+static struct rt_messagequeue mq = {0};
 // static void *msgdata = {0};
 
 void luat_msgbus_init(void) {
@@ -36,6 +36,8 @@ void luat_msgbus_init(void) {
 // }
 
 uint32_t luat_msgbus_put(rtos_msg_t* msg, size_t timeout) {
+    if (!mq.msg_size) // 未初始化
+        return 0;
     LOG_D(">>luat_msgbus_put msg->ptr= %08X", msg->ptr);
     int re = rt_mq_send(&mq, msg, sizeof(rtos_msg_t));
     if (re) {

+ 16 - 4
luat/rtt/luat_msh_rtt.c

@@ -15,14 +15,26 @@
 
 extern lua_State *L;
 
-static void loadstr(int argc, char**argv) {
-    if (argc < 2)
-        return;
-    int re = luaL_dostring(L, argv[1]);
+static int msgbus_handler(lua_State *L, void* ptr) {
+    int re = luaL_dostring(L, (const char*)ptr);
     if (re) {
         LLOGE("luaL_dostring  return re != 0\n");
         LLOGE(lua_tostring(L, -1));
     }
+    luat_heap_free(ptr);
+    return 0;
+}
+
+static void loadstr(int argc, char**argv) {
+    if (argc < 2)
+        return;
+    char* buff = luat_heap_malloc(strlen(argv[1])+1);
+    strcpy(buff, argv[1]);
+    rtos_msg_t msg;
+    msg.handler = msgbus_handler;
+    msg.ptr = buff;
+    luat_msgbus_put(&msg, 0);
+    
 };
 
 MSH_CMD_EXPORT(loadstr , run lua code);