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

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

Wendal Chen 3 лет назад
Родитель
Сommit
133eed8156

+ 3 - 2
components/mbedtls/library/debug.c

@@ -102,6 +102,7 @@ void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level,
     if( NULL == ssl              ||
         NULL == ssl->conf        ||
         NULL == ssl->conf->f_dbg ||
+	    MBEDTLS_ERR_SSL_WANT_READ ==  ret ||
         level > debug_threshold )
     {
         return;
@@ -112,8 +113,8 @@ void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level,
      * the logs would be quickly flooded with WANT_READ, so ignore that.
      * Don't ignore WANT_WRITE however, since is is usually rare.
      */
-    if( ret == MBEDTLS_ERR_SSL_WANT_READ )
-        return;
+
+
 #ifdef LUAT_LOG_NO_NEWLINE
     mbedtls_snprintf( str, DEBUG_BUF_SIZE, "%s() returned %d (-0x%04x)",
               text, ret, (unsigned int) -ret );

+ 2 - 2
components/network/adapter/luat_lib_socket.c

@@ -739,8 +739,8 @@ static int l_socket_set_dns(lua_State *L)
 /*
 设置SSL的log
 @api    socket.sslLog(log_level)
-@int	mbedtls log等级,<=2基本不打印,不要超过9
-@usage socket.sslLog(3)
+@int	mbedtls log等级,0不打印,1只打印错误和警告,2大部分info,3及3以上详细的debug信息,过多的信息可能会造成内存碎片化
+@usage socket.sslLog(2)
 */
 static int l_socket_set_ssl_log(lua_State *L)
 {

+ 13 - 2
components/network/lwip/port/net_lwip.c

@@ -1627,7 +1627,18 @@ static int net_lwip_socket_receive(int socket_id, uint64_t tag,  uint8_t *buf, u
 		}
 		else
 		{
-			prvlwip.socket[socket_id].rx_wait_size -= net_lwip_socket_read_data(socket_id, buf + read_len, &read_len, len, p);
+			if (p)
+			{
+				if (remote_ip)
+				{
+					*remote_ip = p->ip;
+				}
+				if (remote_port)
+				{
+					*remote_port = p->port;
+				}
+				prvlwip.socket[socket_id].rx_wait_size -= net_lwip_socket_read_data(socket_id, buf + read_len, &read_len, len, p);
+			}
 		}
 		if (llist_empty(&prvlwip.socket[socket_id].rx_head))
 		{
@@ -2124,7 +2135,7 @@ static int net_lwip_dns(const char *domain_name, uint32_t len, void *param, void
 	return 0;
 }
 
-static int net_lwip_dns(const char *domain_name, uint32_t len, void *param, void *user_data)
+static int net_lwip_dns_ipv6(const char *domain_name, uint32_t len, void *param, void *user_data)
 {
 	if ((uint32_t)user_data >= NW_ADAPTER_INDEX_LWIP_NETIF_QTY) return -1;
 	char *prv_domain_name = (char *)zalloc(len + 1);

+ 52 - 0
demo/aliyun/main.lua

@@ -0,0 +1,52 @@
+PROJECT = "aliyundemo"
+VERSION = "1.0.0"
+local sys = require "sys"
+require "aliyun"
+
+--根据自己的服务器修改以下参数
+local mqtt_host = "你的实例id.mqtt.iothub.aliyuncs.com" --你公共实例的地址
+local mqtt_port = 1883 --端口
+local mqtt_isssl = true -- 是否为ssl加密连接,默认不加密,true为无证书最简单的加密,table为有证书的加密
+local ProductKey = "你的key" --产品证书
+local ProductSecret = "你的产品密钥"   --产品密钥
+local DeviceName = "你的设备id"   --设备id
+local Registration = false  --如果预注册了的话就不需要改   false   true
+local InstanceId = "iot-你的实例id"  --如果没有注册需要填写实例id,在阿里云的实例详情页面
+local DeviceSecret = "你的设备秘钥"  --一机一密需要的设备密钥
+
+---数据接收的处理函数
+-- @string topic,UTF8编码的消息主题
+-- @number qos,消息质量等级
+-- @string payload,原始编码的消息负载
+local function rcvCbFnc(topic,qos,payload)
+    log.info("aliyun.rcvCbFnc",topic,qos,payload)
+end
+
+--- 连接结果的处理函数
+-- @bool result,连接结果,true表示连接成功,false或者nil表示连接失败
+local function connectCbFnc(result)
+    log.info("aliyun.connectCbFnc",result)
+    if result then
+        --订阅主题,不需要考虑订阅结果,如果订阅失败,aliyun库中会自动重连
+        --根据自己的项目需要订阅主题,下面注释掉的一行代码中的主题是非法的,所以不能打开,一旦打开,会导致订阅失败
+        --aliyun.subscribe({["/"..PRODUCT_KEY.."/"..getDeviceName().."/get"]=0, ["/"..PRODUCT_KEY.."/"..getDeviceName().."/get"]=1})
+        aliyun.subscriber("/ht6f7kmyFFQ/861551056421746/user/ceshi",1)
+        --注册数据接收的处理函数
+        aliyun.on("receive",rcvCbFnc)
+        aliyun.publish("/"..ProductKey.."/"..DeviceName.."/user/get",0,"LUATOS_CESHI")
+    end
+end
+
+aliyun.on("connect",connectCbFnc)
+
+--一型一密
+-- aliyun.operation(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+
+--一机一密
+aliyun.confiDentialTask(DeviceName,ProductKey,DeviceSecret,mqtt_host,mqtt_port,mqtt_isssl)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 98 - 0
demo/socket/Air105/async_socket_demo.lua

@@ -0,0 +1,98 @@
+-- netlab.luatos.com上打开TCP,然后修改IP和端口号,自动回复netlab下发的数据,自收自发测试
+
+local server_ip = "152.70.80.204"
+local server_port = 55619
+local UDP_port = 37834
+local ssl_port = 35528
+local rxbuf = zbuff.create(8192)
+local function netCB(netc, event, param)
+    if param ~= 0 then
+        sys.publish("socket_disconnect")
+        return
+    end
+	if event == socket.LINK then
+	elseif event == socket.ON_LINE then
+        socket.tx(netc, "hello,luatos!")
+	elseif event == socket.EVENT then
+        socket.rx(netc, rxbuf)
+        socket.wait(netc)
+        if rxbuf:used() > 0 then
+            log.info("收到", rxbuf:toStr(0,rxbuf:used()):toHex())
+            log.info("发送", rxbuf:used(), "bytes")
+            socket.tx(netc, rxbuf)
+        end
+        rxbuf:del()
+	elseif event == socket.TX_OK then
+        socket.wait(netc)
+        log.info("发送完成")
+	elseif event == socket.CLOSE then
+        sys.publish("socket_disconnect")
+    end
+end
+
+local function socketTask()
+	local netc = socket.create(nil, netCB)
+	socket.debug(netc, true)
+	socket.config(netc, nil, nil, nil, 300, 5, 6)   --开启TCP保活,防止长时间无数据交互被运营商断线
+    while true do
+        local succ, result = socket.connect(netc, server_ip, server_port)
+        if not succ then
+            log.info("未知错误,5秒后重连")
+        else
+            local result, msg = sys.waitUntil("socket_disconnect")
+        end
+        log.info("服务器断开了,5秒后重连")
+        socket.close(netc)
+        log.info(rtos.meminfo("sys"))
+        sys.wait(5000)
+    end
+end
+
+local function UDPTask()
+    local netc = socket.create(nil, netCB)
+    socket.debug(netc, true)
+    socket.config(netc, nil, true, nil, 300, 5, 6)   --开启TCP保活,防止长时间无数据交互被运营商断线
+    while true do
+        local succ, result = socket.connect(netc, server_ip, UDP_port)
+        if not succ then
+            log.info("未知错误,5秒后重连")
+        else
+            local result, msg = sys.waitUntil("socket_disconnect")
+        end
+        log.info("服务器断开了,5秒后重连")
+        socket.close(netc)
+        log.info(rtos.meminfo("sys"))
+        sys.wait(5000)
+    end
+end
+
+
+local function SSLTask()
+    local netc = socket.create(nil, netCB)
+    socket.debug(netc, true)
+    socket.config(netc, nil, nil, true, 300, 5, 6)   --开启TCP保活,防止长时间无数据交互被运营商断线
+    while true do
+        local succ, result = socket.connect(netc, server_ip, ssl_port)
+        if not succ then
+            log.info("未知错误,5秒后重连")
+        else
+            local result, msg = sys.waitUntil("socket_disconnect")
+        end
+        log.info("服务器断开了,5秒后重连")
+        socket.close(netc)
+        log.info(rtos.meminfo("sys"))
+        sys.wait(5000)
+    end
+end
+
+function socketDemo()
+	sys.taskInit(socketTask)
+end
+
+function UDPDemo()
+    sys.taskInit(UDPTask)
+end
+
+function SSLDemo()
+    sys.taskInit(SSLTask)
+end

+ 224 - 0
demo/test/use/main.lua

@@ -0,0 +1,224 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "httpdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要http库, 大部分能联网的设备都具有这个库
+http也是内置库, 无需require
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用http库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+---- MultipartForm上传文件
+-- url string 请求URL地址
+-- req_headers table 请求头
+-- params table 需要传输的数据参数
+local function postMultipartFormData(url, params)
+    local boundary = "----WebKitFormBoundary"..os.time()
+    local req_headers = {
+        ["Content-Type"] = "multipart/form-data; boundary="..boundary,
+    }
+    local body = {}
+
+    -- 解析拼接 body
+    for k,v in pairs(params) do
+        if k=="texts" then
+            local bodyText = ""
+            for kk,vv in pairs(v) do
+                print(kk,vv)
+                bodyText = bodyText.."--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"\r\n\r\n"..vv.."\r\n"
+            end
+            table.insert(body, bodyText)
+        elseif k=="files" then
+            local contentType =
+            {
+                txt = "text/plain",             -- 文本
+                jpg = "image/jpeg",             -- JPG 格式图片
+                jpeg = "image/jpeg",            -- JPEG 格式图片
+                png = "image/png",              -- PNG 格式图片   
+                gif = "image/gif",              -- GIF 格式图片
+                html = "image/html",            -- HTML
+                json = "application/json"       -- JSON
+            }
+            
+            for kk,vv in pairs(v) do
+                if type(vv) == "table" then
+                    for i=1, #vv do
+                        print(kk,vv[i])
+                        table.insert(body, "--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"; filename=\""..vv[i]:match("[^%/]+%w$").."\"\r\nContent-Type: "..contentType[vv[i]:match("%.(%w+)$")].."\r\n\r\n")
+                        table.insert(body, io.readFile(vv[i]))
+                        table.insert(body, "\r\n")
+                    end
+                else
+                    print(kk,vv)
+                    table.insert(body, "--"..boundary.."\r\nContent-Disposition: form-data; name=\""..kk.."\"; filename=\""..vv:match("[^%/]+%w$").."\"\r\nContent-Type: "..contentType[vv:match("%.(%w+)$")].."\r\n\r\n")
+                    table.insert(body, io.readFile(vv))
+                    table.insert(body, "\r\n")
+                end
+            end
+        end
+    end 
+    table.insert(body, "--"..boundary.."--\r\n")
+    body = table.concat(body)
+    log.info("headers: ", "\r\n" .. json.encode(req_headers), type(body))
+    log.info("body: " .. body:len() .. "\r\n" .. body)
+    local code, headers, body = http.request("POST",url,
+            req_headers,
+            body
+    ).wait()   
+    log.info("http.post", code, headers, body)
+end
+
+-- sys.timerLoopStart(function ()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if rtos.bsp():startsWith("ESP32") then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "uiot"
+        local password = "12345678"
+        log.info("wifi", ssid, password)
+        -- TODO 改成esptouch配网
+        LED = gpio.setup(12, 0, gpio.PULLUP)
+        wlan.init()
+        wlan.setMode(wlan.STATION)
+        wlan.connect(ssid, password, 1)
+        local result, data = sys.waitUntil("IP_READY", 30000)
+        log.info("wlan", "IP_READY", result, data)
+        device_id = wlan.getMac()
+    elseif rtos.bsp() == "AIR105" then
+        -- w5500 以太网, 当前仅Air105支持
+        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
+        w5500.config() --默认是DHCP模式
+        w5500.bind(socket.ETH0)
+        LED = gpio.setup(62, 0, gpio.PULLUP)
+        sys.wait(1000)
+        -- TODO 获取mac地址作为device_id
+    elseif rtos.bsp() == "EC618" then
+        -- Air780E/Air600E系列
+        --mobile.simid(2)
+        LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+        -- log.info("ipv6", mobile.ipv6(true))
+        sys.waitUntil("IP_READY", 30000)
+    end
+
+    -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
+    -- if crypto.cipher_suites then
+    --     log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
+    -- end
+
+    -------------------------------------
+    -------- HTTP 演示代码 --------------
+    -------------------------------------
+
+    
+    socket.sslLog(2)
+    while 1 do
+        -- 最普通的Http GET请求
+        -- local code, headers, body = http.request("GET", "https://www.air32.cn/").wait()
+        -- log.info("http.get", code, headers, body)
+        -- local code, headers, body = http.request("GET", "https://mirrors6.tuna.tsinghua.edu.cn/", nil, nil, {ipv6=true}).wait()
+        -- log.info("http.get", code, headers, body)
+        -- sys.wait(100)
+        	
+        
+        log.info("mem.lua", rtos.meminfo())
+        log.info("mem.sys", rtos.meminfo("sys"))
+        local code, headers, body = http.request("GET", "https://www.luatos.com/").wait()
+        log.info("http.get", code, headers, #body)
+        sys.wait(100)
+        log.info("mem.lua", rtos.meminfo())
+        log.info("mem.sys", rtos.meminfo("sys"))
+        -- 按需打印
+        -- code 响应值, 若大于等于 100 为服务器响应, 小于的均为错误代码
+        -- headers是个table, 一般作为调试数据存在
+        -- body是字符串. 注意lua的字符串是带长度的byte[]/char*, 是可以包含不可见字符的
+        -- log.info("http", code, json.encode(headers or {}), #body > 512 and #body or body)
+
+        -- -- POST request 演示
+        -- local req_headers = {}
+        -- req_headers["Content-Type"] = "application/json"
+        -- local body = json.encode({name="LuatOS"})
+        -- local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date", 
+        --         req_headers,
+        --         body -- POST请求所需要的body, string, zbuff, file均可
+        -- ).wait()
+        -- log.info("http.post", code, headers, body)
+
+        
+        -- -- -- POST multipart/form-data模式 上传文件---手动拼接
+        -- local boundary = "----WebKitFormBoundary"..os.time()
+        -- local req_headers = {
+        --     ["Content-Type"] = "multipart/form-data; boundary="..boundary,
+        -- }
+        -- local body = "--"..boundary.."\r\n"..
+        --              "Content-Disposition: form-data; name=\"uploadFile\"; filename=\"luatos_uploadFile_TEST01.txt\""..
+        --              "\r\nContent-Type: text/plain\r\n\r\n"..
+        --              "1111http_测试一二三四654zacc\r\n"..
+        --              "--"..boundary
+
+        -- log.info("headers: ", "\r\n"..json.encode(req_headers))
+        -- log.info("body: ", "\r\n"..body)
+        -- local code, headers, body = http.request("POST","http://airtest.openluat.com:2900/uploadFileToStatic",
+        --         req_headers,
+        --         body -- POST请求所需要的body, string, zbuff, file均可
+        -- ).wait()
+        -- log.info("http.post", code, headers, body)
+
+        -- -- 也可用postMultipartFormData(url, params) 上传文件
+        -- postMultipartFormData(
+        --     "http://airtest.openluat.com:2900/uploadFileToStatic",
+        --     {
+        --         -- texts = 
+        --         -- {
+        --         --     ["imei"] = "862991234567890",
+        --         --     ["time"] = "20180802180345"
+        --         -- },
+                
+        --         files =
+        --         {
+        --             ["uploadFile"] = "/luadb/luatos_uploadFile.txt",
+        --         }
+        --     }
+        -- )
+    
+        -- -- POST and download, task内的同步操作
+        -- local opts = {}                 -- 额外的配置项
+        -- opts["dst"] = "/data.bin"       -- 下载路径,可选
+        -- opts["timeout"] = 30            -- 超时时长,单位秒,可选
+        -- opts["adapter"] = socket.ETH0  -- 使用哪个网卡,可选
+        -- local code, headers, body = http.request("POST","http://site0.cn/api/httptest/simple/date",
+        --         {}, -- 请求所添加的 headers, 可以是nil
+        --         "", 
+        --         opts
+        -- ).wait()
+        -- log.info("http.post", code, headers, body) -- 只返回code和headers
+    
+        -- local f = io.open("/data.bin", "rb")
+        -- if f then
+        --     local data = f:read("*a")
+        --     log.info("fs", "data", data, data:toHex())
+        -- end
+        
+        -- -- GET request, 开个task让它自行执行去吧, 不管执行结果了
+        -- sys.taskInit(http.request("GET","http://site0.cn/api/httptest/simple/time").wait)
+
+        -- log.info("sys", rtos.meminfo("sys"))
+        -- log.info("lua", rtos.meminfo("lua"))
+        sys.wait(10000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 2 - 2
demo/wlan/Air780E/main.lua

@@ -16,7 +16,7 @@ Air780E/Air600E/Air780EG等基于EC618的模块
 -- 引入必要的库文件(lua编写), 内部库不需要require
 sys = require("sys")
 require("sysplus")
-
+if mobile then mobile.rtime(1) end
 -- wifi扫描成功后, 会有WLAN_SCAN_DONE消息, 读取即可
 sys.subscribe("WLAN_SCAN_DONE", function ()
     local results = wlan.scanResult()
@@ -27,7 +27,7 @@ sys.subscribe("WLAN_SCAN_DONE", function ()
 end)
 
 sys.taskInit(function()
-    sys.wait(1000)
+    sys.wait(5000)
     wlan.init()
     while 1 do
         wlan.scan()

+ 2 - 0
luat/include/luat_libs.h

@@ -145,4 +145,6 @@ LUAMOD_API int luaopen_errdump( lua_State *L );
 LUAMOD_API int luaopen_profiler( lua_State *L );
 LUAMOD_API int luaopen_fskv( lua_State *L );
 LUAMOD_API int luaopen_max30102( lua_State *L );
+
+LUAMOD_API int luaopen_bit64( lua_State *L );
 #endif

+ 2 - 0
luat/include/luat_pm.h

@@ -58,4 +58,6 @@ int luat_pm_get_poweron_reason(void);
 
 int luat_pm_iovolt_ctrl(int id, int val);
 
+int luat_pm_wakeup_pin(int pin, int val);
+
 #endif

+ 3 - 2
luat/modules/luat_lib_adc.c

@@ -53,11 +53,12 @@ static int l_adc_set_range(lua_State *L) {
 读取adc通道
 @api adc.read(id)
 @int 通道id,与具体设备有关,通常从0开始
-@return int 原始值
-@return int 从原始值换算得出的电压值,通常单位是mV
+@return int 原始值,一般没用,可以直接抛弃
+@return int 从原始值换算得出的实际值,通常单位是mV
 @usage
 -- 打开adc通道2,并读取
 if adc.open(2) then
+    -- 这里使用的是adc.read会返回2个值, 推荐走adc.get函数,直接取实际值
     log.info("adc", adc.read(2))
 end
 adc.close(2)

+ 478 - 0
luat/modules/luat_lib_bit64.c

@@ -0,0 +1,478 @@
+/*
+@module  bit64
+@summary 32位系统上对64位数据的基本算术运算和逻辑运算,64位数据用9字节string存储,byte7~byte0存数据,byte8=0表示整形,其他表示浮点
+@version 0.1
+@date    2023.03.11
+@video
+@tag LUAT_USE_BIT64
+@demo  bit64
+*/
+#include "luat_base.h"
+#include "luat_malloc.h"
+#define LUAT_LOG_TAG "bit64"
+#include "luat_log.h"
+#define D64_FLAG 0x01
+#ifdef LUAT_USE_BIT64
+/**
+64bit数据转成32bit输出
+@api bit64.to32(data64bit)
+@string 9字节数据
+@return int or number
+ */
+static int l_bit64_to32(lua_State *L)
+{
+	double d64;
+	int64_t i64;
+    size_t len;
+    const char *data = luaL_checklstring(L, 1, &len);
+
+    if (len != 9)
+    {
+    	lua_pushnil(L);
+    }
+    if (data[8])
+    {
+        memcpy(&d64, data, 8);
+        lua_pushnumber(L, (lua_Number)d64);
+    }
+    else
+    {
+    	memcpy(&i64, data, 8);
+    	lua_pushinteger(L, (lua_Integer)i64);
+    }
+    return 1;
+}
+
+/**
+32bit数据转成64bit数据
+@api bit64.to64(data32bit)
+@int/number 32bit数据
+@return string 9字节数据
+ */
+static int l_bit64_to64(lua_State *L)
+{
+	double d64;
+	uint64_t u64;
+	uint8_t data[9] = {0};
+	if (lua_isinteger(L, 1))
+	{
+		u64 = (lua_Unsigned)lua_tointeger(L, 1);
+		memcpy(data, &u64, 8);
+	}
+	else if (lua_isnumber(L, 1))
+	{
+		d64 = lua_tonumber(L, 1);
+		data[8] = D64_FLAG;
+		memcpy(data, &d64, 8);
+
+	}
+	lua_pushlstring(L, data, 9);
+	return 1;
+}
+
+/**
+64bit数据格式化打印成字符串,用于显示值
+@api bit64.show(a,type,flag)
+@string a
+@int 进制,10=10进制,16=16进制,默认10,只支持10或者16
+@boolean 整形是否按照无符号方式打印,true是,false不是,默认false,浮点忽略
+@return string 可以打印的值
+ */
+static int l_bit64_show(lua_State *L)
+{
+	int64_t i64;
+	double d64;
+    size_t len;
+    uint8_t data[64] = {0};
+    uint8_t flag = 0;
+    const char *string = luaL_checklstring(L, 1, &len);
+    if (len != 9)
+    {
+    	lua_pushnil(L);
+    	return 1;
+    }
+    if (string[8])
+    {
+    	memcpy(&d64, string, 8);
+    }
+    else
+    {
+    	memcpy(&i64, string, 8);
+    }
+    uint8_t type = luaL_optinteger(L, 2, 10);
+	if (lua_isboolean(L, 3))
+	{
+		flag = lua_toboolean(L, 3);
+	}
+	if (type != 16)
+	{
+		if (string[8])
+		{
+			len = snprintf_(data, 63, "%f", d64);
+		}
+		else
+		{
+			if (flag)
+			{
+				len = snprintf_(data, 63, "%llu", i64);
+			}
+			else
+			{
+				len = snprintf_(data, 63, "%lld", (uint64_t)i64);
+			}
+		}
+	}
+	else
+	{
+		if (string[8])
+		{
+			len = snprintf_(data, 63, "0x%llx", d64);
+		}
+		else
+		{
+			len = snprintf_(data, 63, "0x%llx", i64);
+		}
+	}
+	lua_pushlstring(L, data, len);
+	return 1;
+}
+
+static int l_bit64_calculate(lua_State *L, uint8_t op)
+{
+	double d64_a,d64_b;
+	int64_t i64_a, i64_b;
+	uint64_t u64;
+    size_t len;
+    uint8_t data[9] = {0};
+    uint8_t flag1 = 0;
+    uint8_t flag2 = 0;
+    uint8_t fa,fb;
+    const char *string = luaL_checklstring(L, 1, &len);
+    if (len != 9)
+    {
+    	goto DONE;
+    }
+    fa = string[8];
+    if (fa)
+    {
+    	memcpy(&d64_a, string, 8);
+    }
+    else
+    {
+    	memcpy(&i64_a, string, 8);
+    }
+	if (lua_isinteger(L, 2))
+	{
+		i64_b = lua_tointeger(L, 2);
+		fb = 0;
+	}
+	else if (lua_isnumber(L, 2))
+	{
+		d64_b = lua_tonumber(L, 2);
+		fb = 1;
+	}
+	else
+	{
+		string = luaL_checklstring(L, 2, &len);
+	    if (len != 9)
+	    {
+	    	goto DONE;
+	    }
+	    fb = string[8];
+	    if (fb)
+	    {
+	    	memcpy(&d64_b, string, 8);
+	    }
+	    else
+	    {
+	    	memcpy(&i64_b, string, 8);
+	    }
+	}
+
+	if (lua_isboolean(L, 3))
+	{
+		flag1 = lua_toboolean(L, 3);
+	}
+	if (lua_isboolean(L, 4))
+	{
+		flag2 = lua_toboolean(L, 4);
+	}
+	switch(op)
+	{
+	case 0:
+		if (fa && fb)
+		{
+			d64_a = d64_a + d64_b;
+			goto FLOAT_OP;
+		}
+		if (fa && !fb)
+		{
+			d64_a = d64_a + i64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && fb)
+		{
+			d64_a = i64_a + d64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && !fb)
+		{
+			if (flag1)
+			{
+				u64 = (uint64_t)i64_a + (uint64_t)i64_b;
+				memcpy(data, &u64, 8);
+			}
+			else
+			{
+				i64_a = i64_a + i64_b;
+				memcpy(data, &i64_a, 8);
+			}
+			goto DONE;
+		}
+		break;
+	case 1:
+		if (fa && fb)
+		{
+			d64_a = d64_a - d64_b;
+			goto FLOAT_OP;
+		}
+
+		if (fa && !fb)
+		{
+			d64_a = d64_a - i64_b;
+			goto FLOAT_OP;
+		}
+
+		if (!fa && fb)
+		{
+			d64_a = i64_a - d64_b;
+			goto FLOAT_OP;
+		}
+
+		if (!fa && !fb)
+		{
+			if (flag1)
+			{
+				u64 = (uint64_t)i64_a - (uint64_t)i64_b;
+				memcpy(data, &u64, 8);
+			}
+			else
+			{
+				i64_a = i64_a - i64_b;
+				memcpy(data, &i64_a, 8);
+			}
+			goto DONE;
+		}
+		break;
+	case 2:
+		if (fa && fb)
+		{
+			d64_a = d64_a * d64_b;
+			goto FLOAT_OP;
+		}
+		if (fa && !fb)
+		{
+			d64_a = d64_a * i64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && fb)
+		{
+			d64_a = i64_a * d64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && !fb)
+		{
+			if (flag1)
+			{
+				u64 = (uint64_t)i64_a * (uint64_t)i64_b;
+				memcpy(data, &u64, 8);
+			}
+			else
+			{
+				i64_a = i64_a * i64_b;
+				memcpy(data, &i64_a, 8);
+			}
+			goto DONE;
+		}
+		break;
+	case 3:
+		if (fa && fb)
+		{
+			d64_a = d64_a / d64_b;
+			goto FLOAT_OP;
+		}
+		if (fa && !fb)
+		{
+			d64_a = d64_a / i64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && fb)
+		{
+			d64_a = i64_a / d64_b;
+			goto FLOAT_OP;
+		}
+		if (!fa && !fb)
+		{
+			if (flag1)
+			{
+				u64 = (uint64_t)i64_a / (uint64_t)i64_b;
+				memcpy(data, &u64, 8);
+			}
+			else
+			{
+				i64_a = i64_a / i64_b;
+				memcpy(data, &i64_a, 8);
+			}
+			goto DONE;
+		}
+		break;
+	}
+FLOAT_OP:
+	if (flag2)
+	{
+		i64_a = d64_a;
+		memcpy(data, &i64_a, 8);
+	}
+	else
+	{
+		data[8] = D64_FLAG;
+		memcpy(data, &d64_a, 8);
+	}
+	goto DONE;
+DONE:
+	lua_pushlstring(L, data, 9);
+	return 1;
+}
+
+/**
+64bit数据加,a+b,a和b中有一个为浮点,则按照浮点运算
+@api bit64.plus(a,b,flag1,flag2)
+@string a
+@string/int/number b
+@boolean 整形运算时是否按照无符号方式,true是,false不是,默认false,浮点运算忽略
+@boolean 浮点运算结果是否要强制转成整数,true是,false不是,默认false,整形运算忽略
+@return string 9字节数据
+ */
+static int l_bit64_plus(lua_State *L)
+{
+	return l_bit64_calculate(L, 0);
+}
+
+
+/**
+64bit数据减,a-b,a和b中有一个为浮点,则按照浮点运算
+@api bit64.minus(a,b,flag1,flag2)
+@string a
+@string/int/number b
+@boolean 整形运算时是否按照无符号方式,true是,false不是,默认false,浮点运算忽略
+@boolean 浮点运算结果是否要强制转成整数,true是,false不是,默认false,整形运算忽略
+@return string 9字节数据
+ */
+static int l_bit64_minus(lua_State *L)
+{
+	return l_bit64_calculate(L, 1);
+}
+
+/**
+64bit数据乘,a*b,a和b中有一个为浮点,则按照浮点运算
+@api bit64.mult(a,b,flag1,flag2)
+@string a
+@string/int/number b
+@boolean 整形运算时是否按照无符号方式,true是,false不是,默认false,浮点运算忽略
+@boolean 浮点运算结果是否要强制转成整数,true是,false不是,默认false,整形运算忽略
+@return string 9字节数据
+ */
+static int l_bit64_multiply(lua_State *L)
+{
+	return l_bit64_calculate(L, 2);
+}
+
+/**
+64bit数据除,a/b,a和b中有一个为浮点,则按照浮点运算
+@api bit64.pide(a,b,flag1,flag2)
+@string a
+@string/int/number b
+@boolean 整形运算时是否按照无符号方式,true是,false不是,默认false,浮点运算忽略
+@boolean 浮点运算结果是否要强制转成整数,true是,false不是,默认false,整形运算忽略
+@return string 9字节数据
+ */
+static int l_bit64_pide(lua_State *L)
+{
+	return l_bit64_calculate(L, 3);
+}
+
+/**
+64bit数据位移 a>>b 或者 a<<b
+@api bit64.pide(a,b,flag)
+@string a
+@int b
+@boolean 位移方向,true左移<<,false右移>>,默认false
+@return string 9字节数据
+ */
+static int l_bit64_shift(lua_State *L)
+{
+	uint64_t u64;
+	uint32_t pos = 0;
+    size_t len;
+    uint8_t data[9] = {0};
+    uint8_t flag = 0;
+    const char *string = luaL_checklstring(L, 1, &len);
+    if (len != 9)
+    {
+    	goto DONE;
+    }
+    data[8] = string[8];
+    memcpy(&u64, string, 8);
+
+	if (lua_isinteger(L, 2))
+	{
+		pos = lua_tointeger(L, 2);
+		if (!pos)
+		{
+			goto DONE;
+		}
+	}
+	else
+	{
+		goto DONE;
+	}
+	if (lua_isboolean(L, 3))
+	{
+		flag = lua_toboolean(L, 3);
+	}
+	if (flag)
+	{
+		u64 = u64 << pos;
+	}
+	else
+	{
+		u64 = u64 >> pos;
+	}
+    data[8] = string[8];
+    memcpy(data, &u64, 8);
+	lua_pushlstring(L, data, 9);
+	return 1;
+DONE:
+	lua_pushlstring(L, string, len);
+	return 1;
+}
+
+#include "rotable2.h"
+static const rotable_Reg_t reg_bit64[] = {
+	{"to32", ROREG_FUNC(l_bit64_to32)},
+	{"to64", ROREG_FUNC(l_bit64_to64)},
+	{"plus", ROREG_FUNC(l_bit64_plus)},
+	{"minus", ROREG_FUNC(l_bit64_minus)},
+	{"multi", ROREG_FUNC(l_bit64_multiply)},
+	{"pide", ROREG_FUNC(l_bit64_pide)},
+	{"shift", ROREG_FUNC(l_bit64_shift)},
+	{"show", ROREG_FUNC(l_bit64_show)},
+	{NULL,       ROREG_INT(0)}
+};
+
+LUAMOD_API int luaopen_bit64(lua_State *L)
+{
+    luat_newlib2(L, reg_bit64);
+    return 1;
+}
+#endif

+ 27 - 0
luat/modules/luat_lib_pm.c

@@ -350,6 +350,32 @@ static int l_pm_power_ctrl(lua_State *L) {
 // }
 // #endif
 
+
+/**
+配置唤醒引脚 (当前仅仅esp系列可用)
+@api pm.wakeupPin(pin,level)
+@int/table gpio引脚
+@int 唤醒电压 可选,默认低电平唤醒
+@return boolean 处理结果
+@usage
+pm.wakeupPin(8,0)
+ */
+static int l_pm_wakeup_pin(lua_State *L) {
+    int level = luaL_optinteger(L, 2,0);
+    if (lua_istable(L, 1)) {
+        size_t count = lua_rawlen(L, 1);
+		for (size_t i = 1; i <= count; i++){
+			lua_geti(L, 1, i);
+            luat_pm_wakeup_pin(luaL_checkinteger(L, -1), level);
+			lua_pop(L, 1);
+		}
+    }else if(lua_isnumber(L, 1)){
+        luat_pm_wakeup_pin(luaL_checkinteger(L, 1), level);
+    }
+    lua_pushboolean(L, 1);
+    return 1;
+}
+
 #include "rotable2.h"
 static const rotable_Reg_t reg_pm[] =
 {
@@ -368,6 +394,7 @@ static const rotable_Reg_t reg_pm[] =
     { "reboot",         ROREG_FUNC(l_rtos_reboot)},
 	{ "power",          ROREG_FUNC(l_pm_power_ctrl)},
     // { "ioVolt",         ROREG_FUNC(l_pm_iovolt_ctrl)},
+    { "wakeupPin",         ROREG_FUNC(l_pm_wakeup_pin)},
 
 
     //@const NONE number 不休眠模式

+ 462 - 0
script/libs/aLiyun.lua

@@ -0,0 +1,462 @@
+--[[
+@module aliyun
+@summary aliyun 阿里云
+@version 1.0
+@date    2023.03.10
+@author  翟浩宇
+@usage
+-- 用法实例
+参考aliyun demo: https://gitee.com/openLuat/LuatOS/tree/master/demo/aliyun
+]]
+
+local sys = require "sys"
+--[[特别注意, 使用mqtt库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+aliyun = {}
+
+local clientId,password,userName,DeviceSecret
+
+local outQueue =
+{
+    SUBSCRIBE = {},
+    PUBLISH = {},
+}
+
+local evtCb = {}
+
+local mqttc = nil
+
+--添加
+local function insert(type,topic,qos,payload,retain)
+    table.insert(outQueue[type],{t=topic,q=qos,p=payload,r=retain})
+end
+
+--删除
+local function remove(type)
+    if #outQueue[type]>0 then return table.remove(outQueue[type],1) end
+end
+
+--订阅步骤
+local function procSubscribe(client)
+    local i
+    if #outQueue["SUBSCRIBE"]>0 then
+        log.info("订阅表里大于零")
+    else 
+        log.info("订阅表里没数据")
+    end
+
+    for i=1,#outQueue["SUBSCRIBE"] do
+        if not client:subscribe(outQueue["SUBSCRIBE"][i].t , outQueue["SUBSCRIBE"][i].q) then
+            outQueue["SUBSCRIBE"] = {}
+            return false,"procSubscribe"
+        end
+    end
+    outQueue["SUBSCRIBE"] = {}
+    return true
+end
+
+--接收处理
+local function procReceive(client)
+    while true do
+        log.info("到接受处理方法里了")
+        local ret,data,payload,DeviceName,ProductKey = sys.waitUntil("NET_SENT_RDY",30000)
+        log.info("接收到消息之后传到处理方法里的数据",ret,data,payload,DeviceName,ProductKey)
+        --接收到数据
+        if ret then
+            log.info("aliyun.procReceive",data.topic,string.toHex(data.payload))
+            --OTA消息
+            if payload.topic=="/ota/device/upgrade/"..ProductKey.."/"..DeviceName then
+                log.info("进到OTA升级判断里了",payload.topic)
+                -- if aliyunOta and aliyunOta.upgrade then
+                --     aliyunOta.upgrade(data.payload)
+                -- end
+            --其他消息
+            else    
+                if evtCb["receive"] then evtCb["receive"](data.topic,data.qos,data.payload) end
+            end
+            
+            
+            --如果有等待发送的数据,则立即退出本循环
+            if #outQueue["PUBLISH"]>0 then
+                return true,"procReceive"
+            end
+        end
+    end
+	
+    return data=="timeout" or "procReceive"
+end
+
+--发布
+local function procSend(client)
+    sys.taskInit(function()
+        if not procSubscribe(client) then
+            return false,"procSubscribe"
+        end
+        if #outQueue["PUBLISH"]>0 then
+            log.info("发布表里大于零")
+        else 
+            log.info("发布表里没数据")
+        end
+
+        while #outQueue["PUBLISH"]>0 do
+            local item = table.remove(outQueue["PUBLISH"],1)
+            local result = client:publish(item.t,item.p,item.q)
+            if item.cb then item.cb(result,item.para) end
+            if not result then
+                return false,"procSend" 
+            end
+        end
+        return true,"procSend"
+    end)
+end
+
+--二次连接
+local function clientDataTask(clientId,user,password,mqtt_host,mqtt_port,mqtt_isssl,DeviceName,ProductKey)
+    sys.taskInit(function()
+        if mobile.status() == 0 then
+            sys.waitUntil("IP_READY",30000)
+        end
+        if mobile.status() == 1 then
+            local mqttc = mqtt.create(nil,mqtt_host,mqtt_port,mqtt_isssl)  --客户端创建
+            mqttc:auth(clientId,user,password) --三元组配置
+            mqttc:keepalive(30) -- 默认值240s
+            mqttc:autoreconn(true, 3000) -- 自动重连机制
+    
+            mqttc:on(mqtt_cbevent)  --mqtt回调注册
+            if mqttc:connect() then
+                while true do
+                    procSubscribe(mqttc)
+                    procSend(mqttc)
+                    sys.wait(1000)
+                end
+            end
+    
+    
+        else
+            --进入飞行模式,20秒之后,退出飞行模式
+            mobile.flymode(0,true)
+            sys.wait(20000)
+            mobile.flymode(0,false)
+        end
+    end)
+end
+
+--根据返回的数据进行二次加密
+local function directProc(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl,Registration)
+    if not Registration then
+        local clientId = DeviceName.."|securemode=2,signmethod=hmacmd5,timestamp=789|"
+        local userName = DeviceName.."&"..ProductKey
+        
+        local content = "clientId"..DeviceName.."deviceName"..DeviceName.."productKey"..ProductKey.."timestamp789"
+        log.info("content",content)
+        local signKey= fskv.kv_get("deviceSecret")
+        log.info("signKey",signKey)
+        password =crypto.hmac_md5(content,signKey)
+        log.info("password",password)
+
+        
+        log.info("aliyun.directProc",clientId,userName,password)
+        
+        clientDataTask(clientId,userName,password,mqtt_host,mqtt_port,mqtt_isssl,DeviceName,ProductKey)
+    else
+        local clientid = fskv.kv_get("clientid")
+        local deviceToken = fskv.kv_get("deviceToken")
+        local clientId = clientid.."|securemode=-2,authType=connwl|"
+        local userName = DeviceName.."&"..ProductKey
+        local password = deviceToken
+
+        log.info("aliyun.directProc",clientId,userName,password)
+        
+        clientDataTask(clientId,userName,password,mqtt_host,mqtt_port,mqtt_isssl,DeviceName,ProductKey)
+    end
+end
+
+--获取预注册和免预注册一型一密一次连接返回的数据
+local function clientEncryptionTask(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+    sys.taskInit(function()
+        local tm = os.time()
+        --一型一密
+            --预注册
+            if not Registration then
+                clientId = DeviceName.."|securemode=2,authType=register,random="..tm..",signmethod=hmacmd5|"
+            --免预注册
+            else
+                clientId = DeviceName.."|securemode=-2,authType=regnwl,random="..tm..",signmethod=hmacmd5,instanceId="..InstanceId.."|"
+            end
+            userName = DeviceName.."&"..ProductKey
+            local content = "deviceName"..DeviceName.."productKey"..ProductKey.."random"..tm
+            password = crypto.hmac_md5(content,ProductSecret)
+    
+            local mqttClient = mqtt.create(nil,mqtt_host,mqtt_port,mqtt_isssl)  --客户端创建
+            mqttClient:auth(clientId,userName,password) --三元组配置
+            mqttClient:on(function(mqtt_client, event, data, payload)  --mqtt回调注册
+                -- 用户自定义代码
+                if event == "conack" then
+
+                elseif event == "recv" then
+                    log.info("mqtt", "downlink", "topic", data, "payload", payload)
+                    if payload then
+                        local tJsonDecode,res = json.decode(payload)
+                        if not Registration then
+                            --预注册
+                            if res and tJsonDecode["deviceName"] and tJsonDecode["deviceSecret"] then
+                                --把当前设备的SN号改为设备秘钥
+                                fskv.init()
+                                fskv.set("deviceSecret", tJsonDecode["deviceSecret"])
+                                mqttClient:disconnect()
+                                directProc(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl,Registration)
+                            end
+                        else
+                             --免预注册
+                            if res and tJsonDecode["deviceName"] and tJsonDecode["deviceToken"] then
+                                --把当前设备的SN号改为设备秘钥
+                                fskv.init()
+                                fskv.set("deviceToken", tJsonDecode["deviceToken"])
+                                fskv.set("clientid", tJsonDecode["clientId"])
+                                -- sys.wait(1000)
+                                mqttClient:disconnect()
+                                directProc(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl,Registration)
+                            end
+                        end
+                        
+                    end
+                elseif event == "sent" then
+                    log.info("mqtt", "sent", "pkgid", data)
+                end
+            end)
+    
+            mqttClient:connect()
+            log.info("mqtt连接成功")
+    end)
+end
+
+
+--底层libMQTT回调函数,上层的回调函数,通过 aliyun.on注册
+local function mqtt_cbevent(mqtt_client, event, data, payload) 
+    if event == "conack" then
+        evtCb["connect"](true) 
+    elseif event == "recv" then -- 服务器下发的数据
+        log.info("mqtt", "downlink", "topic", data, "payload", payload)
+
+        if evtCb["receive"] then
+            evtCb["receive"](data, payload)
+        end
+    elseif event == "sent" then
+        log.info("mqtt", "sent", "pkgid", data)
+    end
+end
+
+
+--正常连接 预注册一型一密获取DeviceSecret后就是正常的一机一密连接
+local function clientDirectTask(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl)
+    sys.taskInit(function()
+        if mobile.status() == 0 then
+            sys.waitUntil("IP_READY",30000)
+        end
+        if mobile.status() == 1 then
+            if DeviceSecret==nil then
+                DeviceSecret = fskv.get("deviceSecret")
+            end
+            local client_id,user_name,password = iotauth.aliyun(ProductKey,DeviceName,DeviceSecret)
+            mqttc = mqtt.create(nil,mqtt_host, mqtt_port,mqtt_isssl)  --mqtt客户端创建
+    
+            mqttc:auth(client_id,user_name,password) --mqtt三元组配置
+            mqttc:keepalive(30) -- 默认值240s
+            mqttc:autoreconn(true, 3000) -- 自动重连机制
+    
+            mqttc:on(mqtt_cbevent)  --mqtt回调注册
+            if mqttc:connect() then
+                while true do
+                    procSubscribe(mqttc)
+                    procSend(mqttc)
+                    sys.wait(1000)
+                end  
+            end
+            
+        else
+            --进入飞行模式,20秒之后,退出飞行模式
+            mobile.flymode(0,true)
+            sys.wait(20000)
+            mobile.flymode(0,false)
+        end
+    end)
+end
+
+
+--正常连接 免预注册一型一密获取deviceToken后就是正常的一机一密连接
+local function clientTokenTask(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl)
+    sys.taskInit(function()
+        sys.wait(5000)
+        if mobile.status() == 0 then
+            sys.waitUntil("IP_READY",30000)
+        end
+        if mobile.status() == 1 then
+            deviceToken = fskv.get("deviceToken")
+            local clientid = fskv.kv_get("clientid")
+            local clientId = clientid.."|securemode=-2,authType=connwl|"
+    
+            local client_id,user_name,password = iotauth.aliyun(ProductKey,DeviceName,deviceToken)
+            mqttc = mqtt.create(nil,mqtt_host, mqtt_port,mqtt_isssl)  --mqtt客户端创建
+    
+            mqttc:auth(clientId,user_name,deviceToken) --mqtt三元组配置
+            mqttc:keepalive(30) -- 默认值240s
+            mqttc:autoreconn(true, 3000) -- 自动重连机制
+    
+            mqttc:on(mqtt_cbevent)  --mqtt回调注册
+            if mqttc:connect() then
+                while true do
+                    procSubscribe(mqttc)
+                    procSend(mqttc)
+                    sys.wait(1000)
+                end  
+            end
+    
+        else
+            --进入飞行模式,20秒之后,退出飞行模式
+            mobile.flymode(0,true)
+            sys.wait(20000)
+            mobile.flymode(0,false)
+        end
+    end)
+end
+
+--根据掉电不消失的kv文件区来储存的deviceSecret,deviceToken来判断是进行正常连接还是
+
+--[[
+一型一密连接
+@api aliyun.operation(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+@bool Registration 是否预注册
+@string DeviceName 设备id
+@string ProductKey 产品key
+@string ProductSecret 产品秘钥
+@string InstanceId 实例id
+@string mqtt_host 公共实例的地址
+@string mqtt_port 端口
+@bool mqtt_isssl 是否为ssl加密连接,默认不加密,true为无证书最简单的加密,table为有证书的加密
+@usage
+aliyun.operation(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+]]
+function aliyun.operation(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+    fskv.init()
+    fskv.set("DeviceName",DeviceName)
+    local name = fskv.get("DeviceName")
+    local used = fskv.get("deviceSecret")
+    local total = fskv.get("deviceToken")
+    local cid = fskv.get("clientid")
+    --判断是否是同一DeviceName,不是的话就重新连接
+    if name == DeviceName then
+        if not Registration then
+            if used == nil then
+                clientEncryptionTask(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+            else
+                clientDirectTask(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl)
+            end
+        else
+            -- fskv.del("deviceToken")
+            -- fskv.del("clientid")
+            -- log.info("删除deviceToken,clientid")
+            if total == nil then
+                clientEncryptionTask(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+            else
+                clientTokenTask(DeviceName,ProductKey,mqtt_host,mqtt_port,mqtt_isssl)
+            end
+        end
+    else
+            fskv.del("deviceToken")
+            fskv.del("clientid")
+            fskv.del("DeviceName")
+            fskv.del("deviceSecret")
+            --删除kv区的数据,重新建立连接
+            clientEncryptionTask(Registration,DeviceName,ProductKey,ProductSecret,InstanceId,mqtt_host,mqtt_port,mqtt_isssl)
+    end
+end
+
+--[[
+一机一密连接
+@api aliyun.confiDentialTask(DeviceName,ProductKey,DeviceSecret,mqtt_host,mqtt_port,mqtt_isssl)
+@string DeviceName 设备id
+@string ProductKey 产品key
+@string DeviceSecret 设备秘钥
+@string mqtt_host 公共实例的地址
+@string mqtt_port 端口
+@bool mqtt_isssl 是否为ssl加密连接,默认不加密,true为无证书最简单的加密,table为有证书的加密
+@usage
+aliyun.confiDentialTask(DeviceName,ProductKey,DeviceSecret,mqtt_host,mqtt_port,mqtt_isssl)
+]]
+function aliyun.confiDentialTask(DeviceName,ProductKey,DeviceSecret,mqtt_host,mqtt_port,mqtt_isssl)
+    sys.taskInit(function()
+        sys.wait(5000)
+        if mobile.status() == 0 then
+            sys.waitUntil("IP_READY",30000)
+        end
+        if mobile.status() == 1 then
+            local client_id,user_name,password = iotauth.aliyun(ProductKey,DeviceName,DeviceSecret)
+            mqttc = mqtt.create(nil,mqtt_host, mqtt_port,mqtt_isssl)  --mqtt客户端创建
+            mqttc:auth(client_id,user_name,password) --mqtt三元组配置
+            mqttc:keepalive(30) -- 默认值240s
+            mqttc:autoreconn(true, 3000) -- 自动重连机制
+
+            mqttc:on(mqtt_cbevent)  --mqtt回调注册
+            if mqttc:connect() then
+                while true do
+                    procSubscribe(mqttc)
+                    procSend(mqttc)
+                    sys.wait(1000)
+                end  
+            end
+            
+        else
+            --进入飞行模式,20秒之后,退出飞行模式
+            mobile.flymode(0,true)
+            sys.wait(20000)
+            mobile.flymode(0,false)
+        end
+    end)
+end
+
+--[[
+订阅主题
+@api aliyun.subscriber(topic,qos)
+@string/table topic,string或者table类型,一个主题时为string类型,多个主题时为table类型,主题内容为UTF8编码
+@number qos,number或者nil,topic为一个主题时,qos为number类型(0/1,默认0);topic为多个主题时,qos为nil
+@usage
+-- aliyun.subscriber("/b0FMK1Ga5cp/862991234567890/get", 0)
+-- aliyun.subscriber({["/b0FMK1Ga5cp/862991234567890/get"] = 0, ["/b0FMK1Ga5cp/862991234567890/get"] = 1})
+]]
+function aliyun.subscriber(topic,qos)
+    insert("SUBSCRIBE",topic,qos)
+    sys.publish("aliyun_publish_ind","send")
+end
+
+--[[
+发布一条消息
+@api aliyun.publish(topic,qos,payload,retain)
+@string topic,UTF8编码的主题
+@number qos,0/1,默认0
+@numberretain,是否存档, 0/1,默认0
+@number i2c_id i2c_id
+@usage
+aliyun.publish("/"..ProductKey.."/"..DeviceName.."/user/get",0,"LUATOS_CESHI")
+]]
+function aliyun.publish(topic,qos,payload,retain)
+    insert("PUBLISH",topic,qos,payload,retain)
+    sys.publish("aliyun_publish_ind","send")
+    log.info("aliyun aliyun_publish_ind","publish")
+end
+
+--[[
+注册事件的处理函数
+@api aliyun.on(evt,cbFnc)
+@string evt 事件 <br>"auth"表示鉴权服务器认证结果事件 <br>"connect"表示接入服务器连接结果事件 <br>"reconnect"表示重连事件 <br>"receive"表示接收到接入服务器的消息事件
+@function cbFnc 事件的处理函数  <br>当evt为"auth"时,cbFnc的调用形式为:cbFnc(result),result为true表示认证成功,false或者nil表示认证失败 <br>当evt为"connect"时,cbFnc的调用形式为:cbFnc(result),result为true表示连接成功,false或者nil表示连接失败 <br>当evt为"receive"时,cbFnc的调用形式为:cbFnc(topic,qos,payload),topic为UTF8编码的主题(string类型),qos为质量等级(number类型),payload为原始编码的负载(string类型) <br>当evt为"reconnect"时,cbFnc的调用形式为:cbFnc(),表示lib中在自动重连阿里云服务器
+@usage
+aliyun.on("connect",cbFnc)
+]]
+function aliyun.on(evt,cbFnc)
+	evtCb[evt] = cbFnc
+end
+
+
+return aliyun
+