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

add: 添加model/air780e, 来源是原本的LuatOS-Air780E库

Wendal Chen 7 месяцев назад
Родитель
Сommit
a0dee13886
100 измененных файлов с 8453 добавлено и 0 удалено
  1. 95 0
      module/Air780E/.gitignore
  2. 21 0
      module/Air780E/LICENSE
  3. 8 0
      module/Air780E/README.md
  4. 21 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/1.Air780E的helloworld教程/main.lua
  5. 168 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/10.Air780E跟服务器之间的加密通信/libnet.lua
  6. 202 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/10.Air780E跟服务器之间的加密通信/main.lua
  7. 74 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/11.Air780E怎么获取精准的时钟/main.lua
  8. 88 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/12.通过腾讯连连小程序控制灯的亮灭/main.lua
  9. 25 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/2.用Air780E的本地脚本控制灯的亮和灭/main.lua
  10. 123 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/3.用电脑浏览器通过Air780E控制灯的亮和灭/main.lua
  11. 118 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/4.通过Air780E采集温湿度传感器数据并实现网页查看/main.lua
  12. 53 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/5.Air780E固件的远程升级/main.lua
  13. 126 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/6.通过Air780E的MQTT的连接实现远程控制/main.lua
  14. BIN
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/7.通过Air780E驱动SPI小屏幕的详细讲解/logo.jpg
  15. 129 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/7.通过Air780E驱动SPI小屏幕的详细讲解/main.lua
  16. 56 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/8.Air780E的文件系统对温湿度的存储和上报/main.lua
  17. 103 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/functionTest.lua
  18. 18 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/main.lua
  19. 75 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/psm_plus.lua
  20. 111 0
      module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/remote_net_wakeup.lua
  21. 68 0
      module/Air780E/demo/README.md
  22. 53 0
      module/Air780E/demo/SC7A20/main.lua
  23. 24 0
      module/Air780E/demo/adc/main.lua
  24. 86 0
      module/Air780E/demo/adc/testAdc.lua
  25. 49 0
      module/Air780E/demo/adxl345/main.lua
  26. 81 0
      module/Air780E/demo/air153C_wtd/main.lua
  27. 53 0
      module/Air780E/demo/air530z/offline/main.lua
  28. 90 0
      module/Air780E/demo/airlbs/main.lua
  29. 35 0
      module/Air780E/demo/at24cxx/main.lua
  30. 52 0
      module/Air780E/demo/bit/main.lua
  31. 114 0
      module/Air780E/demo/bit64/main.lua
  32. 115 0
      module/Air780E/demo/camera/spi_cam/bf30a2.lua
  33. 328 0
      module/Air780E/demo/camera/spi_cam/gc0310.lua
  34. 361 0
      module/Air780E/demo/camera/spi_cam/gc032a.lua
  35. 153 0
      module/Air780E/demo/camera/spi_cam/main.lua
  36. BIN
      module/Air780E/demo/crypto/logo.jpg
  37. 242 0
      module/Air780E/demo/crypto/main.lua
  38. 21 0
      module/Air780E/demo/dht11/main.lua
  39. 25 0
      module/Air780E/demo/dht12/main.lua
  40. 121 0
      module/Air780E/demo/dingding/main.lua
  41. 91 0
      module/Air780E/demo/eink/main.lua
  42. 62 0
      module/Air780E/demo/errDump/main.lua
  43. 97 0
      module/Air780E/demo/fastlz/fastlz.h
  44. 34 0
      module/Air780E/demo/fastlz/main.lua
  45. 130 0
      module/Air780E/demo/fatfs/main.lua
  46. 124 0
      module/Air780E/demo/feishu/main.lua
  47. 106 0
      module/Air780E/demo/fota/main.lua
  48. 98 0
      module/Air780E/demo/fota2/main.lua
  49. BIN
      module/Air780E/demo/fota_uart/fota_uart.bin
  50. 134 0
      module/Air780E/demo/fota_uart/main.lua
  51. 34 0
      module/Air780E/demo/fota_uart/main.py
  52. 3 0
      module/Air780E/demo/fs/abc.txt
  53. 124 0
      module/Air780E/demo/fs/main.lua
  54. 105 0
      module/Air780E/demo/fskv/main.lua
  55. 92 0
      module/Air780E/demo/ftp/main.lua
  56. 134 0
      module/Air780E/demo/gmssl/main.lua
  57. 35 0
      module/Air780E/demo/gpio/AGPIO/main.lua
  58. 39 0
      module/Air780E/demo/gpio/GPIO上拉下拉模式/main.lua
  59. 27 0
      module/Air780E/demo/gpio/GPIO中断(触发)模式/main.lua
  60. 33 0
      module/Air780E/demo/gpio/GPIO中断(计数)模式/main.lua
  61. 39 0
      module/Air780E/demo/gpio/GPIO翻转测速/main.lua
  62. 41 0
      module/Air780E/demo/gpio/GPIO输入模式/main.lua
  63. 42 0
      module/Air780E/demo/gpio/GPIO输出模式/main.lua
  64. 0 0
      module/Air780E/demo/gpio/IO复用/main.lua
  65. 43 0
      module/Air780E/demo/gpio/gpio/main.lua
  66. 64 0
      module/Air780E/demo/gpio/gpio_button/main.lua
  67. 31 0
      module/Air780E/demo/gpio/gpio_count_irq/main.lua
  68. 41 0
      module/Air780E/demo/gpio/gpio_irq/main.lua
  69. 31 0
      module/Air780E/demo/gpio/powerkey/main.lua
  70. 35 0
      module/Air780E/demo/gpio/usbconnect/main.lua
  71. 46 0
      module/Air780E/demo/gtfont/main.lua
  72. 23 0
      module/Air780E/demo/hello_world/main.lua
  73. 30 0
      module/Air780E/demo/hmeta/main.lua
  74. 3 0
      module/Air780E/demo/http/luatos_uploadFile.txt
  75. 306 0
      module/Air780E/demo/http/main.lua
  76. 74 0
      module/Air780E/demo/httpdns/main.lua
  77. 36 0
      module/Air780E/demo/httpplus/abc.txt
  78. 127 0
      module/Air780E/demo/httpplus/main.lua
  79. 38 0
      module/Air780E/demo/i2c/main.lua
  80. 130 0
      module/Air780E/demo/i2s/main.lua
  81. BIN
      module/Air780E/demo/i2s/test.pcm
  82. BIN
      module/Air780E/demo/i2s/test_16k.mp3
  83. 218 0
      module/Air780E/demo/iconv/main.lua
  84. 132 0
      module/Air780E/demo/io_queue/main.lua
  85. 52 0
      module/Air780E/demo/iotauth/main.lua
  86. 161 0
      module/Air780E/demo/iotcloud/oneNET/main.lua
  87. 140 0
      module/Air780E/demo/ipv6/client/main.lua
  88. 45 0
      module/Air780E/demo/ipv6/server/index.html
  89. 212 0
      module/Air780E/demo/ipv6/server/main.lua
  90. 68 0
      module/Air780E/demo/json/main.lua
  91. 217 0
      module/Air780E/demo/jt808/JT808Prot.lua
  92. 89 0
      module/Air780E/demo/jt808/gpsMng.lua
  93. 83 0
      module/Air780E/demo/jt808/main.lua
  94. 86 0
      module/Air780E/demo/jt808/paraCtrl.lua
  95. 211 0
      module/Air780E/demo/jt808/socket_demo.lua
  96. 95 0
      module/Air780E/demo/lbsLoc/main.lua
  97. 35 0
      module/Air780E/demo/lbsLoc2/main.lua
  98. BIN
      module/Air780E/demo/lcd/logo.jpg
  99. 101 0
      module/Air780E/demo/lcd/main.lua
  100. 141 0
      module/Air780E/demo/lcd_custom/main.lua

+ 95 - 0
module/Air780E/.gitignore

@@ -0,0 +1,95 @@
+# Prerequisites
+*.d
+*.luac
+*.lnks
+*.pdf
+.vscode
+vscode.code-workspace
+.idea
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+#*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+bsp/air302/FlashToolCLI/
+bsp/air302/tmp/
+bsp/air302/local*
+bsp/air302/disk/
+*.zip
+tools/java/.classpath
+tools/java/.project
+tools/java/.settings/
+tools/java/target/
+
+bsp/air640w/disk/
+bsp/air640w/tmp/
+bsp/air640w/local*
+
+__pycache__
+*.pyc
+
+*.tlv
+*.fs
+bsp/air302/air302_sdk/**
+/bsp/air724/sdk/out
+/bsp/air724/sdk/hex
+/bsp/air724/sdk/prebuilts/win32
+
+*.cmake
+*.xmake
+
+debug.log
+
+量产文件
+
+CMakefiles
+bsp/win32/build/
+bsp/win32/release/
+bsp/pico/build/
+bsp/linux/build/

+ 21 - 0
module/Air780E/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019-2024 openLuat & AirM2M
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 8 - 0
module/Air780E/README.md

@@ -0,0 +1,8 @@
+
+## 快速入门
+
+TODO
+
+## 授权协议
+
+[MIT License](LICENSE)

+ 21 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/1.Air780E的helloworld教程/main.lua

@@ -0,0 +1,21 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "helloworld"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+-- log.info("main", "hello world")
+
+-- print(_VERSION)
+
+sys.timerLoopStart(function()
+    print("hello world")
+end, 3000)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 168 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/10.Air780E跟服务器之间的加密通信/libnet.lua

@@ -0,0 +1,168 @@
+--[[
+@module libnet
+@summary libnet 在socket库基础上的同步阻塞api,socket库本身是异步非阻塞api
+@version 1.0
+@date    2023.03.16
+@author  lisiqi
+]]
+
+local libnet = {}
+
+--[[
+阻塞等待网卡的网络连接上,只能用于sysplus.taskInitEx创建的任务函数中
+@api libnet.waitLink(taskName,timeout,...)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一致等待
+@... 其他参数和socket.linkup一致
+@return boolean 失败或者超时返回false 成功返回true
+]]
+function libnet.waitLink(taskName, timeout, ...)
+	local succ, result = socket.linkup(...)
+	if not succ then
+		return false
+	end
+	if not result then
+		result = sys_wait(taskName, socket.LINK, timeout)
+	else
+		return true
+	end
+	if type(result) == 'table' and result[2] == 0 then
+		return true
+	else
+		return false
+	end
+end
+
+
+--[[
+阻塞等待IP或者域名连接上,如果加密连接还要等握手完成,只能用于sysplus.taskInitEx创建的任务函数中
+@api libnet.connect(taskName,timeout,...)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一致等待
+@... 其他参数和socket.connect一致
+@return boolean 失败或者超时返回false 成功返回true
+]]
+function libnet.connect(taskName,timeout, ... )
+	local succ, result = socket.connect(...)
+	if not succ then
+		return false
+	end
+	if not result then
+		result = sys_wait(taskName, socket.ON_LINE, timeout)
+	else
+		return true
+	end
+	if type(result) == 'table' and result[2] == 0 then
+		return true
+	else
+		return false
+	end
+end
+
+--[[
+阻塞等待客户端连接上,只能用于sysplus.taskInitEx创建的任务函数中
+@api libnet.listen(taskName,timeout,...)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一致等待
+@... 其他参数和socket.listen一致
+@return boolean 失败或者超时返回false 成功返回true
+]]
+function libnet.listen(taskName,timeout, ... )
+	local succ, result = socket.listen(...)
+	if not succ then
+		return false
+	end
+	if not result then
+		result = sys_wait(taskName, socket.ON_LINE, timeout)
+	else
+		return true
+	end
+	if type(result) == 'table' and result[2] == 0 then
+		return true
+	else
+		return false
+	end
+end
+
+--[[
+阻塞等待数据发送完成,只能用于sysplus.taskInitEx创建的任务函数中
+@api libnet.tx(taskName,timeout,...)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一直等待
+@... 其他参数和socket.tx一致
+@return boolean 失败或者超时返回false,缓冲区满了或者成功返回true
+@return boolean 缓存区是否满了
+]]
+function libnet.tx(taskName,timeout, ...)
+	local succ, is_full, result = socket.tx(...)
+	if not succ then
+		return false, is_full
+	end
+	if is_full then
+		return true, true
+	end
+	if not result then
+		result = sys_wait(taskName, socket.TX_OK, timeout)
+	else
+		return true, is_full
+	end
+	if type(result) == 'table' and result[2] == 0 then
+		return true, false
+	else
+		return false, is_full
+	end
+end
+
+--[[
+阻塞等待新的网络事件,只能用于sysplus.taskInitEx创建的任务函数中,可以通过sysplus.sendMsg(taskName,socket.EVENT,0)或者sys_send(taskName,socket.EVENT,0)强制退出
+@api libnet.wait(taskName,timeout, netc)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一致等待
+@userdata socket.create返回的netc
+@return boolean 网络异常返回false,其他返回true
+@return boolean 超时返回false,有新的网络事件到返回true
+]]
+function libnet.wait(taskName,timeout, netc)
+	local succ, result = socket.wait(netc)
+	if not succ then
+		return false,false
+	end
+	if not result then
+		result = sys_wait(taskName, socket.EVENT, timeout)
+	else
+		return true,true
+	end
+	if type(result) == 'table' then
+		if result[2] == 0 then
+			return true, true
+		else
+			return false, false
+		end
+	else
+		return true, false
+	end
+end
+
+--[[
+阻塞等待网络断开连接,只能用于sysplus.taskInitEx创建的任务函数中
+@api libnet.close(taskName,timeout, netc)
+@string 任务标志
+@int 超时时间,如果==0或者空,则没有超时一致等待
+@userdata socket.create返回的netc
+]]
+function libnet.close(taskName,timeout, netc)
+	local succ, result = socket.discon(netc)
+	if not succ then
+		socket.close(netc)
+		return
+	end
+	if not result then
+		result = sys_wait(taskName, socket.CLOSED, timeout)
+	else
+		socket.close(netc)
+		return
+	end
+	socket.close(netc)
+end
+
+return libnet

+ 202 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/10.Air780E跟服务器之间的加密通信/main.lua

@@ -0,0 +1,202 @@
+--[[
+socket客户端演示
+
+提示: 
+1. socket支持多个连接的, 通常最多支持8个, 可通过不同的taskName进行区分
+2. 支持与http/mqtt/websocket/ftp库同时使用, 互不干扰
+3. 支持IP和域名, 域名是自动解析的, 但解析域名也需要耗时
+4. 加密连接(TLS/SSL)需要更多内存, 这意味着能容纳的连接数会小很多, 同时也更慢
+
+TLS协议及加密套件
+TLS
+TLS 1.0 支持
+TLS 1.1 支持
+TLS 1.2 支持
+TLS 1.3 默认未开启, 未测试
+SSL 3.0, 默认禁用
+
+加密套件请查询:https://wiki.luatos.com/chips/air780e/network.html#tls
+
+如需使用ipv6, 请查阅 demo/ipv6, 本demo只涉及ipv4
+]]
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "scdemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+
+--=============================================================
+-- 测试网站 https://netlab.luatos.com/ 点击 打开TCP 获取测试端口号
+-- 要按实际情况修改
+local host = "112.125.89.8" -- 服务器ip或者域名, 都可以的
+local port = 45186           -- 服务器端口号
+local is_udp = false        -- 如果是UDP, 要改成true, false就是TCP
+local is_tls = true        -- 加密与否, 要看服务器的实际情况
+--=============================================================
+
+-- 处理未识别的网络消息
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+-- 演示task
+local function sockettest()
+    -- 等待联网
+    sys.waitUntil("IP_READY")
+
+    -- 时间同步
+    socket.sntp()
+
+    -- 开始正在的逻辑, 发起socket链接,等待数据/上报心跳
+    local taskName = "sc"
+    local topic = taskName .. "_txrx"
+    log.info("topic", topic)
+    local txqueue = {}
+    --[[创建一个任务线程
+    @param1     function   任务函数名,用于resume唤醒时调用
+    @param2     string     任务名称,用于唤醒任务id
+    @param3     function   接收到非目标消息时的回调函数
+    @param4     any        任务函数fun的可变参数
+    @return     number     返回该任务的线程号
+    ]]
+    sysplus.taskInitEx(sockettask, taskName, netCB, taskName, txqueue, topic)
+    while 1 do
+        local result, tp, data = sys.waitUntil(topic, 30000)
+        log.info("event", result, tp, data)
+        if not result then
+            -- 等很久了,没数据上传/下发, 发个日期心跳包吧
+            table.insert(txqueue, os.date())
+            sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "uplink" then
+            -- 上行数据, 主动上报的数据,那就发送呀
+            table.insert(txqueue, data)
+            sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "downlink" then
+            -- 下行数据,接收的数据, 从ipv6task来的
+            -- 其他代码可以通过 sys.publish()
+            log.info("socket", "收到下发的数据了", #data,"data:",data)
+        end
+    end
+end
+
+function sockettask(d1Name, txqueue, rxtopic)
+    -- 打印准备连接的服务器信息
+    log.info("socket", host, port, is_udp and "UDP" or "TCP", is_tls and "TLS" or "RAW")
+
+    -- 准备好所需要的接收缓冲区
+    local rx_buff = zbuff.create(1024)
+    local netc = socket.create(nil, d1Name)
+    socket.config(netc, nil, is_udp, is_tls)
+    log.info("任务id", d1Name)
+
+    while true do
+        -- 连接服务器, 15秒超时
+        log.info("socket", "开始连接服务器")
+        sysplus.cleanMsg(d1Name)
+        local result = libnet.connect(d1Name, 15000, netc, host, port)
+        if result then
+			log.info("socket", "服务器连上了")
+            --向服务器发送数据
+			libnet.tx(d1Name, 0, netc, "helloworld")
+        else
+            log.info("socket", "服务器没连上了!!!")
+		end
+		while result do
+            -- 连接成功之后, 先尝试接收
+            -- log.info("socket", "调用rx接收数据")
+			local succ, param = socket.rx(netc, rx_buff)
+			if not succ then
+				log.info("服务器断开了", succ, param, ip, port)
+				break
+			end
+            -- 如果服务器有下发数据, used()就必然大于0, 进行处理
+			if rx_buff:used() > 0 then
+				log.info("socket", "收到服务器数据,长度", rx_buff:used())
+                local data = rx_buff:query() -- 获取数据
+                sys.publish(rxtopic, "downlink", data)
+				rx_buff:del()
+			end
+            -- log.info("libnet", "调用wait开始等待消息")
+            -- 等待事件, 例如: 服务器下发数据, 有数据准备上报, 服务器断开连接
+			result, param, param2 = libnet.wait(d1Name, 15000, netc)
+            log.info("libnet", "wait", result, param, param2)
+			if not result then
+                -- 网络异常了, 那就断开了, 执行清理工作
+				log.info("socket", "服务器断开了", result, param)
+				break
+            elseif #txqueue > 0 then
+                -- 有待上报的数据,处理之
+                while #txqueue > 0 do
+                    local data = table.remove(txqueue, 1)
+                    if not data then
+                        break
+                    end
+                    result,param = libnet.tx(d1Name, 15000, netc,data)
+                    log.info("libnet", "发送数据的结果", result, param)
+                    if not result then
+                        log.info("socket", "数据发送异常", result, param)
+                        break
+                    end
+                end
+            end
+            -- 循环尾部, 继续下一轮循环
+		end
+        -- 能到这里, 要么服务器断开连接, 要么上报(tx)失败, 或者是主动退出
+		libnet.close(d1Name, 5000, netc)
+		-- log.info(rtos.meminfo("sys"))
+		sys.wait(30000) -- 这是重连时长, 自行调整
+    end
+end
+
+sys.taskInit(sockettest)
+
+-- 演示定时上报数据, 不需要就注释掉
+sys.taskInit(function()
+    sys.wait(5000)
+    while 1 do
+        sys.publish("sc_txrx", "uplink", os.date())
+        sys.wait(10000)
+    end
+end)
+
+-- 演示uart数据上报, 不需要就注释掉
+if rtos.bsp() == "EC618" then
+    uart.setup(1, 115200) -- 注意, 是UART1, 不是虚拟串口, 演示目的
+    uart.on(1, "receive", function(id, len)
+        while 1 do
+            local s = uart.read(1, 1024)
+            if #s == 0 then
+                break
+            end
+            sys.publish("sc_txrx", "uplink", s)
+            if #s == len then
+                break
+            end
+        end
+    end)
+end
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 74 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/11.Air780E怎么获取精准的时钟/main.lua

@@ -0,0 +1,74 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "timeDemo"
+VERSION = "1.0"
+
+--[[
+本demo需要mqtt库, 大部分能联网的设备都具有这个库
+mqtt也是内置库, 无需require
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用mqtt库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+sys.taskInit(function ()
+        -- 等待联网
+        sys.waitUntil("IP_READY")
+        sys.wait(1000)
+        -- 对于Cat.1模块, 移动/电信卡, 通常会下发基站时间,  那么sntp就不是必要的, 而联通卡通常不会下发, 就需要sntp了
+        -- 对应ESP32系列模块, 固件默认也会执行sntp, 所以手动调用sntp也是可选的
+        -- sntp内置了几个常用的ntp服务器, 也支持自选服务器
+        while 1 do
+            -- 使用内置的ntp服务器地址, 包括阿里ntp
+            log.info("开始执行SNTP")
+            socket.sntp()
+            -- 自定义ntp地址
+            -- socket.sntp("ntp.aliyun.com")
+            -- socket.sntp({"baidu.com", "abc.com", "ntp.air32.cn"})
+            -- 通常只需要几百毫秒就能成功
+            local ret = sys.waitUntil("NTP_UPDATE", 5000)
+            if ret then
+                -- 以下是获取/打印时间的演示,注意时区问题
+                log.info("sntp", "时间同步成功", "本地时间", os.date())
+                log.info("sntp", "时间同步成功", "UTC时间", os.date("!%c"))
+                log.info("sntp", "时间同步成功", "RTC时钟(UTC时间)", json.encode(rtc.get()))
+                -- os.time(rtc.get()) 需要 2023.07.21 之后的版本, 因为月份的命名差异mon/month
+                -- log.info("sntp", "时间同步成功", "utc时间戳", os.time(rtc.get()))
+                log.info("sntp", "时间同步成功", "本地时间戳", os.time())
+                local t = os.date("*t")
+                log.info("sntp", "时间同步成功", "本地时间os.date() json格式", json.encode(t))
+                log.info("sntp", "时间同步成功", "本地时间os.date(os.time())", os.time(t))
+                -- log.info("sntp", "时间同步成功", "本地时间", os.time())
+                -- 正常使用, 一小时一次, 已经足够了, 甚至1天一次也可以
+                -- sys.wait(3600000) 
+                -- 这里为了演示, 用5秒一次
+                sys.wait(5000)
+            else
+                log.info("sntp", "时间同步失败")
+                sys.wait(60000) -- 1分钟后重试
+            end
+    
+            -- 时间戳, 精确到毫秒. 2023.11.15 新增
+            -- 注意, 至少成功完成2次sntp,该时间戳才比较准确
+            -- 如果仅完成了一次sntp, 时间戳比标准时间会慢一个网络延时的时长(10~500ms)不等
+            if socket.ntptm then
+                local tm = socket.ntptm()
+                log.info("tm数据", json.encode(tm))
+                log.info("时间戳", string.format("%u.%03d", tm.tsec, tm.tms))
+                sys.wait(5000)
+            end
+        end
+    
+end)
+
+sys.subscribe("NTP_ERROR", function()
+    log.info("socket", "sntp error")
+    -- socket.sntp()
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 88 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/12.通过腾讯连连小程序控制灯的亮灭/main.lua

@@ -0,0 +1,88 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "iotclouddemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用mqtt库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+local iotcloud = require("iotcloud")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+local product_id = "58JE68ZUHO"
+local product_key = "oncUYTstf0rak67j3PsvIWWh"
+local device_id = mobile.imei()
+
+-- 统一联网函数
+sys.taskInit(function()
+    local device_id = mcu.unique_id():toHex()
+    if mobile then
+        -- Air780E/Air600E系列
+        --mobile.simid(2) -- 自动切换SIM卡
+        LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+    end
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready", device_id)
+end)
+
+sys.taskInit(function()
+    -- 等待联网
+    local ret, device_id = sys.waitUntil("net_ready")
+    -- -- 动态注册
+    iotcloudc = iotcloud.new(iotcloud.TENCENT,{produt_id = product_id ,product_secret = product_key})
+
+    if iotcloudc then
+        iotcloudc:connect()
+    end
+end)
+
+sys.subscribe("iotcloud", function(cloudc,event,data,payload)
+    -- 注意,此处不是协程内,复杂操作发消息给协程内进行处理
+    if event == iotcloud.CONNECT then -- 云平台联上了
+        print("iotcloud","CONNECT", "云平台连接成功")
+        iotcloudc:subscribe("$thing/down/property/"..product_id.."/"..device_id) -- 可以自由定阅主题等
+    elseif event == iotcloud.RECEIVE then
+        print("iotcloud","topic", data, "payload", payload)
+        local iot_msg = json.decode(payload)
+        local led_value = iot_msg["params"]["power_switch"] 
+        print("led_value:", led_value)
+
+        if led_value == 1 then
+            LED(1)
+        elseif led_value == 0 then
+            LED(0)
+        end
+        -- 用户处理代码
+    elseif event ==  iotcloud.OTA then
+        if data then
+            rtos.reboot()
+        end
+    elseif event == iotcloud.DISCONNECT then -- 云平台断开了
+        -- 用户处理代码
+        print("iotcloud","DISCONNECT", "云平台连接断开")
+    end
+end)
+
+-- -- 每隔20秒发布一次qos为1的消息到云平台
+-- sys.taskInit(function()
+--     while 1 do
+--         sys.wait(20000)
+--         if iotcloudc then
+--             log.info("每隔20秒发布一次qos为1的消息到云平台,消息内容hello world")
+--             iotcloudc:publish("$thing/up/property/"..product_id.."/"..device_id, "hello world!", 1) -- 上传数据
+--         end
+--     end
+-- end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 25 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/2.用Air780E的本地脚本控制灯的亮和灭/main.lua

@@ -0,0 +1,25 @@
+PROJECT = "GPIO_TEST_DEMO"
+VERSION = "1.0.0"
+
+--除了sys和sysplus库需要require,其他的底层库不需要require了
+sys = require("sys")
+
+--[[
+    @param1 引脚号
+    @param2 配置输入输出模式,0是输出模式
+    @param3 配置上下拉,gpio.PULLUP是上拉模式
+]]
+gpio.setup(27, 0, gpio.PULLUP)
+
+sys.taskInit(function()
+    while 1 do
+        --翻转引脚27的电平状态
+        gpio.toggle(27)
+        --延时1000ms
+        sys.wait(1000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()

+ 123 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/3.用电脑浏览器通过Air780E控制灯的亮和灭/main.lua

@@ -0,0 +1,123 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "udpsrvdemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+-- =============================================================
+-- 测试网站 https://netlab.luatos.com/ 点击 打开UDP 获取测试端口号
+-- 要按实际情况修改
+local host = "netlab.luatos.com" -- 服务器ip或者域名, 都可以的
+local port = 47966 -- 服务器端口号
+local is_udp = true -- 如果是UDP, 要改成true, false就是TCP
+local is_tls = false -- 加密与否, 要看服务器的实际情况
+-- =============================================================
+
+-- 设置灯的输出模式
+gpio.setup(27, 0, gpio.PULLUP)
+
+sys.taskInit(function()
+    while 1 do
+        local result, rx_data = sys.waitUntil("sc_txrx", 30000)
+        if result then
+            log.info("sys.waitUntil接收到数据")
+            --[[在接收的数据rx_data中,寻找ledon出现的位置,如果找到
+                会返回第一次出现的位置和最后出现的位置。
+            ]]
+            local s, e = string.find(rx_data, "ledon")
+            if s == 1 and e == 5 then
+                gpio.set(27, 1)
+                log.info("开灯")
+            end
+            local s2, e2 = string.find(rx_data, "ledoff")
+            if s2 == 1 and e2 == 6 then
+                gpio.set(27, 0)
+                log.info("关灯")
+            end
+        else
+            log.info("发布keepalive,waitUntil的返回值为: ", result)
+            -- 发送心跳
+            sys.publish("keepalive")
+        end
+    end
+end)
+
+-- 连接函数
+-- function socketTask(rxtopic)
+sys.taskInit(function()
+    sys.waitUntil("IP_READY")
+    -- 创建一个用于接收UDP服务器下发数据的数组
+    local rx_buff = zbuff.create(1024)
+
+    -- 申请一个socket_ctrl
+    local netc = socket.create(nil)
+    --[[配置network一些信息
+        @param1 socket_ctrl
+        @param2 本地端口号,不写会自动分配一个
+        @parma3 是否是UDP
+        @param4 是否是加密传输
+    ]]
+    local config_succ = socket.config(netc, nil, is_udp, false)
+    if not config_succ then
+        log.info("socket.config", "服务器配置失败")
+    end
+
+    -- 订阅心跳消息
+    sys.subscribe("keepalive", function()
+        succ, full, result = socket.tx(netc, "keepalive" .. os.date())
+        log.info("socket", "心跳包发送数据的结果", succ, full, result)
+    end)
+
+    while config_succ do
+        --[[连接服务器,超时时间15秒
+            @param1 任务id
+            @param2 连接超时时间
+            @param3 socket_ctrl
+            @param4 ip地址或域名
+            @param5 服务器端口号
+            @param6 域名解析是否要IPV6,默认false,只有支持IPV6的协议栈才有效果
+            return 失败或超时返回false,成功返回true
+        ]]
+        local succ,result = socket.connect(netc, host, port)
+        if succ then
+            log.info("socket", "服务器连接成功")
+            sys.wait(1000)
+            --[[发一个数据试试是否连接成功
+                @param1 socket.create()创建的socket_ctrl
+                @param2 要发送的数据
+            ]]
+            socket.tx(netc, "hello world!!!")
+        end
+
+        -- 连接服务器成功后,开始进行接收服务器数据操作
+        while succ do
+            --[[先接收一次数据包,数据已经缓存在底层,使用本函数只是提取出来
+                @param1 socket_ctrl
+                @param2 存放接收数据的zbuff
+            ]]
+            local succ, rx_len = socket.rx(netc, rx_buff)
+            --[[对接收到的数据进行处理
+                rx_buff:used()代表rx_buff内的数据长度
+            ]]
+            if rx_buff:used() > 0 then
+                local rx_data = rx_buff:query()
+                log.info("socket", "接收到的数据为:", rx_data)
+                sys.publish("sc_txrx", rx_data)
+                rx_buff:del()
+            end
+
+            -- 等待接收数据处理完成
+            sys.wait(500)
+        end
+        sys.wait(2000)
+    end
+    socket.close(netc)
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()

+ 118 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/4.通过Air780E采集温湿度传感器数据并实现网页查看/main.lua

@@ -0,0 +1,118 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "udpsrvdemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+-- =============================================================
+-- 测试网站 https://netlab.luatos.com/ 点击 打开UDP 获取测试端口号
+-- 要按实际情况修改
+local host = "netlab.luatos.com" -- 服务器ip或者域名, 都可以的
+local port = 47966 -- 服务器端口号
+local is_udp = true -- 如果是UDP, 要改成true, false就是TCP
+local is_tls = false -- 加密与否, 要看服务器的实际情况
+-- =============================================================
+
+--设置dht11传感器的out引脚与780E开发板的连接引脚
+local dht11_pin = 7
+
+sys.taskInit(function()
+    while 1 do
+        local result, rx_data = sys.waitUntil("sc_txrx", 30000)
+        if not result then
+            log.info("发布keepalive,waitUntil的返回值为: ", result)
+            -- 如果sys.waitUntil30秒内没收到消息sc_txrx,则发送一次心跳
+            sys.publish("keepalive")
+        end
+    end
+end)
+
+-- 连接函数
+sys.taskInit(function()
+    sys.waitUntil("IP_READY")
+
+    -- 申请一个socket_ctrl
+    local netc = socket.create(nil,"MySocket")
+    --[[配置network一些信息
+        @param1 socket_ctrl
+        @param2 本地端口号,不写会自动分配一个
+        @parma3 是否是UDP
+        @param4 是否是加密传输
+    ]]
+    local config_succ = socket.config(netc, nil, is_udp, is_tls)
+    if not config_succ then
+        log.info("socket.config", "服务器配置失败")
+    end
+
+    -- 订阅心跳消息
+    sys.subscribe("keepalive", function()
+        succ, full, result = socket.tx(netc, "keepalive" .. os.date())
+        log.info("socket", "心跳包发送数据的结果", succ, full, result)
+    end)
+
+    while config_succ do
+        --[[连接服务器,超时时间15秒
+            @param1 任务id
+            @param2 连接超时时间
+            @param3 socket_ctrl
+            @param4 ip地址或域名
+            @param5 服务器端口号
+            @param6 域名解析是否要IPV6,默认false,只有支持IPV6的协议栈才有效果
+            return 失败或超时返回false,成功返回true
+        ]]
+        local succ,result = socket.connect(netc, host, port)
+        if succ then
+            log.info("socket", "服务器连接成功")
+            sys.wait(1000)
+            --[[发一个数据试试是否连接成功
+                @param1 socket.create()创建的socket_ctrl
+                @param2 要发送的数据
+            ]]
+            socket.tx(netc, "hello world!!!")
+        else
+            log.info("socket", "服务器连接失败")
+        end
+
+        -- 连接服务器成功后,开始进行向服务器发送温湿度数据操作
+        while succ do
+            --[[读取dht11传感器的数值
+                @param1  dht11的out引脚连接780E开发板的引脚号
+                @param2  是否校验读取到的值,true为校验
+                @return1 湿度值,单位为0.01%
+                @return2 温度值 单位为0.01%
+                @return  成功返回true,失败返回false
+            ]]
+            local h,t,r = sensor.dht1x(dht11_pin, true)
+            if r then
+                --[[
+                    ..为字符串的连接符,
+                    例如log.info("hello".."world")打印出来就是helloworld
+                ]]
+                local data = "湿度:".. (h/100) .. "\r\n".. "温度:".. (t/100)
+                log.info("dht1x",data)
+                --将温湿度的数据上传到web服务器
+                local succ,full,result = socket.tx(netc,data)
+                if not succ then
+                    log.info("socket","温湿度数据上传失败")
+                end
+                --[[如果成功向web服务器上传了数据,则发布消息"sc_txrx"
+                    如果在30秒内没发送过消息,则会发一个心跳指令
+                ]]
+                sys.publish("sc_txrx")
+            else
+                log.info("温湿度值校验失败")
+            end
+            sys.wait(3000)
+        end
+        sys.wait(2000)
+    end
+    socket.close(netc)
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()

+ 53 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/5.Air780E固件的远程升级/main.lua

@@ -0,0 +1,53 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fotademo"
+VERSION = "1.0.0"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "qubOK4pUnggHYGye1L7GNAdsPXTcDLbb" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+sys = require "sys"
+libfota = require "libfota"
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+-- 统一联网函数
+sys.taskInit(function()
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready")
+end)
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(5000)
+        log.info("fota", "version", VERSION)
+        local bsp_version = rtos.version()
+        log.info("当前core版本:",bsp_version)
+    end
+end)
+
+
+function fota_cb(ret)
+    log.info("fota", ret)
+    if ret == 0 then
+        rtos.reboot()
+    end
+end
+
+-- 使用合宙iot平台进行升级
+sys.taskInit(function()
+    sys.waitUntil("net_ready")
+    libfota.request(fota_cb)
+end)
+sys.timerLoopStart(libfota.request, 3600000, fota_cb)
+
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 126 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/6.通过Air780E的MQTT的连接实现远程控制/main.lua

@@ -0,0 +1,126 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "mqttdemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用mqtt库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+--根据自己的服务器修改以下参数
+local mqtt_host = "lbsmqtt.airm2m.com"
+local mqtt_port = 1884
+local mqtt_isssl = false
+local client_id = "mqttx_b55c41b7"
+local user_name = "user"
+local password = "password"
+
+local mqttc = nil
+
+sys.taskInit(function()
+    -- 等待联网
+    sys.waitUntil("IP_READY")
+    -- 获取设备的imei号
+    local device_id = mcu.unique_id():toHex()
+    -- 下面的是mqtt的参数均可自行修改
+    client_id = device_id
+    pub_topic = "/luatos/pub/" .. device_id
+    sub_topic = "/luatos/sub/" .. device_id
+
+    -- 打印一下上报(pub)和下发(sub)的topic名称
+    log.info("mqtt", "pub", pub_topic)
+    log.info("mqtt", "sub", sub_topic)
+
+    --[[
+        @param1 适配器序号,不填会选择平台自带的
+        @param2 服务器地址,域名或ip都可
+        @param3 端口号
+        @param4 是否为ssl加密连接
+        @param5 是否为ipv6
+    ]]
+    mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl, ca_file)
+
+    --[[配置mqtt连接服务器的参数
+        @param1 设备id
+        @param2 账号[可选]
+        @param3 密码[可选]
+        @param4 清除session,默认true[可选]
+    ]]
+    mqttc:auth(client_id,user_name,password) -- client_id必填,其余选填
+    --设置心跳
+    -- mqttc:keepalive(240) -- 默认值240s
+
+    --[[
+        @param1 是否自动重连
+        @param2 自动重连机制,单位ms
+    ]]
+    mqttc:autoreconn(true, 3000) -- 自动重连机制
+
+    --[[mqtt事件回调函数,其中事件包括
+        conack:连接成功事件。
+        recv:接收服务器下发数据的事件
+        sent:发送完成事件
+        disconnect:断开连接事件
+        ]]
+    --[[回调函数参数:@param1 mqtt的句柄
+        @param2 事件
+        @param3 
+    ]]
+    mqttc:on(function(mqtt_client, event, data, payload)
+        -- 用户自定义代码
+        log.info("mqtt", "event", event, mqtt_client, data, payload)
+        if event == "conack" then
+            -- mqtt连接上服务器后,发布一条消息。订阅一个mqtt主题
+            sys.publish("mqtt_conack")
+            mqtt_client:subscribe(sub_topic)--单主题订阅
+            -- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
+        elseif event == "recv" then
+            log.info("mqtt", "downlink", "topic", data, "payload", payload)
+        elseif event == "sent" then
+        end
+    end)
+
+    -- mqttc自动处理重连, 除非自行关闭
+    mqttc:connect()
+    --等待连接成功
+	sys.waitUntil("mqtt_conack")
+    while true do
+        -- 演示等待其他task发送过来的上报信息
+        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
+        if ret then
+            -- 当接收到的tpoic是字符串close时,就跳出等待其他task发过来的上报消息的循环
+            if topic == "close" then break end
+            mqttc:publish(topic, data, qos)
+        end
+    end
+    --跳出等待上报消息的循环后,就关闭close
+    mqttc:close()
+    --删除创建的mqtt实例
+    mqttc = nil
+end)
+
+-- 定时上报数据演示
+sys.taskInit(function()
+    sys.wait(3000)
+	local data = "123test,"
+	local qos = 0 -- QOS0不带puback, QOS1是带puback的
+    while true do
+        sys.wait(3000)
+        --如果mqttc实例存在,并且mqtt客户端就绪
+        if mqttc and mqttc:ready() then
+            --发布一个mqtt消息,这个消息的订阅,在mqtt服务器上
+            local pkgid = mqttc:publish(pub_topic, data .. os.date(), qos)
+        end
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

BIN
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/7.通过Air780E驱动SPI小屏幕的详细讲解/logo.jpg


+ 129 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/7.通过Air780E驱动SPI小屏幕的详细讲解/main.lua

@@ -0,0 +1,129 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lcddemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--[[
+-- LCD接法示例
+LCD管脚       Air780E管脚            
+GND          GND                          
+VCC          3.3V                      
+SCL          (GPIO11)          
+SDA          (GPIO09)         
+RES          (GPIO01)       
+DC           (GPIO10)       
+CS           (GPIO08)       
+BL(可以不接)  (GPIO22)      
+
+提示:
+1. 只使用SPI的时钟线(SCK)和数据输出线(MOSI), 其他均为GPIO脚
+2. 数据输入(MISO)和片选(CS), 虽然是SPI, 但已复用为GPIO, 并非固定,是可以自由修改成其他脚
+3. 若使用多个SPI设备, 那么RES/CS请选用非SPI功能脚
+4. BL可以不接的
+]]
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+local spi_id    =   0
+local pin_reset =   1
+local pin_dc    =   10
+local pin_cs    =   8
+local bl        =   22
+
+--[[设置并启用SPI
+    @param1 SPI号
+    @param2 cs片选引脚
+    @param3 CPHA 默认0,可选0/1
+    @param4 CPOL 默认0,可选0/1
+    @param5 数据宽度,默认8bit
+    @param6 波特率,默认20M=20000000
+    @param7 大小端, 默认spi.MSB, 可选spi.LSB
+    @return spi_device 
+]]
+spi_lcd = spi.deviceSetup(spi_id,pin_cs,0,0,8,20*1000*1000,spi.MSB,1,0)
+port = "device"
+
+--[[ 此为合宙售卖的1.8寸TFT LCD LCD 分辨率:128X160 屏幕ic:st7735 购买地址:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-24045920841.19.6c2275a1Pa8F9o&id=560176729178]]
+--[[lcd显示屏初始化
+    @param1 lcd类型
+    @param2 附加参数,table
+    @param3 spi设备,当port = “device”时有效
+    @param4 允许初始化在lcd service里运行,默认是false
+]]
+lcd.init("st7735",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 128,h = 160,xoffset = 0,yoffset = 0},spi_lcd)
+
+--[[ 此为合宙售卖的0.96寸TFT LCD LCD 分辨率:160X80 屏幕ic:st7735s 购买地址:https://item.taobao.com/item.htm?id=661054472686]]
+--lcd.init("st7735v",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 1,w = 160,h = 80,xoffset = 0,yoffset = 24},spi_lcd)
+
+--如果显示颜色相反,请解开下面一行的注释,关闭反色
+--lcd.invoff()
+--0.96寸TFT如果显示依旧不正常,可以尝试老版本的板子的驱动
+-- lcd.init("st7735s",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 2,w = 160,h = 80,xoffset = 0,yoffset = 0},spi_lcd)
+
+-- 不在内置驱动的, 看上一级目录的demo/lcd_custom
+
+sys.taskInit(function()
+    -- 开启缓冲区, 刷屏速度会加快, 但也消耗2倍屏幕分辨率的内存
+    -- lcd.setupBuff()          -- 使用lua内存
+    -- lcd.setupBuff(nil, true) -- 使用sys内存, 只需要选一种
+    -- lcd.autoFlush(false)
+
+    while 1 do 
+        -- 清屏,默认背景色
+        lcd.clear()
+        --log.info("wiki", "https://wiki.luatos.com/api/lcd.html")
+        -- API 文档 https://wiki.luatos.com/api/lcd.html
+        if lcd.showImage then
+            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
+            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
+            -- 判断要显示的图片是否存在
+            log.info("文件/luadb/logo.jpg是否存在",io.exists("/luadb/logo.jpg")) 
+            --[[显示图片,当前只支持jpg,jpeg
+                @param1 x坐标
+                @param2 y坐标
+                @param3 文件路径
+            ]]
+            lcd.showImage(40,0,"/luadb/logo.jpg")
+            sys.wait(1000)
+            
+        end
+        --[[在两点之间画一条线
+            @param1 第一个点的X位置
+            @param2 第一个点的y位置
+            @param3 第二个点的x位置
+            @param4 第二个点的y位置
+            @param5 绘画颜色,默认前景色[可选]
+        ]]
+        log.info("lcd.drawLine", lcd.drawLine(10,90,80,90,0x001F))
+        --[[从x / y位置(左上边缘)开始绘制一个框
+            @param1 左上边缘的X位置
+            @param2 左上边缘的Y位置
+            @param3 右下边缘的X位置
+            @param4 右下边缘的Y位置
+            @param5 绘画颜色,默认前景色[可选]
+        ]]
+        log.info("lcd.drawRectangle", lcd.drawRectangle(10,110,50,140,0xF800))
+        --[[从x / y位置(圆心)开始绘制一个圆
+            @param1 圆心的X位置
+            @param2 圆心的Y位置
+            @param3 半径
+            @param4 绘画颜色,默认前景色[可选]
+        ]]
+        log.info("lcd.drawCircle", lcd.drawCircle(100,120,20,0x0CE0))
+        sys.wait(1000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 56 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/8.Air780E的文件系统对温湿度的存储和上报/main.lua

@@ -0,0 +1,56 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "filedemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+sys = require("sys")
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(5000)
+        --采集温湿度数据,该引脚需要接开发板上一个带上拉5k电阻的引脚
+        local hum,tem,result = sensor.dht1x(7,true)
+        log.info("hum:",hum/100,"tem:",tem/100,result)
+
+        if result then
+            --[[打印文件系统信息
+            @param1 获取是否成功
+            @param2 总的block数量
+            @param3 已使用的block数量
+            @param4 block的大小,单位字节
+            @param5 文件系统类型,例如lfs代表littlefs
+            ]]
+            log.info("result,总block,已使用block,block大小,类型",fs.fsstat())
+            --拼接温湿度和结果数据
+            local fullData = hum..tem..tostring(result)
+            --将温湿度数据写入文件中
+            local res_wri = io.writeFile("/dht1.txt", fullData)
+            --打印写入结果
+            log.info("writeFile result",res_wri)
+            --读取温湿度数据
+            local readData = io.readFile("/dht1.txt")
+            --[[string.sub(s,i,j)
+                返回字符串s中的位置i到位置j的数据
+            ]]
+            log.info("文件读取的数据","hum:",string.sub(readData,1,4)/100,"tem:",string.sub(readData,5,8)/100,string.sub(readData,9,12))
+        else
+            log.info("温湿度值校验失败")
+        end
+
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+
+-- tcs3472 下载固件和脚本

+ 103 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/functionTest.lua

@@ -0,0 +1,103 @@
+local server_ip = "112.125.89.8"    --换成自己的,demo用UDP服务器,如果用TCP服务器,目前需要在用极致功耗模式时先断开服务器
+local server_port = 45147 --换成自己的
+-- local period = 1800000 --默认30分钟变化一次模式
+local period = 300000
+
+local reason, slp_state = pm.lastReson()
+log.info("wakeup state", pm.lastReson())
+if reason > 0 then
+    log.info("已经从深度休眠唤醒")
+    pm.power(pm.WORK_MODE,3)
+else
+    sys.taskInit(function()
+        -- log.info("High Performance")
+        -- pm.power(pm.WORK_MODE,1)
+        -- sys.wait(period)
+        -- log.info("Balanced")
+        -- pm.power(pm.WORK_MODE,2)
+        -- sys.wait(period)
+        log.info("no low power")
+        pm.power(pm.WORK_MODE,0)
+        sys.wait(period)
+        log.info("power save")
+        pm.power(pm.WORK_MODE,3)
+        pm.dtimerStart(3, period)
+		--AGPIO3 nil代表输入模式
+        gpio.setup(23,nil)
+        gpio.close(35)
+		--AGPIOWU0
+		gpio.setup(20, function()
+			log.info("gpio")
+		end, gpio.PULLUP, gpio.FALLING)
+        sys.wait(period)
+    end)
+end
+
+local libnet = require "libnet"
+
+local d1Name = "D1_TASK"
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+local function testTask(ip, port)
+	d1Online = false
+	local tx_buff = zbuff.create(1024)
+	local rx_buff = zbuff.create(1024)
+	local netc 
+	local result, param, is_err
+	netc = socket.create(nil, d1Name)
+	socket.debug(netc, false)
+	socket.config(netc, nil, true, nil) -- demo用UDP服务器,如果用TCP服务器,目前需要在用极致功耗模式时先断开服务器
+	-- socket.config(netc, nil, true)
+	while true do
+		log.info(rtos.meminfo("sys"))
+		result = libnet.waitLink(d1Name, 0, netc)
+		result = libnet.connect(d1Name, 15000, netc, ip, port)
+		-- result = libnet.connect(d1Name, 5000, netc, "112.125.89.8",34607)
+		d1Online = result
+		if result then
+			log.info("服务器连上了")
+			libnet.tx(d1Name, 0, netc, "helloworld")
+            if reason > 0 then
+                pm.dtimerStart(3, period)
+                gpio.setup(23,nil)
+                gpio.close(35)
+				gpio.setup(20, function()
+					log.info("gpio")
+				end, gpio.PULLUP, gpio.FALLING)
+                sys.wait(period) 
+            end
+		end
+		while result do
+			succ, param, _, _ = socket.rx(netc, rx_buff)
+			if not succ then
+				log.info("服务器断开了", succ, param, ip, port)
+				break
+			end
+			if rx_buff:used() > 0 then
+				log.info("收到服务器数据,长度", rx_buff:used())
+				uart.tx(uart_id, rx_buff)
+				rx_buff:del()
+			end
+			if tx_buff:len() > 1024 then
+				tx_buff:resize(1024)
+			end
+			if rx_buff:len() > 1024 then
+				rx_buff:resize(1024)
+			end
+			log.info(rtos.meminfo("sys"))
+			-- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
+			result, param = libnet.wait(d1Name, 300000, netc)
+			if not result then
+				log.info("服务器断开了", result, param)
+				break
+			end
+		end
+		d1Online = false
+		libnet.close(d1Name, 5000, netc)
+		log.info(rtos.meminfo("sys"))
+		sys.wait(1000)
+	end
+end
+sysplus.taskInitEx(testTask, d1Name, netCB, server_ip, server_port)

+ 18 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/main.lua

@@ -0,0 +1,18 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "socket_low_power"
+VERSION = "1.0"
+PRODUCT_KEY = "123" --换成自己的
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+log.style(1)
+
+
+-- require "functionTest"
+require "psm_plus"
+-- require "remote_net_wakeup"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 75 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/psm_plus.lua

@@ -0,0 +1,75 @@
+local server_ip = "112.125.89.8"    --如果用TCP服务器,目前需要在用极致功耗模式时先断开服务器
+local server_port = 46391  --换成自己的
+-- local period = 3* 60* 60 * 1000 --3小时唤醒一次
+local period = 60 * 1000 --60秒唤醒一次
+
+local reason, slp_state = pm.lastReson()  --获取唤醒原因
+log.info("wakeup state", pm.lastReson())
+local libnet = require "libnet"
+
+local d1Name = "D1_TASK"
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+local function testTask(ip, port)
+    local txData
+    if reason == 0 then
+        txData = "normal wakeup"
+    elseif reason == 1 then
+        txData = "timer wakeup"
+    elseif reason == 2 then
+        txData = "pad wakeup"
+    elseif reason == 3 then
+        txData = "uart1 wakeup"
+    end
+    if slp_state > 0 then
+        mobile.flymode(0,false) -- 退出飞行模式,进入psm+前进入飞行模式,唤醒后需要主动退出
+    end
+
+    gpio.close(32)
+
+	local netc, needBreak
+	local result, param, is_err
+	netc = socket.create(nil, d1Name)
+	socket.debug(netc, false)
+	socket.config(netc) -- demo用TCP服务器,目前需要在用极致功耗模式时先断开服务器
+    local retry = 0
+	while retry < 3 do
+		log.info(rtos.meminfo("sys"))
+		result = libnet.waitLink(d1Name, 0, netc)
+		result = libnet.connect(d1Name, 5000, netc, ip, port)
+		if result then
+			log.info("服务器连上了")
+            result, param = libnet.tx(d1Name, 15000, netc, txData)
+			if not result then
+				log.info("服务器断开了", result, param)
+				break
+			else
+                needBreak = true
+            end
+		else
+            log.info("服务器连接失败")
+        end
+		libnet.close(d1Name, 5000, netc)
+        retry = retry + 1
+        if needBreak then
+            break
+        end
+	end
+   
+    uart.setup(1, 9600)     --配置uart1,外部唤醒用
+    gpio.setup(23,nil)      --AGPIO3设置为输入模式
+    gpio.close(35)          --这里pwrkey接地才需要,不接地通过按键控制的不需要
+    gpio.setup(32, function() --配置wakeup中断,外部唤醒用
+        log.info("gpio")
+    end, gpio.PULLUP, gpio.FALLING)
+    pm.dtimerStart(3, period)  --启动深度休眠定时器
+    mobile.flymode(0,true)     --进入飞行模式
+    pm.power(pm.WORK_MODE,3)   --进入极致功耗模式
+    log.info("获取内存信息",rtos.meminfo("sys"))   --获取内存信息,sys:系统内存
+    sys.wait(15000)   --demo演示唤醒时间是一分钟,如果15s后模块重启,则说明进入极致功耗模式失败,
+    log.info("进入极致功耗模式失败,尝试重启")
+    rtos.reboot()
+end
+sysplus.taskInitEx(testTask, d1Name, netCB, server_ip, server_port)

+ 111 - 0
module/Air780E/demo/Air780E的LuatOS开发快速入门文档适配demo/9.500毫安的电池,怎么让Air780E续航10年/remote_net_wakeup.lua

@@ -0,0 +1,111 @@
+-- netlab.luatos.com上打开TCP,然后修改IP和端口号,自动回复netlab下发的数据,自收自发测试
+
+local server_ip = "112.125.89.8"
+local server_port = 46391
+local rxbuf = zbuff.create(8192)
+
+local socketIsConnected = false
+
+local socketTxCycle = 5 * 1000
+local socketWaitTxSuccess = 15 * 1000
+local socketTxQueue = {}
+
+local function insertData(data)
+    if #socketTxQueue >= 10 then -- 缓存10条消息
+        return
+    end
+
+    table.insert(socketTxQueue , data)
+    if #socketTxQueue == 1 then
+        sys.publish("SOCKET_APP_NEW_SOCKET")
+    end
+end
+
+local function heartTimerCb()
+    insertData("heart")
+end  
+
+local function netCB(netc, event, param)
+    log.info("netc", netc, event, param)
+    if param ~= 0 then
+        socketIsConnected = false
+        sys.timerStop(heartTimerCb)
+        sys.publish("socket_disconnect")
+        return
+    end
+	if event == socket.LINK then
+	elseif event == socket.ON_LINE then
+        socketIsConnected = true
+        sys.timerLoopStart(heartTimerCb, 60000)
+        sys.publish("SOCKET_APP_IS_READY")
+        insertData("hello,luatos!")
+	elseif event == socket.EVENT then
+        socket.rx(netc, rxbuf)
+        socket.wait(netc)
+        if rxbuf:used() > 0 then
+            insertData("recv ok")
+        end
+        rxbuf:del()
+	elseif event == socket.TX_OK then
+        socket.wait(netc)
+        log.info("发送完成")
+        sys.publish("SOCKET_TX_OK")
+	elseif event == socket.CLOSED then
+        socketIsConnected = false
+        sys.timerStop(heartTimerCb)
+        sys.publish("socket_disconnect")
+    end
+end
+
+local netc = socket.create(nil, netCB)
+
+local function socketTask()
+	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
+
+sys.taskInit(function ()
+    local needWait
+    while true do
+        if socketIsConnected then
+            if #socketTxQueue >= 1 then
+                local txData = table.remove(socketTxQueue, 1)
+                local succ, full, result = socket.tx(netc, txData)
+                if succ then
+                    local result = sys.waitUntil("SOCKET_TX_OK", socketWaitTxSuccess)
+                    log.info("result", result)
+                else
+                    socketIsConnected = false
+                    sys.publish("socket_disconnect")
+                end
+            else
+                sys.waitUntil("SOCKET_APP_NEW_SOCKET")
+            end
+        else
+            sys.waitUntil("SOCKET_APP_IS_READY") 
+        end
+    end
+end)
+
+
+function socketDemo()
+    gpio.setup(23,nil)
+    gpio.setup(32, function()
+        insertData("wakeup data")
+    end, gpio.PULLUP, gpio.FALLING)
+    pm.power(pm.WORK_MODE, 3)
+	sys.taskInit(socketTask)
+end
+socketDemo()

+ 68 - 0
module/Air780E/demo/README.md

@@ -0,0 +1,68 @@
+# LuatOS 演示代码
+
+## 重要提示
+
+库的demo通常都需要配合最新的固件, 如果发现demo有问题, 请先确认是不是最新固件.
+
+最新固件下载地址: https://gitee.com/openLuat/LuatOS/releases
+
+## demo的适用性
+
+* 如果有子文件夹, 例如Air101, 代表该demo可能只适合对应的硬件使用. 但Air101/Air103/W806属于同一类型, 基本通用.
+* 不带子文件的,通常是通用demo, 与具体硬件无关, 但使用的固件可能不带对应的库, 就会提示xxx not found 或者 nil xxx
+
+## Demo列表
+
+* esp32c3的配网相关的demo 请查阅 [wlan](wlan/) 目录
+
+|文件名|功能|依赖的库|受支持的模块|备注|
+|------|----|-------|-----------|----|
+|[adc](https://gitee.com/openLuat/LuatOS/tree/master/demo/adc/)|模数转换|adc|所有||
+|[camera](https://gitee.com/openLuat/LuatOS/tree/master/demo/camera/)|摄像头|camera|air105||
+|[coremark](https://gitee.com/openLuat/LuatOS/tree/master/demo/coremark/)|跑分|coremark|所有|生产固件均不带该库,可自行编译或云编译|
+|[crypto](https://gitee.com/openLuat/LuatOS/tree/master/demo/crypto/)|加解密|crypto|所有||
+|[dht12](https://gitee.com/openLuat/LuatOS/tree/master/demo/dht12/)|温湿度传感器|i2c|所有||
+|[eink](https://gitee.com/openLuat/LuatOS/tree/master/demo/eink/)|电子墨水屏|eink|所有||
+|[fatfs](https://gitee.com/openLuat/LuatOS/tree/master/demo/fatfs/)|挂载sd卡|fatfs,sdio|所有|部分模块支持sdio挂载,其余支持spi挂载|
+|[fdb](https://gitee.com/openLuat/LuatOS/tree/master/demo/fdb/)|持久化kv存储|fdb|所有||
+|[fs](https://gitee.com/openLuat/LuatOS/tree/master/demo/fs/)|文件系统|io|所有||
+|[gpio](https://gitee.com/openLuat/LuatOS/tree/master/demo/gpio/)|通用输入输出|gpio|所有||
+|[gpio_irq](https://gitee.com/openLuat/LuatOS/tree/master/demo/gpio_irq/)|io中断|gpio|所有||
+|[gtfont](https://gitee.com/openLuat/LuatOS/tree/master/demo/gtfont/)|高通字体|gtfont|所有|需要额外的高通字体芯片,外挂在SPI|
+|[hello_world](https://gitee.com/openLuat/LuatOS/tree/master/demo/hello_world/)|最简示例|无|所有||
+|[i2c](https://gitee.com/openLuat/LuatOS/tree/master/demo/i2c/)|IIC总线|i2c|所有|演示i2c基本操作|
+|[io_queue](https://gitee.com/openLuat/LuatOS/tree/master/demo/io_queue/)|IO序列|ioqueue|air105|高精度IO序列|
+|[ir](https://gitee.com/openLuat/LuatOS/tree/master/demo/ir/)|红外|ir|air105|当前仅支持接收|
+|[json](https://gitee.com/openLuat/LuatOS/tree/master/demo/json/)|JSON编解码|json|所有||
+|[keyboard](https://gitee.com/openLuat/LuatOS/tree/master/demo/keyboard/)|键盘矩阵|keyboard|air105|硬件直驱|
+|[lcd](https://gitee.com/openLuat/LuatOS/tree/master/demo/lcd/)|SPI屏驱|lcd,spi|所有||
+|[lcd_custom](https://gitee.com/openLuat/LuatOS/tree/master/demo/lcd_custom/)|自定义LCD屏驱|lcd,spi|所有|自定义LCD驱动|
+|[lcd_mlx90640](https://gitee.com/openLuat/LuatOS/tree/master/demo/lcd_mlx90640/)|红外测温|mlx90640|所有|未完成|
+|[libcoap](https://gitee.com/openLuat/LuatOS/tree/master/demo/libcoap/)|coap编解码|licoap|所有|仅编解码,不含通信|
+|[libgnss](https://gitee.com/openLuat/LuatOS/tree/master/demo/libgnss/)|GNSS解析|libgnss|所有|通过UART与GNSS模块通信|
+|[lvgl](https://gitee.com/openLuat/LuatOS/tree/master/demo/lvgl/)|LVGL示例|lvgl,spi|所有|该目录下有大量LVGL实例,不同模组的实例也能参考|
+|[meminfo](https://gitee.com/openLuat/LuatOS/tree/master/demo/meminfo/)|内存状态|rtos|所有||
+|[multimedia](https://gitee.com/openLuat/LuatOS/tree/master/demo/multimedia/)|多媒体|decoder|air105|音频解码示例|
+|[network](https://gitee.com/openLuat/LuatOS/tree/master/demo/network/)|网络库|network|air105|与w5500配合,实现以太网访问|
+|[nimble](https://gitee.com/openLuat/LuatOS/tree/master/demo/nimble/)|蓝牙库|nimble|air101/air103|仅支持简单收发,功耗高|
+|[ota](https://gitee.com/openLuat/LuatOS/tree/master/demo/ota/)|固件更新|uart|自带网络的请使用libfota库,参考fota的demo||
+|[pm](https://gitee.com/openLuat/LuatOS/tree/master/demo/pm/)|功耗控制|pm|所有||
+|[pwm](https://gitee.com/openLuat/LuatOS/tree/master/demo/pwm/)|可控方波|pwm|所有||
+|[rtc](https://gitee.com/openLuat/LuatOS/tree/master/demo/rtc/)|内部时钟|rtc|所有||
+|[sfud](https://gitee.com/openLuat/LuatOS/tree/master/demo/sfud/)|通用FLASH读写|sfud,spi|所有||
+|[sht20](https://gitee.com/openLuat/LuatOS/tree/master/demo/sht20/)|温湿度传感器|i2c|所有||
+|[sht30](https://gitee.com/openLuat/LuatOS/tree/master/demo/sht30/)|温湿度传感器|i2c|所有||
+|[socket](https://gitee.com/openLuat/LuatOS/tree/master/demo/socket/)|网络套接字|socket|air105/air780e||
+|[spi](https://gitee.com/openLuat/LuatOS/tree/master/demo/spi/)|SPI库演示|spi|所有||
+|[statem](https://gitee.com/openLuat/LuatOS/tree/master/demo/statem/)|io状态机|statem|所有|air105推荐用ioqueue|
+|[sys_timerStart](https://gitee.com/openLuat/LuatOS/tree/master/demo/sys_timerStart/)|演示定时运行|sys|所有||
+|[u8g2](https://gitee.com/openLuat/LuatOS/tree/master/demo/u8g2/)|单色OLED屏驱|u8g2|所有||
+|[uart](https://gitee.com/openLuat/LuatOS/tree/master/demo/uart/)|UART演示|uart|所有||
+|[usb_hid](https://gitee.com/openLuat/LuatOS/tree/master/demo/usb_hid/)|USB自定义HID|usbapp|air105||
+|[usb_tf](https://gitee.com/openLuat/LuatOS/tree/master/demo/usb_tf/)|USB读写TF卡|usbapp|air105|速度500~700kbyte/s|
+|[usb_uart](https://gitee.com/openLuat/LuatOS/tree/master/demo/usb_uart/)|USB虚拟串口|usbapp|air105||
+|[video_play](https://gitee.com/openLuat/LuatOS/tree/master/demo/video_play/)|视频播放|uart,sdio|所有|当前仅支持裸rgb565ble视频流|
+|[wdt](https://gitee.com/openLuat/LuatOS/tree/master/demo/wdt/)|硬狗|wdt|所有||
+|[ws2812](https://gitee.com/openLuat/LuatOS/tree/master/demo/ws2812/)|驱动WS2812B|gpio,pwm,spi|所有||
+|[wlan](https://gitee.com/openLuat/LuatOS/tree/master/demo/wlan/)|wifi相关|wlan|ESP32系列支持wifi,Air780E系列只支持wifi扫描||
+

+ 53 - 0
module/Air780E/demo/SC7A20/main.lua

@@ -0,0 +1,53 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "sc7a20_demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+ 
+local sc7a20 = require "sc7a20"
+
+i2cid = 0
+i2c_speed = i2c.FAST
+
+gpio.setup(24, function() --配置中断,外部唤醒用
+    log.info("gpio 24")
+end, gpio.PULLUP, gpio.BOTH)
+
+gpio.setup(2, function() --配置中断,外部唤醒用
+    log.info("gpio 2")
+end, gpio.PULLUP, gpio.BOTH)
+
+sys.taskInit(function()
+    i2c.setup(i2cid, i2c_speed)
+
+    sc7a20.init(i2cid)--初始化,传入i2c_id
+
+    sys.wait(50)
+    sc7a20.set_thresh(i2cid, string.char(0x05), string.char(0x05))  -- 设置活动阀值
+    sys.wait(50)
+    sc7a20.set_irqf(i2cid, 1, string.char(0x1F), string.char(0x03), string.char(0xFF))  -- AOI1中断映射到INT1上
+    sys.wait(50)
+    sc7a20.set_irqf(i2cid, 2, string.char(0x1F), string.char(0x03), string.char(0xFF))  -- AOI2中断映射到INT2上
+
+    while 1 do
+        local sc7a20_data = sc7a20.get_data()
+        log.info("sc7a20_data", "sc7a20_data.x"..(sc7a20_data.x),"sc7a20_data.y"..(sc7a20_data.y),"sc7a20_data.z"..(sc7a20_data.z))
+        sys.wait(1000)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 24 - 0
module/Air780E/demo/adc/main.lua

@@ -0,0 +1,24 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "adcdemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+local testAdc = require "testAdc"
+sys.taskInit(testAdc.dotest)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 86 - 0
module/Air780E/demo/adc/testAdc.lua

@@ -0,0 +1,86 @@
+
+--[[
+1. Air101,Air103 模块上的ADC0脚-PA1, 0~2.4v,不要超过范围使用!!!
+2. Air101,Air103模块上的ADC1脚-PA4, 0~2.4v,不要超过范围使用!!!
+3. Air103 模块上的ADC2脚-PA2, 0~2.4v,不要超过范围使用!!! 
+4. Air103 模块上的ADC3脚-PA3, 0~2.4v,不要超过范围使用!!! 
+5. Air101,Air103 adc.CH_CPU 为内部温度 ,adc.CH_VBAT为VBAT
+6. Air105 adc参考电压是1.88V,所有通道一致,
+7. Air105内部分压没有隔离措施,在开启内部分压后,量程有所变化,具体看寄存器手册,1~5分压后能测到3.6,6通道能接近5V,但是不能直接测5V,可以测4.2V 0通道是始终开启无法关闭分压。
+8. Air780E内部ADC接口为12bits 外部直流分压为0-3.4V
+9. Air780E内部具有2个ADC接口,ADC0 -- AIO3 ADC1 -- AIO4 
+10. 特殊通道, CPU内部温度Temp -- adc.CH_CPU 主供电脚电压 VBAT -- adc.CH_VBAT
+11. 设置分压(adc.setRange)要在adc.open之前设置,否则无效!!
+]]
+
+local testAdc = {}
+
+local rtos_bsp = rtos.bsp()
+function adc_pin()
+     --Air780E开发板ADC编号
+    -- 默认不开启分压,范围是0-1.2v精度高
+    -- 设置分压要在adc.open之前设置,否则无效!!
+    -- adc.setRange(adc.ADC_RANGE_3_8)
+    return 0,1,255,255,adc.CH_CPU ,adc.CH_VBAT 
+end
+local adc_pin_0,adc_pin_1,adc_pin_2,adc_pin_3,adc_pin_temp,adc_pin_vbat=adc_pin()
+
+
+function testAdc.dotest()
+    if rtos_bsp == "AIR105" then
+        adc.setRange(adc.ADC_RANGE_3_6) --开启的内部分压,可以把量程扩大
+    end
+    if adc_pin_0 and adc_pin_0 ~= 255 then adc.open(adc_pin_0) end
+    if adc_pin_1 and adc_pin_1 ~= 255 then adc.open(adc_pin_1) end
+    if adc_pin_2 and adc_pin_2 ~= 255 then adc.open(adc_pin_2) end
+    if adc_pin_3 and adc_pin_3 ~= 255 then adc.open(adc_pin_3) end
+    if adc_pin_temp and adc_pin_temp ~= 255 then adc.open(adc_pin_temp) end
+    if adc_pin_vbat and adc_pin_vbat ~= 255 then adc.open(adc_pin_vbat) end
+
+    if adc_pin_0 and adc_pin_0 ~= 255 and mcu and mcu.ticks then
+        sys.wait(1000)
+        log.info("开始读取ADC")
+        local ms_start = mcu.ticks()
+        for i = 1, 100, 1 do
+            adc.get(adc_pin_0)
+        end
+        local ms_end = mcu.ticks()
+        log.info("结束读取ADC")
+        log.info("adc", "读取耗时", "100次", ms_end - ms_start, "ms", "单次", (ms_end - ms_start) // 100, "ms")
+    end
+
+    -- 下面是循环打印, 接地不打印0也是正常现象
+    -- ADC的精度都不会太高, 若需要高精度ADC, 建议额外添加adc芯片
+    while true do
+        if adc_pin_0 and adc_pin_0 ~= 255 then
+            log.debug("adc", "adc" .. tostring(adc_pin_0), adc.get(adc_pin_0)) -- 若adc.get报nil, 改成adc.read
+        end
+        if adc_pin_1 and adc_pin_1 ~= 255 then
+            log.debug("adc", "adc" .. tostring(adc_pin_1), adc.get(adc_pin_1))
+        end
+        if adc_pin_2 and adc_pin_2 ~= 255 then
+            log.debug("adc", "adc" .. tostring(adc_pin_2), adc.get(adc_pin_2))
+        end
+        if adc_pin_3 and adc_pin_3 ~= 255 then
+            log.debug("adc", "adc" .. tostring(adc_pin_3), adc.get(adc_pin_3))
+        end
+        if adc_pin_temp and adc_pin_temp ~= 255 then
+            log.debug("adc", "CPU TEMP", adc.get(adc_pin_temp))
+        end
+        if adc_pin_vbat and adc_pin_vbat ~= 255 then
+            log.debug("adc", "VBAT", adc.get(adc_pin_vbat))
+        end
+        sys.wait(1000)
+    end
+
+    -- 若不再读取, 可关掉adc, 降低功耗, 非必须
+    if adc_pin_0 and adc_pin_0 ~= 255 then adc.close(adc_pin_0) end
+    if adc_pin_1 and adc_pin_1 ~= 255 then adc.close(adc_pin_1) end
+    if adc_pin_2 and adc_pin_2 ~= 255 then adc.close(adc_pin_2) end
+    if adc_pin_3 and adc_pin_3 ~= 255 then adc.close(adc_pin_3) end
+    if adc_pin_temp and adc_pin_temp ~= 255 then adc.close(adc_pin_temp) end
+    if adc_pin_vbat and adc_pin_vbat ~= 255 then adc.close(adc_pin_vbat) end
+
+end
+
+return testAdc

+ 49 - 0
module/Air780E/demo/adxl345/main.lua

@@ -0,0 +1,49 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "adxl345_demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+local adxl34x = require "adxl34x"
+
+i2cid = 0
+i2c_speed = i2c.FAST
+
+gpio.setup(24, function() --配置wakeup中断,外部唤醒用 示例使用gpio24 连接ADXL34X INT1引脚
+    log.info("gpio ri")
+end, gpio.PULLUP, gpio.FALLING)
+
+sys.taskInit(function()
+    i2c.setup(i2cid, i2c_speed)
+
+    adxl34x.init(i2cid)--初始化,传入i2c_id
+
+    sys.wait(50)
+    adxl34x.set_thresh(i2cid, string.char(0x05), string.char(0x02), string.char(0x05))  -- 设置阀值
+    sys.wait(50)
+    adxl34x.set_irqf(i2cid, string.char(0x00), string.char(0xff), string.char(0x10))     -- activity映射到到INT1,并开启对应中断功能
+
+    while 1 do
+        adxl34x.get_int_source(i2cid)    -- 不加这个不会触发中断
+        
+        local adxl34x_data = adxl34x.get_data()
+        log.info("adxl34x_data", "adxl34x_data.x"..(adxl34x_data.x),"adxl34x_data.y"..(adxl34x_data.y),"adxl34x_data.z"..(adxl34x_data.z))
+        sys.wait(1000)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 81 - 0
module/Air780E/demo/air153C_wtd/main.lua

@@ -0,0 +1,81 @@
+PROJECT = 'air153C_wtd'
+VERSION = '2.0.0'
+LOG_LEVEL = log.LOG_INFO
+log.setLevel(LOG_LEVEL )
+require 'air153C_wtd'
+local sys = require "sys"
+_G.sysplus = require("sysplus")
+
+--[[
+    对于喂狗以及关闭喂狗,调用函数时需要等待对应的时间
+    例如:   1. 喂狗是410ms,那么需要等待至少400ms,即
+            air153C_wtd.feed_dog(pin)
+            sys.wait(410ms)
+            2. 关闭喂狗是710ms,那么需要等待至少700ms
+            air153C_wtd.close_watch_dog(pin)
+            sys.wait(710ms)
+]]
+
+sys.taskInit(function ()
+    log.info("main","taskInit")
+    local flag = 0
+    air153C_wtd.init(28)
+    air153C_wtd.feed_dog(28)--模块开机第一步需要喂狗一次
+    sys.wait(3000)--此处延时3s,防止1s内喂狗2次导致进入测试模式
+
+
+    --不喂狗
+    log.info("WTD","not eatdog test start!")
+    while 1 do
+        flag=flag+1
+        log.info("not feed dog",flag)
+        sys.wait(1000)
+    end
+
+
+    --喂狗
+    -- log.info("WTD","eatdog test start!")
+    -- while 1 do
+    -- air153C_wtd.feed_dog(28)--28为看门狗控制引脚
+    -- log.info("main","feed dog")
+    -- sys.wait(200000)
+    -- end
+
+    
+    --关闭喂狗
+    -- log.info("WTD","close eatdog test start!")
+    -- air153C_wtd.close_watch_dog(28)--28为看门狗控制引脚
+    -- sys.wait(1000)
+    
+
+    --先关闭喂狗,再打开喂狗
+    -- log.info("WTD","close eatdog and open eatdog test start!")
+    -- while 1 do
+    --     if flag==0 then
+    --         flag = 1
+    --         log.info("main","close watch dog")
+    --         air153C_wtd.close_watch_dog(28)--28为看门狗控制引脚
+    --         sys.wait(30000) --方便观察设置的时间长一点
+    --     end
+    --     flag=flag+1
+    --     if flag == 280 then
+    --         log.info("main","feed dog")
+    --         air153C_wtd.feed_dog(28)
+    --     end
+    --     sys.wait(1000)
+    --     log.info("Timer count(1s):", flag);
+    -- end
+
+
+    --测试模式复位
+    --测试模式: 1s内喂狗2次,会使模块复位重启
+    -- log.info("WTD","testmode test start!")
+    -- while flag<2 do
+    -- flag =flag+ 1
+    -- air153C_wtd.feed_dog(28)--28为看门狗控制引脚
+    -- log.info("main","feed dog")
+    -- sys.wait(500)
+    -- end
+end)
+
+sys.run()

+ 53 - 0
module/Air780E/demo/air530z/offline/main.lua

@@ -0,0 +1,53 @@
+
+_G.sys = require("sys")
+require "sysplus"
+--[[
+接Air530Z-BD, 本demo演示的是不带AGPS的, 带AGPS的请参考demo/air530z/agps (还没写完)
+
+提醒:
+1. Air530Z-BD的串口默认是9600波特率, 单北斗
+2. Air530Z 是北斗+GPS双模, 默认是9600波特率
+3. UART的TX/RX要交叉接, 否则无法正常工作
+]]
+
+local gps_uart_id = 2
+
+sys.taskInit(function()
+    libgnss.clear() -- 清空数据,兼初始化
+    sys.wait(100)
+    -- 先尝试9600波特率, 并切换波特率
+    uart.setup(gps_uart_id, 9600)
+    uart.write(gps_uart_id, "$PCAS01,5*19\r\n")
+    sys.wait(200)
+
+    -- 按115200开始读取数据
+    uart.setup(gps_uart_id, 115200)
+    -- 调试日志,可选
+    -- libgnss.debug(true)
+    libgnss.bind(gps_uart_id)
+end)
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(1000)
+        log.info("RMC", json.encode(libgnss.getRmc(2) or {}, "7f"))
+        -- log.info("INT", libgnss.getIntLocation())
+        -- log.info("GGA", libgnss.getGga(3))
+        -- log.info("GLL", json.encode(libgnss.getGll(2) or {}, "7f"))
+        -- log.info("GSA", json.encode(libgnss.getGsa(1) or {}, "7f"))
+        -- log.info("GSV", json.encode(libgnss.getGsv(2) or {}, "7f"))
+        -- log.info("VTG", json.encode(libgnss.getVtg(2) or {}, "7f"))
+        -- log.info("ZDA", json.encode(libgnss.getZda(2) or {}, "7f"))
+        -- log.info("date", os.date())
+        -- log.info("sys", rtos.meminfo("sys"))
+        -- log.info("lua", rtos.meminfo("lua"))
+
+        -- 打印全部卫星
+        -- local gsv = libgnss.getGsv() or {sats={}}
+        -- for i, v in ipairs(gsv.sats) do
+        --     log.info("sat", i, v.nr, v.snr, v.azimuth, v.elevation)
+        -- end
+    end
+end)
+
+sys.run()

+ 90 - 0
module/Air780E/demo/airlbs/main.lua

@@ -0,0 +1,90 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "paid_lbs"
+VERSION = "1.0.0"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "xxx" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+log.info("main", PROJECT, VERSION)
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(20000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+local airlbs = require "airlbs"
+
+local timeout = 60 -- 扫描基站/wifi 做 基站/wifi定位 的超时时间,最小5S,最大60S
+
+-- 此为收费服务,需自行联系销售申请
+local airlbs_project_id = ""
+local airlbs_project_key = ""
+
+-- --多基站定位
+-- sys.taskInit(function()
+--     sys.waitUntil("IP_READY") -- 等待底层上报联网成功
+--     socket.sntp() -- 进行NTP授时,放置部分联通卡没有基站授时
+--     sys.waitUntil("NTP_UPDATE", 1000)
+--     while 1 do
+--         if airlbs_project_id and airlbs_project_key then
+--             local result, data = airlbs.request({
+--                 project_id = airlbs_project_id,
+--                 project_key = airlbs_project_key,
+--                 timeout = timeout * 1000 -- 实际的超时时间(单位:ms)
+--             })
+--             if result then
+--                 log.info("airlbs多基站定位返回的经纬度数据为", json.encode(data))
+--             end
+--         else
+--             log.warn("请检查project_id和project_key")
+--         end
+--         sys.wait(20000)
+--     end
+
+-- end)
+
+-- wifi/基站混合定位
+sys.taskInit(function()
+    sys.waitUntil("IP_READY")
+    -- 如需wifi定位,需要硬件以及固件支持wifi扫描功能
+    local wifi_info = nil
+    if wlan then
+        sys.wait(3000) -- 网络可用后等待一段时间才再调用wifi扫描功能,否则可能无法获取wifi信息
+        wlan.init()
+        wlan.scan()
+        sys.waitUntil("WLAN_SCAN_DONE", timeout * 1000)
+        wifi_info = wlan.scanResult()
+        log.info("scan", "wifi_info", #wifi_info)
+    end
+
+    socket.sntp()
+    sys.waitUntil("NTP_UPDATE", 1000)
+
+    while 1 do
+        local result, data = airlbs.request({
+            project_id = airlbs_project_id,
+            project_key = airlbs_project_key,
+            wifi_info = wifi_info,
+            timeout = timeout * 1000
+        })
+        if result then
+                log.info("airlbs多基站定位返回的经纬度数据为", json.encode(data))
+        else
+            log.warn("请检查project_id和project_key")
+        end
+        sys.wait(20000) -- 循环20S一次wifi定位
+    end
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 35 - 0
module/Air780E/demo/at24cxx/main.lua

@@ -0,0 +1,35 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "at24cdemo"
+VERSION = "1.0.0"
+-- sys库是标配
+sys = require("sys")
+
+
+--经过测试,该demo对相同引脚的一些Flash同样支持  
+--目前测试发现的Flash型号:FM24CL64-GTR
+
+--1010 000x
+--7bit地址,不包含最后一位读写位
+local addr = 0x50
+-- 按照实际芯片更改编号哦
+local i2cid = 0
+
+sys.taskInit(function()
+    log.info("i2c initial",i2c.setup(i2cid))
+    while true do
+        i2c.send(i2cid, addr, string.char(0x01, 0x00) .. "12345678")
+        sys.wait(100)
+        i2c.send(i2cid, addr, string.char(0x01, 0x00))
+        sys.wait(100)
+        local data = i2c.recv(i2cid, addr, 8)
+        log.info("i2c", "data2", data:toHex(), #data)
+        sys.wait(1000)
+    end
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 52 - 0
module/Air780E/demo/bit/main.lua

@@ -0,0 +1,52 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "bit64_test"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+
+
+local function log_bit()
+        log.info("按位取反,输出-6",bit.bnot(5))
+        log.info("与,--输出1",bit.band(1,1))
+        log.info("或,--输出3",bit.bor(1,2))
+        log.info("异或结果为4",bit.bxor(2,3,5))
+        log.info("逻辑左移,“100”,输出为4",bit.lshift(1,2))
+
+        log.info("逻辑右移,“001”,输出为1",bit.rshift(4,2))
+        log.info("算数右移,左边添加的数与符号有关,输出为0",bit.arshift(2,2))
+        log.info("参数是位数,作用是1向左移动两位,打印出4",bit.bit(2))
+        log.info("测试位数是否被置1",bit.isset(5,0))--第一个参数是是测试数字,第二个是测试位置.从右向左数0到7.是1返回true,否则返回false,该返回true
+        log.info("测试位数是否被置1",bit.isset(5,1))--打印false
+        log.info("测试位数是否被置1",bit.isset(5,2))--打印true
+        log.info("测试位数是否被置1",bit.isset(5,3))--返回返回false
+        log.info("测试位数是否被置0",bit.isclear(5,0))----与上面的相反
+        log.info("测试位数是否被置0",bit.isclear(5,1))
+        log.info("测试位数是否被置0",bit.isclear(5,2))
+        log.info("测试位数是否被置0",bit.isclear(5,3))
+        log.info("把0的第0,1,2,3位值为1",bit.set(0,0,1,2,3))--在相应的位数置1,打印15
+        log.info("把5的第0,2位置为0",bit.clear(5,0,2))--在相应的位置置0,打印0
+end
+
+sys.taskInit(log_bit)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 114 - 0
module/Air780E/demo/bit64/main.lua

@@ -0,0 +1,114 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "bit64_test"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+
+local data,b64,b32,a,b
+
+if bit64 then
+	log.style(1)
+	log.info("bit64 演示")
+	data = 12345678
+	b64 = bit64.to64(data)
+	b32 = bit64.to32(b64)
+	log.info("i32", b32, mcu.x32(b32))
+	data = -12345678
+	b64 = bit64.to64(data)
+	b32 = bit64.to32(b64)
+	log.info("i32", b32, mcu.x32(b32))
+	data = 12.34234
+	b64 = bit64.to64(data)
+	b32 = bit64.to32(b64)
+	log.info("f32", data, b32)
+	data = -12.34234
+	b64 = bit64.to64(data)
+	b32 = bit64.to32(b64)
+	log.info("f32", data, b32)
+
+
+	a = bit64.to64(87654321)
+	b = bit64.to64(12345678)
+	log.info("87654321+12345678=", bit64.show(bit64.plus(a,b)))
+	log.info("87654321-12345678=", bit64.show(bit64.minus(a,b)))
+	log.info("87654321*12345678=", bit64.show(bit64.multi(a,b)))
+	log.info("87654321/12345678=", bit64.show(bit64.pide(a,b)))
+
+	a = bit64.to64(87654321)
+	b = 1234567
+	log.info("87654321+1234567=", bit64.show(bit64.plus(a,b)))
+	log.info("87654321-1234567=", bit64.show(bit64.minus(a,b)))
+	log.info("87654321*1234567=", bit64.show(bit64.multi(a,b)))
+	log.info("87654321/1234567=", bit64.show(bit64.pide(a,b)))
+
+
+	a = bit64.to64(87654.326)
+	b = bit64.to64(12345)
+	log.info("87654.326+12345=", 87654.326 + 12345)
+	log.info("87654.326+12345=", bit64.show(bit64.plus(a,b)))
+	log.info("87654.326-12345=", bit64.show(bit64.minus(a,b)))
+	log.info("87654.326*12345=", bit64.show(bit64.multi(a,b)))
+	log.info("87654.326/12345=", bit64.show(bit64.pide(a,b)))
+
+	a = bit64.to64(87654.32)
+	b = bit64.to64(12345.67)
+	log.info("float", "87654.32+12345.67=", 87654.32 + 12345.67)
+	log.info("double","87654.32+12345.67=", bit64.show(bit64.plus(a,b)))
+	log.info("double to float","87654.32+12345.67=", bit64.to32(bit64.plus(a,b)))
+	log.info("87654.32-12345.67=", bit64.show(bit64.minus(a,b)))
+	log.info("87654.32*12345.67=", bit64.show(bit64.multi(a,b)))
+	log.info("87654.32/12345.67=", bit64.show(bit64.pide(a,b)))
+	log.info("double to int64", "87654.32/12345.67=", bit64.show(bit64.pide(a,b,nil,true)))
+
+	a = bit64.to64(0xc0000000)
+	b = 2
+	a = bit64.shift(a,8,true)
+	log.info("0xc0000000 << 8 =", bit64.show(a, 16))
+	log.info("0xc000000000+2=", bit64.show(bit64.plus(a,b), 16))
+	log.info("0xc000000000-2=", bit64.show(bit64.minus(a,b), 16))
+	log.info("0xc000000000*2=", bit64.show(bit64.multi(a,b), 16))
+	log.info("0xc000000000/2=", bit64.show(bit64.pide(a,b), 16))
+	log.style(0)
+
+	if bit64.strtoll then
+		local data = bit64.strtoll("864040064024194", 10)
+		log.info("data", data:toHex())
+		log.info("data", bit64.show(data))
+	end
+end
+
+local function sys_run_time()
+	local tick64, per = mcu.tick64(true)
+	local per_cnt = per * 1000000
+	while true do
+		tick64, per = mcu.tick64(true)
+		log.info("work time","当前时间", bit64.to32(bit64.pide(tick64,per_cnt)))
+		sys.wait(1000)
+	end
+end
+
+if mcu.tick64 then
+	sys.taskInit(sys_run_time)
+end
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 115 - 0
module/Air780E/demo/camera/spi_cam/bf30a2.lua

@@ -0,0 +1,115 @@
+
+local reg_table = {
+	{0xf2,0x01},
+	{0xcf,0xb0},
+	{0x12,0x20},
+	{0x15,0x80},
+	{0x6b,0x71},
+	{0x00,0x40},
+	{0x04,0x00},
+	{0x06,0x26},
+	{0x08,0x07},
+	{0x1c,0x12},
+	{0x20,0x20},
+	{0x21,0x20},
+	{0x34,0x02},
+	{0x35,0x02},
+	{0x36,0x21},
+	{0x37,0x13},
+	{0xca,0x23},
+	{0xcb,0x22},
+	{0xcc,0x89},
+	{0xcd,0x4c},
+	{0xce,0x6b},
+	{0xa0,0x8e},
+	{0x01,0x1b},
+	{0x02,0x1d},
+	{0x13,0x08},
+	{0x87,0x13},
+	{0x8b,0x08},
+	{0x70,0x17},
+	{0x71,0x43},
+	{0x72,0x0a},
+	{0x73,0x62},
+	{0x74,0xa2},
+	{0x75,0xbf},
+	{0x76,0x00},
+	{0x77,0xcc},
+	{0x40,0x32},
+	{0x41,0x28},
+	{0x42,0x26},
+	{0x43,0x1d},
+	{0x44,0x1a},
+	{0x45,0x14},
+	{0x46,0x11},
+	{0x47,0x0f},
+	{0x48,0x0e},
+	{0x49,0x0d},
+	{0x4B,0x0c},
+	{0x4C,0x0b},
+	{0x4E,0x0a},
+	{0x4F,0x09},
+	{0x50,0x09},
+	{0x24,0x30},
+	{0x25,0x36},
+	{0x80,0x00},
+	{0x81,0x20},
+	{0x82,0x40},
+	{0x83,0x30},
+	{0x84,0x50},
+	{0x85,0x30},
+	{0x86,0xd8},
+	{0x89,0x45},
+	{0x8a,0x33},
+	{0x8f,0x81},
+	{0x91,0xff},
+	{0x92,0x08},
+	{0x94,0x82},
+	{0x95,0xfd},
+	{0x9a,0x20},
+	{0x9e,0xbc},
+	{0xf0,0x87},
+	{0x51,0x06},
+	{0x52,0x25},
+	{0x53,0x2b},
+	{0x54,0x0f},
+	{0x57,0x2a},
+	{0x58,0x22},
+	{0x59,0x2c},
+	{0x23,0x33},
+	{0xa1,0x93},
+	{0xa2,0x0f},
+	{0xa3,0x2a},
+	{0xa4,0x08},
+	{0xa5,0x26},
+	{0xa7,0x80},
+	{0xa8,0x80},
+	{0xa9,0x1e},
+	{0xaa,0x19},
+	{0xab,0x18},
+	{0xae,0x50},
+	{0xaf,0x04},
+	{0xc8,0x10},
+	{0xc9,0x15},
+	{0xd3,0x0c},
+	{0xd4,0x16},
+	{0xee,0x06},
+	{0xef,0x04},
+	{0x55,0x34},
+	{0x56,0x9c},
+	{0xb1,0x98},
+	{0xb2,0x98},
+	{0xb3,0xc4},
+	{0xb4,0x0c},
+	{0xa0,0x8f},
+	{0x13,0x07},
+}
+
+function bf30a2Init(cspiId,i2cId,speed,scanMode,onlyY)
+	local id = camera.init(cspiId,speed,0,0,1,0,0,onlyY,scanMode,240,320)
+	for i=1,#reg_table do
+		i2c.send(i2cId,0x6e,reg_table[i],1)
+	end
+	camera.start(id)
+	return id
+end

+ 328 - 0
module/Air780E/demo/camera/spi_cam/gc0310.lua

@@ -0,0 +1,328 @@
+local reg_table = {
+        {0xfe, 0xf0},
+        {0xfe, 0xf0},
+        {0xfe, 0x00},
+        {0xfc, 0x16}, 
+        {0xfc, 0x16}, 
+        {0xf2, 0x07}, 
+        {0xf3, 0x83}, 
+        {0xf5, 0x07}, 
+        {0xf7, 0x88}, 
+        {0xf8, 0x00}, 
+        {0xf9, 0x4f}, 
+        {0xfa, 0x11}, 
+        {0xfc, 0xce},
+        {0xfd, 0x00},
+
+        {0x00, 0x2f},
+        {0x01, 0x0f},
+        {0x02, 0x04},
+        {0x03, 0x02},
+        {0x04, 0x12},
+        {0x09, 0x00},
+        {0x0a, 0x00},
+        {0x0b, 0x00},
+        {0x0c, 0x04},
+        {0x0d, 0x01},
+        {0x0e, 0xe8},
+        {0x0f, 0x02},
+        {0x10, 0x88},
+        {0x16, 0x00},
+        {0x17, 0x14},
+        {0x18, 0x1a},
+        {0x19, 0x14},
+        {0x1b, 0x48},
+        {0x1c, 0x6c},
+        {0x1e, 0x6b},
+        {0x1f, 0x28},
+        {0x20, 0x8b},
+        {0x21, 0x49},
+        {0x22, 0xd0},
+        {0x23, 0x04},
+        {0x24, 0xff},
+        {0x34, 0x20},
+
+        {0x26, 0x23}, 
+        {0x28, 0xff}, 
+        {0x29, 0x00}, 
+        {0x32, 0x04},
+        {0x33, 0x10}, 
+        {0x37, 0x20}, 
+        {0x38, 0x10},
+        {0x47, 0x80}, 
+        {0x4e, 0x66}, 
+        {0xa8, 0x02}, 
+        {0xa9, 0x80},
+
+        {0x40, 0xff},
+        {0x41, 0x21}, 
+        {0x42, 0xcf}, 
+        {0x44, 0x00},
+        {0x45, 0xa0},
+        {0x46, 0x02}, 
+        {0x4a, 0x11},
+        {0x4b, 0x01},
+        {0x4c, 0x20}, 
+        {0x4d, 0x05}, 
+        {0x4f, 0x01},
+        {0x50, 0x01}, 
+        {0x55, 0x01}, 
+        {0x56, 0xe0},
+        {0x57, 0x02}, 
+        {0x58, 0x80},
+
+        {0x70, 0x70},
+        {0x5a, 0x84},
+        {0x5b, 0xc9},
+        {0x5c, 0xed},
+        {0x77, 0x74},
+        {0x78, 0x40},
+        {0x79, 0x5f},
+
+        {0x82, 0x14},
+        {0x83, 0x0b},
+        {0x89, 0xf0},
+
+        {0x8f, 0xaa},
+        {0x90, 0x8c},
+        {0x91, 0x90},
+        {0x92, 0x03},
+        {0x93, 0x03},
+        {0x94, 0x05},
+        {0x95, 0x65},
+        {0x96, 0xf0},
+
+        {0xfe, 0x00},
+        {0x9a, 0x20},
+        {0x9b, 0x80},
+        {0x9c, 0x40},
+        {0x9d, 0x80},
+        {0xa1, 0x30},
+        {0xa2, 0x32},
+        {0xa4, 0x30}, 
+        {0xa5, 0x30}, 
+        {0xaa, 0x10}, 
+        {0xac, 0x22},
+
+        {0xfe, 0x00},
+        {0xbf, 0x08},
+        {0xc0, 0x16},
+        {0xc1, 0x28},
+        {0xc2, 0x41},
+        {0xc3, 0x5a},
+        {0xc4, 0x6c},
+        {0xc5, 0x7a},
+        {0xc6, 0x96},
+        {0xc7, 0xac},
+        {0xc8, 0xbc},
+        {0xc9, 0xc9},
+        {0xca, 0xd3},
+        {0xcb, 0xdd},
+        {0xcc, 0xe5},
+        {0xcd, 0xf1},
+        {0xce, 0xfa},
+        {0xcf, 0xff},
+
+        {0xd0, 0x40},
+        {0xd1, 0x34},
+        {0xd2, 0x34},
+        {0xd3, 0x40},
+        {0xd6, 0xf2},
+        {0xd7, 0x1b},
+        {0xd8, 0x18},
+        {0xdd, 0x03},
+
+        {0xfe, 0x01},
+        {0x05, 0x30},
+        {0x06, 0x75},
+        {0x07, 0x40},
+        {0x08, 0xb0},
+        {0x0a, 0xc5},
+        {0x0b, 0x11},
+        {0x0c, 0x00},
+        {0x12, 0x52},
+        {0x13, 0x38},
+        {0x18, 0x95},
+        {0x19, 0x96},
+        {0x1f, 0x20},
+        {0x20, 0xc0},
+        {0x3e, 0x40},
+        {0x3f, 0x57},
+        {0x40, 0x7d},
+        {0x03, 0x60},
+        {0x44, 0x00},
+
+        {0xfe, 0x01},
+        {0x1c, 0x91},
+        {0x21, 0x15},
+        {0x50, 0x80},
+        {0x56, 0x04},
+        {0x59, 0x08},
+        {0x5b, 0x02},
+        {0x61, 0x8d},
+        {0x62, 0xa7},
+        {0x63, 0xd0},
+        {0x65, 0x06},
+        {0x66, 0x06},
+        {0x67, 0x84},
+        {0x69, 0x08},
+        {0x6a, 0x25},
+        {0x6b, 0x01},
+        {0x6c, 0x00},
+        {0x6d, 0x02},
+        {0x6e, 0xf0},
+        {0x6f, 0x80},
+        {0x76, 0x80},
+        {0x78, 0xaf},
+        {0x79, 0x75},
+        {0x7a, 0x40},
+        {0x7b, 0x50},
+        {0x7c, 0x0c},
+        {0x90, 0xc9}, 
+        {0x91, 0xbe},
+        {0x92, 0xe2},
+        {0x93, 0xc9},
+        {0x95, 0x1b},
+        {0x96, 0xe2},
+        {0x97, 0x49},
+        {0x98, 0x1b},
+        {0x9a, 0x49},
+        {0x9b, 0x1b},
+        {0x9c, 0xc3},
+        {0x9d, 0x49},
+        {0x9f, 0xc7},
+        {0xa0, 0xc8},
+        {0xa1, 0x00},
+        {0xa2, 0x00},
+        {0x86, 0x00},
+        {0x87, 0x00},
+        {0x88, 0x00},
+        {0x89, 0x00},
+        {0xa4, 0xb9},
+        {0xa5, 0xa0},
+        {0xa6, 0xba},
+        {0xa7, 0x92},
+        {0xa9, 0xba},
+        {0xaa, 0x80},
+        {0xab, 0x9d},
+        {0xac, 0x7f},
+        {0xae, 0xbb},
+        {0xaf, 0x9d},
+        {0xb0, 0xc8},
+        {0xb1, 0x97},
+        {0xb3, 0xb7},
+        {0xb4, 0x7f},
+        {0xb5, 0x00},
+        {0xb6, 0x00},
+        {0x8b, 0x00},
+        {0x8c, 0x00},
+        {0x8d, 0x00},
+        {0x8e, 0x00},
+        {0x94, 0x55},
+        {0x99, 0xa6},
+        {0x9e, 0xaa},
+        {0xa3, 0x0a},
+        {0x8a, 0x00},
+        {0xa8, 0x55},
+        {0xad, 0x55},
+        {0xb2, 0x55},
+        {0xb7, 0x05},
+        {0x8f, 0x00},
+        {0xb8, 0xcb},
+        {0xb9, 0x9b},
+
+        {0xfe, 0x01},
+        {0xd0, 0x38}, 
+        {0xd1, 0x00},
+        {0xd2, 0x02},
+        {0xd3, 0x04},
+        {0xd4, 0x38},
+        {0xd5, 0x12},
+        {0xd6, 0x30},
+        {0xd7, 0x00},
+        {0xd8, 0x0a},
+        {0xd9, 0x16},
+        {0xda, 0x39},
+        {0xdb, 0xf8},
+
+        {0xfe, 0x01},
+        {0xc1, 0x3c},
+        {0xc2, 0x50},
+        {0xc3, 0x00},
+        {0xc4, 0x40},
+        {0xc5, 0x30},
+        {0xc6, 0x30},
+        {0xc7, 0x10},
+        {0xc8, 0x00},
+        {0xc9, 0x00},
+        {0xdc, 0x20},
+        {0xdd, 0x10},
+        {0xdf, 0x00},
+        {0xde, 0x00},
+
+        {0x01, 0x10},
+        {0x0b, 0x31}, 
+        {0x0e, 0x50},
+        {0x0f, 0x0f},
+        {0x10, 0x6e},
+        {0x12, 0xa0},
+        {0x15, 0x60},
+        {0x16, 0x60},
+        {0x17, 0xe0},
+
+        {0xcc, 0x0c}, 
+        {0xcd, 0x10},
+        {0xce, 0xa0},
+        {0xcf, 0xe6},
+
+    
+        {0x45, 0xf7},
+        {0x46, 0xff}, 
+        {0x47, 0x15},
+        {0x48, 0x03}, 
+        {0x4f, 0x60}, 
+  
+        {0xfe, 0x00},
+        {0x05, 0x01},
+        {0x06, 0x32}, 
+        {0x07, 0x00},
+        {0x08, 0x0c}, 
+        {0xfe, 0x01},
+        {0x25, 0x00}, 
+        {0x26, 0x3c},
+        {0x27, 0x01}, 
+        {0x28, 0xdc},
+        {0x29, 0x01}, 
+        {0x2a, 0xe0},
+        {0x2b, 0x01}, 
+        {0x2c, 0xe0},
+        {0x2d, 0x01}, 
+        {0x2e, 0xe0},
+        {0x3c, 0x20},
+
+	--SPI配置
+	{0xfe, 0x03},
+	{0x52, 0xa2},
+	{0x53, 0x24}, 
+	{0x54, 0x20},
+	{0x55, 0x00},
+	{0x59, 0x1f}, 
+	{0x5a, 0x00},
+	{0x5b, 0x80},
+	{0x5c, 0x02},
+	{0x5d, 0xe0},
+	{0x5e, 0x01},
+	{0x51, 0x03},
+	{0x64, 0x04},
+	{0xfe, 0x00},
+	{0x44, 0x02},
+}
+
+function gc0310Init(cspiId,i2cId,speed,scanMode,onlyY)
+	local id = camera.init(cspiId,speed,1,1,2,1,0x00010101,onlyY,scanMode,640,480)
+	for i=1,#reg_table do
+		i2c.send(i2cId,0x21,reg_table[i],1)
+	end
+	camera.start(id)
+	return id
+end

+ 361 - 0
module/Air780E/demo/camera/spi_cam/gc032a.lua

@@ -0,0 +1,361 @@
+local reg_table = {
+   {0xf3, 0x83}, 
+   {0xf5, 0x08},
+   {0xf7, 0x01},
+   {0xf8, 0x01}, 
+   {0xf9, 0x4e},
+   {0xfa, 0x00},
+   {0xfc, 0x02},
+   {0xfe, 0x02},
+   {0x81, 0x03},
+
+   {0xfe, 0x00},
+   {0x77, 0x64},
+   {0x78, 0x40},
+   {0x79, 0x60},
+
+   {0xfe, 0x00},
+   {0x03, 0x01},
+   {0x04, 0xcb},
+   {0x05, 0x01},
+   {0x06, 0xb2},
+   {0x07, 0x00},
+   {0x08, 0x10},
+
+   {0x0a, 0x00},
+   {0x0c, 0x00},
+   {0x0d, 0x01},
+   {0x0e, 0xe8},
+   {0x0f, 0x02},
+   {0x10, 0x88},
+
+   {0x17, 0x54},
+   {0x19, 0x08},
+   {0x1a, 0x0a},
+   {0x1f, 0x40},
+   {0x20, 0x30},
+   {0x2e, 0x80},
+   {0x2f, 0x2b},
+   {0x30, 0x1a},
+   {0xfe, 0x02},
+   {0x03, 0x02},
+   {0x05, 0xd7},
+   {0x06, 0x60},
+   {0x08, 0x80},
+   {0x12, 0x89},
+
+
+   {0xfe, 0x03},
+   {0x52, 0xba}, 
+   {0x53, 0x24},
+   {0x54, 0x20},
+   {0x55, 0x00},
+   {0x59, 0x1f}, 
+   {0x5a, 0x00}, 
+   {0x5b, 0x80},
+   {0x5c, 0x02},
+   {0x5d, 0xe0},
+   {0x5e, 0x01},
+   {0x51, 0x03},
+   {0x64, 0x04},
+   {0xfe, 0x00},
+
+
+   {0xfe, 0x00},
+   {0x18, 0x02},
+   {0xfe, 0x02},
+   {0x40, 0x22},
+   {0x45, 0x00},
+   {0x46, 0x00},
+   {0x49, 0x20},
+   {0x4b, 0x3c},
+   {0x50, 0x20},
+   {0x42, 0x10},
+
+
+   {0xfe, 0x01},
+   {0x0a, 0xc5},
+   {0x45, 0x00},
+   {0xfe, 0x00},
+   {0x40, 0xff},
+   {0x41, 0x25},
+   {0x42, 0xef},
+   {0x43, 0x10},
+   {0x44, 0x83}, 
+   {0x46, 0x22},
+   {0x49, 0x03},
+   {0x52, 0x02},
+   {0x54, 0x00},
+   {0xfe, 0x02},
+   {0x22, 0xf6},
+
+
+   {0xfe, 0x01},
+   {0xc1, 0x38},
+   {0xc2, 0x4c},
+   {0xc3, 0x00},
+   {0xc4, 0x2c},
+   {0xc5, 0x24},
+   {0xc6, 0x18},
+   {0xc7, 0x28},
+   {0xc8, 0x11},
+   {0xc9, 0x15},
+   {0xca, 0x20},
+   {0xdc, 0x7a},
+   {0xdd, 0xa0},
+   {0xde, 0x80},
+   {0xdf, 0x88},
+
+
+   {0xfe, 0x01},
+   {0x50, 0xc1},
+   {0x56, 0x34},
+   {0x58, 0x04},
+   {0x65, 0x06},
+   {0x66, 0x0f},
+   {0x67, 0x04},
+   {0x69, 0x20},
+   {0x6a, 0x40},
+   {0x6b, 0x81},
+   {0x6d, 0x12},
+   {0x6e, 0xc0},
+   {0x7b, 0x2a},
+   {0x7c, 0x0c},
+   {0xfe, 0x01},
+   {0x90, 0xe3},
+   {0x91, 0xc2},
+   {0x92, 0xff},
+   {0x93, 0xe3},
+   {0x95, 0x1c},
+   {0x96, 0xff},
+   {0x97, 0x44},
+   {0x98, 0x1c},
+   {0x9a, 0x44},
+   {0x9b, 0x1c},
+   {0x9c, 0x64},
+   {0x9d, 0x44},
+   {0x9f, 0x71},
+   {0xa0, 0x64},
+   {0xa1, 0x00},
+   {0xa2, 0x00},
+   {0x86, 0x00},
+   {0x87, 0x00},
+   {0x88, 0x00},
+   {0x89, 0x00},
+   {0xa4, 0xc2},
+   {0xa5, 0x9b},
+   {0xa6, 0xc8},
+   {0xa7, 0x92},
+   {0xa9, 0xc9},
+   {0xaa, 0x96},
+   {0xab, 0xa9},
+   {0xac, 0x99},
+   {0xae, 0xce},
+   {0xaf, 0xa9},
+   {0xb0, 0xcf},
+   {0xb1, 0x9d},
+   {0xb3, 0xcf},
+   {0xb4, 0xac},
+   {0xb5, 0x00},
+   {0xb6, 0x00},
+   {0x8b, 0x00},
+   {0x8c, 0x00},
+   {0x8d, 0x00},
+   {0x8e, 0x00},
+   {0x94, 0x55},
+   {0x99, 0xa6},
+   {0x9e, 0xaa},
+   {0xa3, 0x0a},
+   {0x8a, 0x00},
+   {0xa8, 0x55},
+   {0xad, 0x55},
+   {0xb2, 0x55},
+   {0xb7, 0x05},
+   {0x8f, 0x00},
+   {0xb8, 0xc7},
+   {0xb9, 0xa0},
+
+   {0xfe, 0x01},
+   {0xd0, 0x40},
+   {0xd1, 0x00},
+   {0xd2, 0x00},
+   {0xd3, 0xfa},
+   {0xd4, 0x4a},
+   {0xd5, 0x02},
+
+   {0xd6, 0x44},
+   {0xd7, 0xfa},
+   {0xd8, 0x04},
+   {0xd9, 0x08},
+   {0xda, 0x5c},
+   {0xdb, 0x02},
+   {0xfe, 0x00},
+
+
+   {0xfe, 0x00},
+   {0xba, 0x00},
+   {0xbb, 0x04},
+   {0xbc, 0x0a},
+   {0xbd, 0x0e},
+   {0xbe, 0x22},
+   {0xbf, 0x30},
+   {0xc0, 0x3d},
+   {0xc1, 0x4a},
+   {0xc2, 0x5d},
+   {0xc3, 0x6b},
+   {0xc4, 0x7a},
+   {0xc5, 0x85},
+   {0xc6, 0x90},
+   {0xc7, 0xa5},
+   {0xc8, 0xb5},
+   {0xc9, 0xc2},
+   {0xca, 0xcc},
+   {0xcb, 0xd5},
+   {0xcc, 0xde},
+   {0xcd, 0xea},
+   {0xce, 0xf5},
+   {0xcf, 0xff},
+
+
+   {0xfe, 0x00},
+   {0x5a, 0x08},
+   {0x5b, 0x0f},
+   {0x5c, 0x15},
+   {0x5d, 0x1c},
+   {0x5e, 0x28},
+   {0x5f, 0x36},
+   {0x60, 0x45},
+   {0x61, 0x51},
+   {0x62, 0x6a},
+   {0x63, 0x7d},
+   {0x64, 0x8d},
+   {0x65, 0x98},
+   {0x66, 0xa2},
+   {0x67, 0xb5},
+   {0x68, 0xc3},
+   {0x69, 0xcd},
+   {0x6a, 0xd4},
+   {0x6b, 0xdc},
+   {0x6c, 0xe3},
+   {0x6d, 0xf0},
+   {0x6e, 0xf9},
+   {0x6f, 0xff},
+
+
+   {0xfe, 0x00},
+   {0x70, 0x50},
+
+
+   {0xfe, 0x00},
+   {0x4f, 0x01},
+   {0xfe, 0x01},
+   {0x0c, 0x01},
+   {0x0d, 0x00}, 
+   {0x12, 0xa0},
+   {0x13, 0x38},
+   {0x1f, 0x40},
+   {0x20, 0x40},
+   {0x23, 0x0a},
+   {0x26, 0x9a},
+   {0x3e, 0x20},
+   {0x3f, 0x2d},
+   {0x40, 0x40},
+   {0x41, 0x5b},
+   {0x42, 0x82},
+   {0x43, 0xb7},
+   {0x04, 0x0a},
+   {0x02, 0x79},
+   {0x03, 0xc0},
+
+  
+   {0xfe, 0x01},
+   {0xcc, 0x08},
+   {0xcd, 0x08},
+   {0xce, 0xa4},
+   {0xcf, 0xec},
+
+ 
+   {0xfe, 0x00},
+   {0x81, 0xb8},
+   {0x82, 0x04},
+   {0x83, 0x10},
+   {0x84, 0x01},
+   {0x86, 0x50},
+   {0x87, 0x18},
+   {0x88, 0x10},
+   {0x89, 0x70},
+   {0x8a, 0x20},
+   {0x8b, 0x10},
+   {0x8c, 0x08},
+   {0x8d, 0x0a},
+
+
+   {0xfe, 0x00},
+   {0x8f, 0xaa},
+   {0x90, 0x1c},
+   {0x91, 0x52},
+   {0x92, 0x03},
+   {0x93, 0x03},
+   {0x94, 0x08},
+   {0x95, 0x6a},
+   {0x97, 0x00},
+   {0x98, 0x00},
+
+ 
+   {0xfe, 0x00},
+   {0x9a, 0x30},
+   {0x9b, 0x50},
+   {0xa1, 0x30},
+   {0xa2, 0x66},
+   {0xa4, 0x28},
+   {0xa5, 0x30},
+   {0xaa, 0x28},
+   {0xac, 0x32},
+
+  
+   {0xfe, 0x00},
+   {0xd1, 0x3f},
+   {0xd2, 0x3f},
+   {0xd3, 0x38},
+   {0xd6, 0xf4},
+   {0xd7, 0x1d},
+   {0xdd, 0x72},
+   {0xde, 0x84},
+
+   {0xfe, 0x00},
+   {0x05, 0x01},
+   {0x06, 0xad},
+   {0x07, 0x00},
+   {0x08, 0x10},
+
+   {0xfe, 0x01},
+   {0x25, 0x00},
+   {0x26, 0x4d},
+
+   {0x27, 0x01},
+   {0x28, 0xce}, 
+   {0x29, 0x01},
+   {0x2a, 0xce}, 
+   {0x2b, 0x01},
+   {0x2c, 0xce}, 
+   {0x2d, 0x01},
+   {0x2e, 0xce}, 
+   {0x2f, 0x01},
+   {0x30, 0xce}, 
+   {0x31, 0x01},
+   {0x32, 0xce}, 
+   {0x33, 0x01},
+   {0x34, 0xce}, 
+   {0x3c, 0x10}, 
+   {0xfe, 0x00},
+   {0x44, 0x03},
+}
+
+function gc032aInit(cspiId,i2cId,speed,scanMode,onlyY)
+	local id = camera.init(cspiId,speed,1,1,2,1,0x00010101,onlyY,scanMode,640,480)
+	for i=1,#reg_table do
+		i2c.send(i2cId,0x21,reg_table[i],1)
+	end
+	camera.start(id)
+	return id
+end

+ 153 - 0
module/Air780E/demo/camera/spi_cam/main.lua

@@ -0,0 +1,153 @@
+PROJECT = "camerademo"
+VERSION = "1.0.0"
+-- 实际使用时选1个就行
+require "bf30a2"
+require "gc032a"
+require "gc0310"
+sys = require("sys")
+log.style(1)
+
+local SCAN_MODE = 0 -- 写1演示扫码
+local scan_pause = true
+local getRawStart = false
+local RAW_MODE = 0 -- 写1演示获取原始图像
+-- SCAN_MODE和RAW_MODE都没有写1就是拍照
+
+
+local spi_id, pin_reset, pin_dc, pin_cs, bl
+spi_lcd = spi.deviceSetup(spi_id, pin_cs, 0, 0, 8, 20 * 1000 * 1000, spi.MSB, 1, 0)
+port = "device"
+
+--[[ 此为合宙售卖的1.8寸TFT LCD LCD 分辨率:128X160 屏幕ic:st7735 购买地址:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-24045920841.19.6c2275a1Pa8F9o&id=560176729178]]
+-- lcd.init("st7735",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 128,h = 160,xoffset = 0,yoffset = 0},spi_lcd)
+
+--[[ 此为合宙售卖的1.54寸TFT LCD LCD 分辨率:240X240 屏幕ic:st7789 购买地址:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-24045920841.20.391445d5Ql4uJl&id=659456700222]]
+-- lcd.init("st7789",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 240,h = 320,xoffset = 0,yoffset = 0},spi_lcd,true)
+
+--[[ 此为合宙售卖的0.96寸TFT LCD LCD 分辨率:160X80 屏幕ic:st7735s 购买地址:https://item.taobao.com/item.htm?id=661054472686]]
+-- lcd.init("st7735v",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 1,w = 160,h = 80,xoffset = 0,yoffset = 24},spi_lcd)
+-- 如果显示颜色相反,请解开下面一行的注释,关闭反色
+-- lcd.invoff()
+-- 如果显示依旧不正常,可以尝试老版本的板子的驱动
+-- lcd.init("st7735s",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 2,w = 160,h = 80,xoffset = 0,yoffset = 0},spi_lcd)
+lcd.init("gc9306x", {
+    port = port,
+    pin_dc = pin_dc,
+    pin_pwr = bl,
+    pin_rst = pin_reset,
+    direction = 0,
+    w = 240,
+    h = 320,
+    xoffset = 0,
+    yoffset = 0
+}, spi_lcd, true)
+
+local uartid = uart.VUART_0 -- 根据实际设备选取不同的uartid
+-- 初始化
+local result = uart.setup(uartid, -- 串口id
+115200, -- 波特率
+8, -- 数据位
+1 -- 停止位
+)
+
+camera.on(0, "scanned", function(id, str)
+    if type(str) == 'string' then
+        log.info("扫码结果", str)
+    elseif str == false then
+        log.error("摄像头没有数据")
+    else
+        log.info("摄像头数据", str)
+        sys.publish("capture done", true)
+    end
+end)
+
+local function press_key()
+    log.info("boot press")
+    sys.publish("PRESS", true)
+end
+gpio.setup(0, press_key, gpio.PULLDOWN, gpio.RISING)
+gpio.debounce(0, 100, 1)
+local rawbuff, err
+if RAW_MODE ~= 1 then
+    rawbuff, err = zbuff.create(60 * 1024, 0, zbuff.HEAP_AUTO)
+else
+    rawbuff, err = zbuff.create(640 * 480 * 2, 0, zbuff.HEAP_AUTO) -- gc032a
+    -- local rawbuff = zbuff.create(240 * 320 * 2, zbuff.HEAP_AUTO)  --bf302a
+end
+if rawbuff == nil then
+    log.info(err)
+end
+
+sys.taskInit(function()
+    log.info("摄像头启动")
+    local cspiId, i2cId = 1, 1
+    local camera_id
+    i2c.setup(i2cId, i2c.FAST)
+    gpio.setup(5, 0) -- PD拉低
+    -- camera_id = bf30a2Init(cspiId,i2cId,25500000,SCAN_MODE,SCAN_MODE)
+    camera_id = gc0310Init(cspiId, i2cId, 25500000, SCAN_MODE, SCAN_MODE)
+    -- camera_id = gc032aInit(cspiId,i2cId,24000000,SCAN_MODE,SCAN_MODE)
+    camera.stop(camera_id)
+    camera.preview(camera_id, true)
+    log.info("按下boot开始测试")
+    log.info(rtos.meminfo("sys"))
+    log.info(rtos.meminfo("psram"))
+    while 1 do
+        result, data = sys.waitUntil("PRESS", 30000)
+        if result == true and data == true then
+            if SCAN_MODE == 1 then
+                if scan_pause then
+                    log.info("启动扫码")
+                    -- camera_id = gc0310Init(cspiId,i2cId,25500000,SCAN_MODE,SCAN_MODE)
+                    camera.start(camera_id)
+                    scan_pause = false
+                    sys.wait(200)
+                    log.info(rtos.meminfo("sys"))
+                    log.info(rtos.meminfo("psram"))
+                else
+                    log.info("停止扫码")
+                    -- camera.close(camera_id)	--完全关闭摄像头才用这个
+                    camera.stop(camera_id)
+                    scan_pause = true
+                    sys.wait(200)
+                    log.info(rtos.meminfo("sys"))
+                    log.info(rtos.meminfo("psram"))
+                end
+            elseif RAW_MODE == 1 then
+                if getRawStart == false then
+                    getRawStart = true
+                    log.debug("摄像头首次捕获原始图像")
+                    camera.startRaw(camera_id, 640, 480, rawbuff) -- gc032a
+                    -- camera.startRaw(camera_id,240,320,rawbuff) --bf302a
+                else
+                    log.debug("摄像头继续捕获原始图像")
+                    camera.getRaw(camera_id)
+                end
+                result, data = sys.waitUntil("capture done", 30000)
+                log.info("摄像头捕获原始图像完成")
+                log.info(rtos.meminfo("sys"))
+                log.info(rtos.meminfo("psram"))
+                -- uart.tx(uartid, rawbuff) --找个能保存数据的串口工具保存成文件就能在电脑上看了, 格式为JPG                
+            else
+                log.debug("摄像头拍照")
+                -- camera_id = gc0310Init(cspiId,i2cId,25500000,SCAN_MODE,SCAN_MODE)
+                camera.capture(camera_id, rawbuff, 1) -- 2和3需要非常多非常多的psram,尽量不要用
+                result, data = sys.waitUntil("capture done", 30000)
+                log.info(rawbuff:used())
+                -- camera.close(camera_id)	--完全关闭摄像头才用这个
+                camera.stop(camera_id)
+                uart.tx(uartid, rawbuff) -- 找个能保存数据的串口工具保存成文件就能在电脑上看了, 格式为JPG
+                rawbuff:resize(60 * 1024)
+                log.info(rtos.meminfo("sys"))
+                log.info(rtos.meminfo("psram"))
+            end
+
+        end
+    end
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

BIN
module/Air780E/demo/crypto/logo.jpg


+ 242 - 0
module/Air780E/demo/crypto/main.lua

@@ -0,0 +1,242 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "cryptodemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+
+    sys.wait(1000)
+
+    -- MD5,输出结果已经hex编码
+    log.info("md5", crypto.md5("abc"))
+    log.info("hmac_md5", crypto.hmac_md5("abc", "1234567890"))
+
+    -- SHA1,输出结果已经hex编码
+    log.info("sha1", crypto.sha1("abc"))
+    log.info("hmac_sha1", crypto.hmac_sha1("abc", "1234567890"))
+
+    -- SHA256,输出结果已经hex编码
+    log.info("sha256", crypto.sha256("abc"))
+    log.info("hmac_sha256", crypto.hmac_sha256("abc", "1234567890"))
+
+    -- SHA512,输出结果已经hex编码
+    log.info("sha512", crypto.sha512("abc"))
+    log.info("hmac_sha512", crypto.hmac_sha512("abc", "1234567890"))
+
+	local data_encrypt = crypto.cipher_encrypt("AES-128-ECB", "ZERO", "023001", "HZBIT@WLW/YSBKEY")
+	log.info("AES", "aes-128-ecb", data_encrypt:toHex())
+	local data_decrypt = crypto.cipher_decrypt("AES-128-ECB", "ZERO", data_encrypt, "HZBIT@WLW/YSBKEY")
+	log.info("AES", "aes-128-ecb", data_decrypt)
+
+    -- AES加密, 未经Hex编码. AES-128-ECB 算法,待加密字符串如果超过32字节会报错,待查. by wendal 20200812
+    local data_encrypt = crypto.cipher_encrypt("AES-128-ECB", "PKCS7", "12345678901234 > 123456", "1234567890123456")
+    local data2_encrypt = crypto.cipher_encrypt("AES-128-CBC", "PKCS7", "12345678901234 > 123456", "1234567890123456", "1234567890666666")
+    log.info("AES", "aes-128-ecb", data_encrypt:toHex())
+    log.info("AES", "aes-128-cbc", data2_encrypt:toHex())
+
+    -- AES解密, 未经Hex编码
+    local data_decrypt = crypto.cipher_decrypt("AES-128-ECB", "PKCS7", data_encrypt, "1234567890123456")
+    local data2_decrypt = crypto.cipher_decrypt("AES-128-CBC", "PKCS7", data2_encrypt, "1234567890123456", "1234567890666666")
+    log.info("AES", "aes-128-ecb", data_decrypt)
+    log.info("AES", "aes-128-cbc", data2_decrypt)
+    log.info("mem", rtos.meminfo("sys"))
+
+    -- DES-ECB 加解密
+    local data1 = crypto.cipher_encrypt("DES-ECB", "PKCS7", "abcdefg", "12345678")
+    if data1 then -- DES-ECB 在某些平台不支持的
+        log.info("des", data1:toHex())
+        local data2 = crypto.cipher_decrypt("DES-ECB", "PKCS7", data1, "12345678")
+        log.info("des", data2)
+    else
+        log.info("des", "当前固件不支持DES/3DES")
+    end
+
+    -- 3DES-ECB 加解密
+    local data1 = crypto.cipher_encrypt("DES-EDE3-ECB", "PKCS7", "abcdefg!!--ZZSS", "123456781234567812345678")
+    if data1 then -- DES-ECB 在某些平台不支持的
+        log.info("3des", data1:toHex())
+        local data2 = crypto.cipher_decrypt("DES-EDE3-ECB", "PKCS7", data1, "123456781234567812345678")
+        log.info("3des", data2)
+    else
+        log.info("3des", "当前固件不支持DES/3DES")
+    end
+
+
+    -- 打印所有支持的cipher
+    if crypto.cipher_list then
+        log.info("cipher", "list", json.encode(crypto.cipher_list()))
+    else
+        log.info("cipher", "当前固件不支持crypto.cipher_list")
+    end
+    -- 打印所有支持的cipher suites
+    if crypto.cipher_suites then
+        log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
+    else
+        log.info("cipher", "当前固件不支持crypto.cipher_suites")
+    end
+
+    ---------------------------------------
+    log.info("随机数测试")
+    for i=1, 10 do
+        sys.wait(100)
+        log.info("crypto", "真随机数",string.unpack("I",crypto.trng(4)))
+        -- log.info("crypto", "伪随机数",math.random()) -- 输出的是浮点数,不推荐
+        -- log.info("crypto", "伪随机数",math.random(1, 65525)) -- 不推荐
+    end
+
+    -- totp的密钥
+    log.info("totp的密钥")
+    local secret = "VK54ZXPO74ISEM2E"
+    --写死时间戳用来测试
+    local ts = 1646796576
+    --生成十分钟的动态码验证下
+    for i=1,600,30 do
+        local r = crypto.totp(secret,ts+i)
+        local time = os.date("*t",ts+i + 8*3600)--东八区
+        log.info("totp", string.format("%06d" ,r),time.hour,time.min,time.sec)
+    end
+
+    -- 文件测试
+    log.info("文件hash值测试")
+    if crypto.md_file then
+        log.info("md5", crypto.md_file("MD5", "/luadb/logo.jpg"))
+        log.info("sha1", crypto.md_file("SHA1", "/luadb/logo.jpg"))
+        log.info("sha256", crypto.md_file("SHA256", "/luadb/logo.jpg"))
+        
+        log.info("hmac_md5", crypto.md_file("MD5", "/luadb/logo.jpg", "123456"))
+        log.info("hmac_sha1", crypto.md_file("SHA1", "/luadb/logo.jpg", "123456"))
+        log.info("hmac_sha256", crypto.md_file("SHA256", "/luadb/logo.jpg", "123456"))
+    else
+        log.info("文件hash值测试", "当前固件不支持crypto.md_file")
+    end
+
+    if crypto.checksum then
+        log.info("checksum", "OK", string.char(crypto.checksum("OK")):toHex())
+        log.info("checksum", "357E", string.char(crypto.checksum("357E", 1)):toHex())
+    else
+        log.info("checksum", "当前固件不支持crypto.checksum")
+    end
+
+    -- 流式hash测试
+    log.info("流式hash测试")
+    if crypto.hash_init then
+        -- MD5
+        local md5_obj = crypto.hash_init("MD5")
+        crypto.hash_update(md5_obj, "1234567890")
+        crypto.hash_update(md5_obj, "1234567890")
+        crypto.hash_update(md5_obj, "1234567890")
+        crypto.hash_update(md5_obj, "1234567890")
+        local md5_result = crypto.hash_finish(md5_obj)
+        log.info("md5_stream", md5_result)
+        log.info("md5", crypto.md5("1234567890123456789012345678901234567890"))
+
+        -- HMAC_MD5
+        local hmac_md5_obj = crypto.hash_init("MD5", "1234567890")
+        crypto.hash_update(hmac_md5_obj, "1234567890")
+        crypto.hash_update(hmac_md5_obj, "1234567890")
+        crypto.hash_update(hmac_md5_obj, "1234567890")
+        crypto.hash_update(hmac_md5_obj, "1234567890")
+        local hmac_md5_result = crypto.hash_finish(hmac_md5_obj)
+        log.info("hmac_md5_stream", hmac_md5_result)
+        log.info("hmac_md5", crypto.hmac_md5("1234567890123456789012345678901234567890", "1234567890"))
+
+        -- SHA1
+        local sha1_obj = crypto.hash_init("SHA1")
+        crypto.hash_update(sha1_obj, "1234567890")
+        crypto.hash_update(sha1_obj, "1234567890")
+        crypto.hash_update(sha1_obj, "1234567890")
+        crypto.hash_update(sha1_obj, "1234567890")
+        local sha1_result = crypto.hash_finish(sha1_obj)
+        log.info("sha1_stream", sha1_result)
+        log.info("sha1", crypto.sha1("1234567890123456789012345678901234567890"))
+
+        -- HMAC_SHA1
+        local hmac_sha1_obj = crypto.hash_init("SHA1", "1234567890")
+        crypto.hash_update(hmac_sha1_obj, "1234567890")
+        crypto.hash_update(hmac_sha1_obj, "1234567890")
+        crypto.hash_update(hmac_sha1_obj, "1234567890")
+        crypto.hash_update(hmac_sha1_obj, "1234567890")
+        local hmac_sha1_result = crypto.hash_finish(hmac_sha1_obj)
+        log.info("hmac_sha1_stream", hmac_sha1_result)
+        log.info("hmac_sha1", crypto.hmac_sha1("1234567890123456789012345678901234567890", "1234567890"))
+
+        -- SHA256
+        local sha256_obj = crypto.hash_init("SHA256")
+        crypto.hash_update(sha256_obj, "1234567890")
+        crypto.hash_update(sha256_obj, "1234567890")
+        crypto.hash_update(sha256_obj, "1234567890")
+        crypto.hash_update(sha256_obj, "1234567890")
+        local sha256_result = crypto.hash_finish(sha256_obj)
+        log.info("sha256_stream", sha256_result)
+        log.info("sha256", crypto.sha256("1234567890123456789012345678901234567890"))
+
+        -- HMAC_SHA256
+        local hmac_sha256_obj = crypto.hash_init("SHA256", "1234567890")
+        crypto.hash_update(hmac_sha256_obj, "1234567890")
+        crypto.hash_update(hmac_sha256_obj, "1234567890")
+        crypto.hash_update(hmac_sha256_obj, "1234567890")
+        crypto.hash_update(hmac_sha256_obj, "1234567890")
+        local hmac_sha256_result = crypto.hash_finish(hmac_sha256_obj)
+        log.info("hmac_sha256_stream", hmac_sha256_result)
+        log.info("hmac_sha256", crypto.hmac_sha256("1234567890123456789012345678901234567890", "1234567890"))
+
+        -- SHA512
+        local sha512_obj = crypto.hash_init("SHA512")
+        if sha512_obj then
+            crypto.hash_update(sha512_obj, "1234567890")
+            crypto.hash_update(sha512_obj, "1234567890")
+            crypto.hash_update(sha512_obj, "1234567890")
+            crypto.hash_update(sha512_obj, "1234567890")
+            local sha512_result = crypto.hash_finish(sha512_obj)
+            log.info("sha512_stream", sha512_result)
+            log.info("sha512", crypto.sha512("1234567890123456789012345678901234567890"))
+        end
+
+        -- HMAC_SHA512
+        local hmac_sha512_obj = crypto.hash_init("SHA512", "1234567890")
+        if hmac_sha512_obj then
+            crypto.hash_update(hmac_sha512_obj, "1234567890")
+            crypto.hash_update(hmac_sha512_obj, "1234567890")
+            crypto.hash_update(hmac_sha512_obj, "1234567890")
+            crypto.hash_update(hmac_sha512_obj, "1234567890")
+            local hmac_sha512_result = crypto.hash_finish(hmac_sha512_obj)
+            log.info("hmac_sha512_stream", hmac_sha512_result)
+            log.info("hmac_sha512", crypto.hmac_sha512("1234567890123456789012345678901234567890", "1234567890"))
+        end
+    else
+        log.info("crypto", "当前固件不支持crypto.hash_init")
+    end
+
+    log.info("crc7测试")
+    if crypto.crc7 then
+        local result = crypto.crc7(string.char(0xAA), 0xE5, 0x00)
+        log.info("crc7测试", result, string.format("%02X", result))
+    else
+        log.info("crypto", "当前固件不支持crypto.crc7")
+    end
+
+    log.info("crypto", "ALL Done")
+    sys.wait(100000)
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 21 - 0
module/Air780E/demo/dht11/main.lua

@@ -0,0 +1,21 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "dht12"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+sys.taskInit(function()
+    local dht11_pin = 7
+    while 1 do
+        sys.wait(1000)
+        local h,t,r = sensor.dht1x(dht11_pin, true)
+        log.info("dht11", "湿度", h/100, "温度", t/100,r)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 25 - 0
module/Air780E/demo/dht12/main.lua

@@ -0,0 +1,25 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "dht12"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+-- https://datasheet.lcsc.com/szlcsc/DHT12-Digital-temperature-and-humidity-sensor_C83989.pdf
+
+sys.taskInit(function()
+    local id = 0--i2c的id,请按需更改
+    while 1 do
+        sys.wait(5000) -- 5秒读取一次
+        i2c.setup(id, i2c.SLOW)
+        --log.info("dht12", read_dht12(0)) -- 如果想用传统方式读取,请取消read_dht12方法的注释
+        log.info("dht12", i2c.readDHT12(id))
+        i2c.close(id)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 121 - 0
module/Air780E/demo/dingding/main.lua

@@ -0,0 +1,121 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "dingdingdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo是演示钉钉的 "自定义webhook机器人"
+]]
+
+--------------------------------------------------------------------------------------
+-- webhook和secret要换成你自己机器人的值
+-- webhook是钉钉分配给机器人的URL
+-- secret是选取 "加签", 自动生成的密钥
+-- 下面的给LuatOS的一个测试群发消息, 随时可能关掉, 换成你自己的值
+local webhook = "https://oapi.dingtalk.com/robot/send?access_token=7ddc72eeb8fb7dcb4898834c318cfec994a1c33faea05dfc8031d22ce56131cf"
+local secret = "SECf1d8a3a5abc32671f5353ed095d3135580357ef26a1b43f841e620cdf498d384"
+--------------------------------------------------------------------------------------
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用http库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+if wdt then
+    wdt.init(3000)
+    sys.timerLoopStart(wdt.feed, 1000)
+end
+
+-- 因为这个demo适合所有能联网的设备
+-- 统一联网函数, 按需要增删
+sys.taskInit(function()
+    if http == nil then
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本固件未包含http库, 请查证")
+        end
+    end
+    local device_id = mcu.unique_id():toHex()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        log.info("wifi", ssid, password)
+        -- TODO 改成自动配网
+        -- LED = gpio.setup(12, 0, gpio.PULLUP)
+        wlan.init()
+        wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
+        device_id = wlan.getMac()
+        wlan.connect(ssid, password, 1)
+    elseif mobile then
+        -- Air780E/Air600E系列
+        --mobile.simid(2) -- 自动切换SIM卡
+        -- LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+    elseif w5500 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)
+    elseif mqtt then
+        -- 适配的mqtt库也OK
+        -- 没有其他操作, 单纯给个注释说明
+    else
+        -- 其他不认识的bsp, 循环提示一下吧
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp可能未适配网络层, 请查证")
+        end
+    end
+    -- 默认都等到联网成功
+    log.info("wait IP_READY")
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready", device_id)
+end)
+
+sys.taskInit(function()
+    -- 等待联网
+    local _, device_id = sys.waitUntil("net_ready")
+    sys.wait(500)
+    socket.sntp() -- 如果是联网卡, 这里是需要sntp的, 否则时间不对
+    sys.waitUntil("NTP_UPDATE", 5000)
+
+    local rheaders = {}
+    rheaders["Content-Type"] = "application/json"
+    while 1 do
+        local timestamp = tostring(os.time()) .. "000" -- LuatOS的时间戳只到秒,但钉钉需要毫秒,补3个零
+        -- timestamp = "1684673085314"
+        local tmp = crypto.hmac_sha256(timestamp .. "\n" .. secret, secret)
+        -- log.info("tmp", "hmac_sha256", tmp)
+        -- log.info("tmp", "base64", tmp:fromHex():toBase64())
+        local sign = crypto.hmac_sha256(timestamp .. "\n" .. secret, secret):fromHex():toBase64():urlEncode()
+        log.info("timestamp", timestamp)
+        log.info("sign", sign)
+        local url = webhook .. "&timestamp=" .. timestamp .. "&sign=" .. sign
+        log.info("url", url)
+        local data = {msgtype="text"}
+        -- content就是要发送的文本内容, 其他格式按钉钉的要求拼接table就好了
+        local content = "我的id是" .. tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp()
+        data["text"] = {content=content}
+        local code,headers, body = http.request("POST", url, rheaders, (json.encode(data))).wait()
+        -- 正常会返回 200, {"errcode":0,"errmsg":"ok"}
+        -- 其他错误, 一般是密钥错了, 仔细检查吧
+        log.info("dingding", code, body)
+        sys.wait(60000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 91 - 0
module/Air780E/demo/eink/main.lua

@@ -0,0 +1,91 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "einkdemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--[[
+
+注意,使用前先看本注释每一句话!!!!!!!
+注意,使用前先看本注释每一句话!!!!!!!
+注意,使用前先看本注释每一句话!!!!!!!
+
+注意:具体硬件接线参考下方eink_pin 函数的gpio定义,
+eink_pin函数会返回对应bsp的 spi_id,pin_reset,pin_dc,pin_cs,pin_busy 值,下方函数有注释
+spi_id对应引脚参考对应芯片/模组手册,使用开发板的话看开发板原理图
+
+举例AIR101:
+AIR101就看bsp判断分支 rtos_bsp == "AIR101"
+返回的 0,pin.PB03,pin.PB01,pin.PB04,pin.PB00 依次为 spi_id,pin_reset,pin_dc,pin_cs,pin_busy
+spi_id为0就看芯片手册spi0引脚定义,即 SCLK=PB02, MOSI=PB05, MISO=PB03 因为只需要输出所以不需要miso引脚,miso引脚用作了pin_reset
+所以AIR101接线为 Pin_RSCL:PB02, Pin_RSDA:PB05, Pin_RES:PB03, Pin_DC:PB01, Pin_CS:PB04, Pin_BUSY:PB00
+
+再举例EC618:
+EC618就看bsp判断分支 rtos_bsp == "EC618"
+返回的 0,1,10,8,22 依次为 spi_id,pin_reset,pin_dc,pin_cs,pin_busy
+spi_id为0就看芯片手册spi0引脚定义,即 SCLK=GPIO11, MOSI=GPIO9, MISO=GPIO10 因为只需要输出所以不需要miso引脚,miso引脚用作了pin_dc
+所以EC618接线为 Pin_RSCL:GPIO11, Pin_RSDA:GPIO9, Pin_RES:GPIO1, Pin_DC:GPIO10, Pin_CS:GPIO8, Pin_BUSY:GPIO22
+
+
+本demo为 1.54寸v2,200x200 屏幕,实际使用什么屏幕自己看自己的屏幕规格,
+不是一样的尺寸就随便用,后缀的 v1 v2 v3 abcd 都有区别并不通用否则不同驱动就没意义了
+
+注意,使用前先看本注释!!!!!!!
+注意,使用前先看本注释!!!!!!!
+注意,使用前先看本注释!!!!!!!
+
+]]
+
+
+-- spi_id,pin_reset,pin_dc,pin_cs,pin_busy
+function eink_pin()     
+    return 0,1,10,8,22
+end
+
+sys.taskInit(function()
+    local spi_id,pin_reset,pin_dc,pin_cs,pin_busy,mode = eink_pin() 
+    if spi_id then
+        eink.model(eink.MODEL_1in54)
+        spi.setup(spi_id,nil,0,0,8,20*1000*1000)
+        eink.setup(mode, spi_id,pin_busy,pin_reset,pin_dc,pin_cs)
+        eink.setWin(200, 200, 0)
+        --稍微等一会,免得墨水屏没初始化完成
+        sys.wait(100)
+        log.info("e-paper 1.54", "Testing Go")
+        eink.clear()
+        --画几条线一个圆
+        eink.circle(50, 100, 40)
+        eink.line(100, 20, 105, 180)
+        eink.line(100, 100, 180, 20)
+        eink.line(100, 100, 180, 180)
+        eink.show()
+        log.info("e-paper 1.54", "Testing End")
+    end
+end)
+
+-- 2022.12.02后编译的固件推荐使用以下方法
+-- local sysplus = require("sysplus")
+-- sys.taskInit(function()
+--     local spi_id,pin_reset,pin_dc,pin_cs,pin_busy,mode = eink_pin() 
+--     if spi_id then
+--         eink.async(1)
+--         spi_eink = spi.deviceSetup(spi_id,pin_cs,0,0,8,20*1000*1000,spi.MSB,1,0)
+--         eink.init(eink.MODEL_1in54,
+--                 {port = "device",pin_dc = pin_dc, pin_busy = pin_busy,pin_rst = pin_reset},
+--                 spi_eink)
+--         eink.setWin(200, 200, 0)
+--         sys.wait(100)
+    
+--         log.info("e-paper 1.54", "Testing Go")
+--         eink.clear().wait()
+--         eink.print(30, 20, "LuatOS-AIR780E",0x00)
+    
+--         eink.show().wait()
+--         log.info("e-paper 1.54", "Testing End")
+--     end
+-- end)
+
+
+sys.run()

+ 62 - 0
module/Air780E/demo/errDump/main.lua

@@ -0,0 +1,62 @@
+PROJECT = "errdump_test"
+VERSION = "1.0"
+PRODUCT_KEY = "s1uUnY6KA06ifIjcutm5oNbG3MZf5aUv" --换成自己的
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+log.style(1)
+
+--下面演示自动发送
+-- errDump.config(true, 600, "user_id")	-- 默认是关闭,用这个可以额外添加用户标识,比如用户自定义的ID之类
+
+-- local function test_user_log()
+-- 	while true do
+-- 		sys.wait(15000)
+-- 		errDump.record("测试一下用户的记录功能")
+-- 	end
+-- end
+
+-- local function test_error_log()
+-- 	sys.wait(60000)
+-- 	-- lllllllllog.record("测试一下用户的记录功能") --默认写错代码死机
+-- end
+
+
+
+-- 下面演示手动获取信息
+errDump.config(true, 0)
+local function test_user_log()
+	local buff = zbuff.create(4096)
+	local new_flag = errDump.dump(buff, errDump.TYPE_SYS)		-- 开机手动读取一次异常日志
+	if buff:used() > 0 then
+		log.info(buff:toStr(0, buff:used()))	-- 打印出异常日志
+	end
+	new_flag = errDump.dump(buff, errDump.TYPE_SYS)
+	if not new_flag then
+		log.info("没有新数据了,删除系统错误日志")
+		errDump.dump(nil, errDump.TYPE_SYS, true)
+	end
+	while true do
+		sys.wait(15000)
+		errDump.record("测试一下用户的记录功能")
+		local new_flag = errDump.dump(buff, errDump.TYPE_USR)
+		if new_flag then
+			log.info("errBuff", buff:toStr(0, buff:used()))
+		end
+		new_flag = errDump.dump(buff, errDump.TYPE_USR)
+		if not new_flag then
+			log.info("没有新数据了,删除用户错误日志")
+			errDump.dump(nil, errDump.TYPE_USR, true)
+		end
+
+	end
+end
+
+local function test_error_log()
+	sys.wait(60000)
+	lllllllllog.record("测试一下用户的记录功能") --默认写错代码死机
+end
+
+sys.taskInit(test_user_log)
+sys.taskInit(test_error_log)
+sys.run()

+ 97 - 0
module/Air780E/demo/fastlz/fastlz.h

@@ -0,0 +1,97 @@
+/*
+  FastLZ - Byte-aligned LZ77 compression library
+  Copyright (C) 2005-2020 Ariya Hidayat <ariya.hidayat@gmail.com>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef FASTLZ_H
+#define FASTLZ_H
+
+#define FASTLZ_VERSION 0x000500
+
+#define FASTLZ_VERSION_MAJOR 0
+#define FASTLZ_VERSION_MINOR 5
+#define FASTLZ_VERSION_REVISION 0
+
+#define FASTLZ_VERSION_STRING "0.5.0"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+  Compress a block of data in the input buffer and returns the size of
+  compressed block. The size of input buffer is specified by length. The
+  minimum input buffer size is 16.
+
+  The output buffer must be at least 5% larger than the input buffer
+  and can not be smaller than 66 bytes.
+
+  If the input is not compressible, the return value might be larger than
+  length (input buffer size).
+
+  The input buffer and the output buffer can not overlap.
+
+  Compression level can be specified in parameter level. At the moment,
+  only level 1 and level 2 are supported.
+  Level 1 is the fastest compression and generally useful for short data.
+  Level 2 is slightly slower but it gives better compression ratio.
+
+  Note that the compressed data, regardless of the level, can always be
+  decompressed using the function fastlz_decompress below.
+*/
+
+int fastlz_compress_level(int level, const void* input, int length, void* output);
+
+/**
+  Decompress a block of compressed data and returns the size of the
+  decompressed block. If error occurs, e.g. the compressed data is
+  corrupted or the output buffer is not large enough, then 0 (zero)
+  will be returned instead.
+
+  The input buffer and the output buffer can not overlap.
+
+  Decompression is memory safe and guaranteed not to write the output buffer
+  more than what is specified in maxout.
+
+  Note that the decompression will always work, regardless of the
+  compression level specified in fastlz_compress_level above (when
+  producing the compressed block).
+ */
+
+int fastlz_decompress(const void* input, int length, void* output, int maxout);
+
+/**
+  DEPRECATED.
+
+  This is similar to fastlz_compress_level above, but with the level
+  automatically chosen.
+
+  This function is deprecated and it will be completely removed in some future
+  version.
+*/
+
+int fastlz_compress(const void* input, int length, void* output);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* FASTLZ_H */

+ 34 - 0
module/Air780E/demo/fastlz/main.lua

@@ -0,0 +1,34 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fastlzdemo"
+VERSION = "1.0.0"
+
+sys = require("sys")
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+    sys.wait(1000)
+    -- 压缩过的字符串
+    local tmp = io.readFile("/luadb/fastlz.h") or "q309pura;dsnf;asdouyf89q03fonaewofhaeop;fhiqp02398ryhai;ofinap983fyua0weo;ifhj3p908fhaes;iofaw789prhfaeiwop;fhaesp98fadsjklfhasklfsjask;flhadsfk"
+    local L1 = fastlz.compress(tmp)
+    local dstr = fastlz.uncompress(L1)
+    log.info("fastlz", "压缩等级1", #tmp, #L1, #dstr)
+    L1 = nil
+    dstr = nil
+    local L2 = fastlz.compress(tmp, 2)
+    local dstr = fastlz.uncompress(L2)
+    log.info("fastlz", "压缩等级2", #tmp, #L2, #dstr)
+    L1 = nil
+    dstr = nil
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 130 - 0
module/Air780E/demo/fatfs/main.lua

@@ -0,0 +1,130 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fatfs"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--[[
+接线要求:
+
+SPI 使用常规4线解法
+开发板(Air105)         TF模块
+PB3                    CS
+PB2(SPI2_CLK)          CLK
+PB4(SPI2_MISO)         MOSI
+PB5(SPI2_MISO)         MISO
+3.3V                   VCC
+GND                    GND
+
+核心要义: 找对应SPI端口的3个脚, CLK时钟, MISO和MOSI, CS脚可以选硬件默认的,也可以自选一个普通GPIO
+
+SD/TF模块请选不带电平转换的版本!!
+https://detail.tmall.com/item.htm?abbucket=10&id=634710962749&ns=1&spm=a21n57.1.0.0.696f523csnpBFA&skuId=4710673879054
+
+如果是带电平转换的, SPI波特率要限制在10M或以下
+]]
+
+-- 特别提醒, 由于FAT32是DOS时代的产物, 文件名超过8个字节是需要额外支持的(需要更大的ROM)
+-- 例如 /sd/boottime 是合法文件名, 而/sd/boot_time就不是合法文件名, 需要启用长文件名支持.
+
+-- spi_id,pin_cs
+local function fatfs_spi_pin()  
+    return 0, 8
+end
+
+sys.taskInit(function()
+    sys.wait(1000)
+    -- fatfs.debug(1) -- 若挂载失败,可以尝试打开调试信息,查找原因
+
+    -- 此为spi方式
+    local spi_id, pin_cs = fatfs_spi_pin() 
+    spi.setup(spi_id, nil, 0, 0, 8, 400 * 1000)
+    gpio.setup(pin_cs, 1)
+    fatfs.mount(fatfs.SPI, "/sd", spi_id, pin_cs, 24 * 1000 * 1000)
+
+    -- 此为sdio方式,目前只101/103支持sdio,按需使用
+    -- fatfs.mount(fatfs.SDIO, "/sd")
+
+    local data, err = fatfs.getfree("/sd")
+    if data then
+        log.info("fatfs", "getfree", json.encode(data))
+    else
+        log.info("fatfs", "err", err)
+    end
+
+    -- #################################################
+    -- 文件操作测试
+    -- #################################################
+    local f = io.open("/sd/boottime", "rb")
+    local c = 0
+    if f then
+        local data = f:read("*a")
+        log.info("fs", "data", data, data:toHex())
+        c = tonumber(data)
+        f:close()
+    end
+    log.info("fs", "boot count", c)
+    if c == nil then
+        c = 0
+    end
+    c = c + 1
+    f = io.open("/sd/boottime", "wb")
+    if f ~= nil then
+        log.info("fs", "write c to file", c, tostring(c))
+        f:write(tostring(c))
+        f:close()
+    else
+        log.warn("sdio", "mount not good?!")
+    end
+    if fs then
+        log.info("fsstat", fs.fsstat("/"))
+        log.info("fsstat", fs.fsstat("/sd"))
+    end
+
+    -- 测试一下追加, fix in 2021.12.21
+    os.remove("/sd/test_a")
+    sys.wait(50)
+    f = io.open("/sd/test_a", "w")
+    if f then
+        f:write("ABC")
+        f:close()
+    end
+    f = io.open("/sd/test_a", "a+")
+    if f then
+        f:write("def")
+        f:close()
+    end
+    f = io.open("/sd/test_a", "r")
+    if  f then
+        local data = f:read("*a")
+        log.info("data", data, data == "ABCdef")
+        f:close()
+    end
+
+    -- 测试一下按行读取, fix in 2022-01-16
+    f = io.open("/sd/testline", "w")
+    if f then
+        f:write("abc\n")
+        f:write("123\n")
+        f:write("wendal\n")
+        f:close()
+    end
+    sys.wait(100)
+    f = io.open("/sd/testline", "r")
+    if f then
+        log.info("sdio", "line1", f:read("*l"))
+        log.info("sdio", "line2", f:read("*l"))
+        log.info("sdio", "line3", f:read("*l"))
+        f:close()
+    end
+
+    -- #################################################
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 124 - 0
module/Air780E/demo/feishu/main.lua

@@ -0,0 +1,124 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "feishudemo"
+VERSION = "1.0.0"
+
+--[[
+本demo是演示飞书的 "自定义机器人"
+]]
+
+--------------------------------------------------------------------------------------
+-- webhook和secret要换成你自己机器人的值
+-- webhook是钉钉分配给机器人的URL
+-- secret是选取 "加签", 自动生成的密钥
+-- 下面的给一个测试群发消息, 随时可能关掉, 换成你自己的值
+local webhook = "https://open.feishu.cn/open-apis/bot/v2/hook/568bfe5a-eda5-4a79-8348-9d21c572cc3b"
+local secret = "XRtUovKq24De3zkNS9VHVf"
+--------------------------------------------------------------------------------------
+
+-- 飞书关于机器人的文档 https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN?lang=zh-CN
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用http库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+if wdt then
+    wdt.init(3000)
+    sys.timerLoopStart(wdt.feed, 1000)
+end
+
+-- 因为这个demo适合所有能联网的设备
+-- 统一联网函数, 按需要增删
+sys.taskInit(function()
+    if http == nil then
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本固件未包含http库, 请查证")
+        end
+    end
+    local device_id = mcu.unique_id():toHex()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        log.info("wifi", ssid, password)
+        -- TODO 改成自动配网
+        -- LED = gpio.setup(12, 0, gpio.PULLUP)
+        wlan.init()
+        wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
+        device_id = wlan.getMac()
+        wlan.connect(ssid, password, 1)
+    elseif mobile then
+        -- Air780E/Air600E系列
+        --mobile.simid(2) -- 自动切换SIM卡
+        -- LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+    elseif w5500 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)
+    elseif mqtt then
+        -- 适配的mqtt库也OK
+        -- 没有其他操作, 单纯给个注释说明
+    else
+        -- 其他不认识的bsp, 循环提示一下吧
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp可能未适配网络层, 请查证")
+        end
+    end
+    -- 默认都等到联网成功
+    log.info("wait IP_READY")
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready", device_id)
+end)
+
+sys.taskInit(function()
+    -- 等待联网
+    local _, device_id = sys.waitUntil("net_ready")
+    sys.wait(500)
+    socket.sntp() -- 如果是联网卡, 这里是需要sntp的, 否则时间不对
+    sys.waitUntil("NTP_UPDATE", 5000)
+
+    local rheaders = {}
+    rheaders["Content-Type"] = "application/json"
+    while 1 do
+        -- LuatOS的时间戳只到秒,飞书也只需要秒
+        local timestamp = tostring(os.time())
+        -- timestamp = "1684673085314"
+        local tmp = crypto.hmac_sha256("", timestamp .. "\n" .. secret)
+        -- log.info("tmp", "hmac_sha256", tmp)
+        -- log.info("tmp", "base64", tmp:fromHex():toBase64())
+        local sign = crypto.hmac_sha256("", timestamp .. "\n" .. secret):fromHex():toBase64()
+        log.info("timestamp", timestamp)
+        log.info("sign", sign)
+        -- 注意, 这里的参数跟钉钉不同, 钉钉有个access_token参数, 飞书没有
+        local url = webhook
+        log.info("url", url)
+        -- json格式也需要按飞书的来
+        local data = {msg_type="text"}
+        data["timestamp"] = timestamp
+        data["sign"] = sign
+        -- text就是要发送的文本内容, 其他格式按飞书的要求拼接table就好了
+        local text = "我的id是" .. tostring(device_id) .. "," .. (os.date()) .. "," .. rtos.bsp()
+        data["content"] = {text=text}
+        local rbody = (json.encode(data))
+        log.info("feishu", rbody)
+        local code,headers, body = http.request("POST", url, rheaders, rbody).wait()
+        -- 正常会返回 200, {"StatusCode":0,"StatusMessage":"success","code":0,"data":{},"msg":"success"}
+        -- 其他错误, 一般是密钥错了, 仔细检查吧
+        log.info("feishu", code, body)
+        sys.wait(60000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 106 - 0
module/Air780E/demo/fota/main.lua

@@ -0,0 +1,106 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fotademo"
+VERSION = "1.0.0"
+
+--[[
+本demo 适用于 Air780E/Air780EG/Air600E
+1. 需要 V1103及以上的固件
+2. 需要 LuaTools 2.1.89 及以上的升级文件生成
+]]
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "1234" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+sys = require "sys"
+libfota = require "libfota"
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+-- 统一联网函数
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持, 要根据实际情况修改ssid和password!!
+        local ssid = "luatos1234"
+        local password = "12341234"
+        log.info("wifi", ssid, password)
+        -- TODO 改成自动配网
+        wlan.init()
+        wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
+        wlan.connect(ssid, password, 1)
+    elseif mobile then
+        -- EC618系列, 如Air780E/Air600E/Air700E
+        -- mobile.simid(2) -- 自动切换SIM卡, 按需启用
+        -- 模块默认会自动联网, 无需额外的操作
+    elseif w5500 then
+        -- w5500 以太网
+        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
+        w5500.config() --默认是DHCP模式
+        w5500.bind(socket.ETH0)
+    elseif socket then
+        -- 适配了socket库也OK, 就当1秒联网吧
+        sys.timerStart(sys.publish, 1000, "IP_READY")
+    else
+        -- 其他不认识的bsp, 循环提示一下吧
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp可能未适配网络层, 请查证")
+        end
+    end
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready")
+end)
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(1000)
+        log.info("fota", "version", VERSION)
+    end
+end)
+
+
+function fota_cb(ret)
+    log.info("fota", ret)
+    if ret == 0 then
+        rtos.reboot()
+    end
+end
+
+--支持外部flash全量更新的固件,可以打开下面的注释,做全量更新,外部flash挂载在SPI0,使用GPIO27控制上下电
+--spi_flash = spi.deviceSetup(0,8,0,0,8,44*1000*1000,spi.MSB,1,0)
+--fota.init(0xe0000000, nil, spi_flash, 27)	--GPIO27控制上下电
+
+-- 使用合宙iot平台进行升级
+sys.taskInit(function()
+    sys.waitUntil("net_ready")
+    libfota.request(fota_cb)
+end)
+sys.timerLoopStart(libfota.request, 3600000, fota_cb)
+
+-- 使用自建服务器进行升级
+-- local ota_url = "http://192.168.1.5:8000/demo.fota"
+-- local ota_url = "http://192.168.1.5:8000/demo.fota"
+-- sys.taskInit(function()
+--     sys.waitUntil("net_ready")
+--     sys.wait(3000)
+--     libfota.request(fota_cb, ota_url)
+--     -- 按键触发
+--     -- sys.wait(1000)
+--     -- gpio.setup(0, function()
+--     --     log.info("sayhi")
+--     -- end, gpio.PULLUP)
+-- end)
+-- sys.timerLoopStart(libfota.request, 3600000, fota_cb, ota_url)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 98 - 0
module/Air780E/demo/fota2/main.lua

@@ -0,0 +1,98 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fotademo"
+-- iot限制,只能上传xxx.yyy.zzz格式的三位数的版本号,但实际上现在只用了XXX和ZZZ,中间yyy暂未使用
+-- 需要注意的是,因为yyy不生效,所以111.222.333版本和111.444.333版本,对iot平台来说都一样,所以建议中间那一位永远写000
+VERSION = "001.000.000"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "123" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+sys = require "sys"
+libfota2 = require "libfota2"
+
+-- 联网函数, 可自行删减
+sys.taskInit(function()
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    log.info("4G网络链接成功")
+    sys.publish("net_ready")
+end)
+
+-- 循环打印版本号, 方便看版本号变化, 非必须
+sys.taskInit(function()
+    while 1 do
+        sys.wait(5000)
+        log.info("降功耗 找合宙")
+        -- log.info("fota", "脚本版本号", VERSION)
+        log.info("fota", "脚本版本号", VERSION, "core版本号", rtos.version())
+    end
+end)
+
+-- 升级结果的回调函数
+-- 功能:获取fota的回调函数
+-- 参数:
+-- result:number类型
+--   0表示成功
+--   1表示连接失败
+--   2表示url错误
+--   3表示服务器断开
+--   4表示接收报文错误
+--   5表示使用iot平台VERSION需要使用 xxx.yyy.zzz形式
+local function fota_cb(ret)
+    log.info("fota", ret)
+    if ret == 0 then
+        log.info("升级包下载成功,重启模块")
+        rtos.reboot()
+    elseif ret == 1 then
+        log.info("连接失败", "请检查url拼写或服务器配置(是否为内网)")
+    elseif ret == 2 then
+        log.info("url错误", "检查url拼写")
+    elseif ret == 3 then
+        log.info("服务器断开", "检查服务器白名单配置")
+    elseif ret == 4 then
+        log.info("接收报文错误", "检查模块固件或升级包内文件是否正常")
+    elseif ret == 5 then
+        log.info("版本号书写错误", "iot平台版本号需要使用xxx.yyy.zzz形式")
+    else
+        log.info("不是上面几种情况 ret为", ret)
+    end
+end
+
+-- 使用合宙iot平台进行升级,不需要管下面这段代码
+-- 使用第三方服务器时打开下面这段代码
+--[[local ota_opts = {
+    url = "", 
+    -- 合宙IOT平台的默认升级URL, 不填就是这个默认值
+    -- 如果是自建的OTA服务器, 则需要填写正确的URL, 例如 http://192.168.1.5:8000/update
+    -- 如果自建OTA服务器,且url包含全部参数,不需要额外添加参数, 请在url前面添加 ### 
+    -- 如果不加###,则默认会上传如下参数
+    -- 1. opts.version string 版本号, 默认是 BSP版本号.x.z格式
+    -- 2. opts.timeout int 请求超时时间, 默认300000毫秒,单位毫秒
+    -- 3. opts.project_key string 合宙IOT平台的项目key, 默认取全局变量PRODUCT_KEY. 自建服务器不用填
+    -- 4. opts.imei string 设备识别码, 默认取IMEI(Cat.1模块)或WLAN MAC地址(wifi模块)或MCU唯一ID
+    -- 5. opts.firmware_name string 底层版本号
+    -- 请求的版本号, 合宙IOT有一套版本号体系,不传就是合宙规则, 自建服务器的话当然是自行约定版本号了
+    version = ""
+    -- 其他更多参数, 请查阅libfota2的文档 https://wiki.luatos.com/api/libs/libfota2.html
+}]]--
+sys.taskInit(function()
+    -- 这个判断是提醒要设置PRODUCT_KEY的,实际生产请删除
+    if "123" == _G.PRODUCT_KEY and not ota_opts.url then
+        while 1 do
+            sys.wait(1000)
+            log.info("fota", "请修改正确的PRODUCT_KEY")
+        end
+    end
+    -- 等待网络就行后开始检查升级
+    sys.waitUntil("net_ready")
+    log.info("开始检查升级")
+    sys.wait(500)
+    libfota2.request(fota_cb, ota_opts)
+end)
+-- 演示定时自动升级, 每隔4小时自动检查一次
+sys.timerLoopStart(libfota2.request, 4 * 3600000, fota_cb, ota_opts)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

BIN
module/Air780E/demo/fota_uart/fota_uart.bin


+ 134 - 0
module/Air780E/demo/fota_uart/main.lua

@@ -0,0 +1,134 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fotademo"
+VERSION = "1.0.0"
+
+--[[
+演示用uart进行固件升级
+
+1. 需要 V1107及以上的固件
+2. 需要 LuaTools 2.1.89 及以上的升级文件生成
+
+目录内文件的说明
+1. main.lua 本文件, 是下载到模块的唯一文件
+2. fota_uart.bin 演示用的脚本升级文件,不需要下载到模块
+3. main.py 上位机发送升级包的程序, 不需要下载到模块
+
+fota_uart.bin 使用 LuaTools 的 "量产文件" 按钮进行生成, .bin后缀的就是脚本OTA文件
+
+用法:
+1. 先把脚本和固件烧录到模块里, 并确认开机
+2. 进入命令行程序, 执行 python main.py 升级
+3. 观察luatools的输出和main.py的输出
+4. 模块接收正确的升级数据后,会提示1秒后重启
+5. 本demo自带的脚本升级包,升级后是GPIO闪灯的demo
+
+注意: 本demo默认是走虚拟串口进行交互, 如需改成物理串口, 修改uart_id和main.py
+]]
+
+_G.sys = require "sys"
+
+-- 定义所需要的UART编号
+-- uart_id = 1    -- 物理UART1, 通常也是MAIN_UART
+uart_id = uart.VUART_0 -- 虚拟USB串口
+
+-- 循环打印当前版本, 从而直观表示是否升级成功
+-- sys.taskInit(function()
+--     while 1 do
+--         sys.wait(3000)
+--         log.info("fota", "version", VERSION)
+--     end
+-- end)
+
+-- 开始初始化uart
+uart_zbuff = zbuff.create(1024)
+uart.setup(uart_id, 115200)
+
+-- 几个状态变量, 调试用
+local uart_fota_state = 0
+local uart_rx_counter = 0
+local uart_fota_writed = 0
+uart.on(uart_id, "receive", function(id, len)
+    -- 防御缓冲区超标的情况
+    if uart_zbuff:used() > 8192 then
+        log.warn("fota", "uart_zbuff待处理的数据太多了,强制清空")
+        uart_zbuff:del()
+    end
+    while 1 do
+        local len = uart.rx(id, uart_zbuff)
+        if len <= 0 then
+            break
+        end
+        -- if #s > 0 then -- #s 是取字符串的长度
+        uart_rx_counter = uart_rx_counter + len
+        log.info("uart", "收到数据", len, "累计", uart_rx_counter)
+        if uart_fota_state == 0 then
+            sys.publish("UART_FOTA")
+        end
+    end
+end)
+
+sys.taskInit(function()
+    local fota_state = 0 -- 0还没开始, 1进行中
+    while 1 do
+        -- 等待升级数据到来
+        sys.waitUntil("UART_FOTA", 1000)
+        local used = uart_zbuff:used()
+        if used > 0 then
+            if fota_state == 0 then
+                -- 等待FOTA的状态
+                if used > 5 then
+                    local data = uart_zbuff:query()
+                    uart_zbuff:del()
+                    -- 如果接受到 #FOTA\n 代表数据要来了
+                    if data:startsWith("#FOTA") and data:endsWith("\n") then
+                        fota_state = 1
+                        log.info("fota", "检测到fota起始标记,进入FOTA状态", data)
+                        fota.init()
+                        -- 固件数据发送端应该在收到#FOTA RDY\n之后才开始发送数据
+                        uart.write(uart_id, "#FOTA RDY\n")
+                    end
+                end
+            else
+                uart_fota_writed = uart_fota_writed + used
+                log.info("准备写入fota包", used, "累计写入", uart_fota_writed)
+                local result, isDone, cache = fota.run(uart_zbuff)
+                log.debug("fota.run", result, isDone, cache)
+                uart_zbuff:del() -- 清空缓冲区
+                if not result then
+                    fota_state = 0
+                    fota.isDone()
+                    uart.write(uart_id, "#FOTA ERR\n")
+                    log.info("fota", "出错了", result, isDone, cache)
+                elseif isDone then
+                    while true do
+                        sys.wait(100)
+                        local succ, fotaDone = fota.isDone()
+                        if not succ then
+                            fota_state = 0
+                            uart.write(uart_id, "#FOTA ERR\n")
+                            log.info("fota", "出错了")
+                            break
+                        end
+                        if fotaDone then
+                            uart_fota_state = 1
+                            log.info("fota", "已完成,1s后重启")
+                            -- 反馈给上位机
+                            uart.write(uart_id, "#FOTA OK\n")
+                            sys.wait(1000)
+                            rtos.reboot()
+                        end
+                        sys.wait(100)
+                    end
+                else
+                    log.info("fota", "单包写入完成", used, "等待下一个包")
+                    uart.write(uart_id, "#FOTA NEXT\n")
+                end
+            end
+        end
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 34 - 0
module/Air780E/demo/fota_uart/main.py

@@ -0,0 +1,34 @@
+#!/usr/bin/python3
+# -*- coding: UTF-8 -*-
+
+import os, sys, serial.tools.list_ports, time
+
+
+for item in serial.tools.list_ports.comports():
+    if not item.pid or not item.location :
+        continue
+    if item.vid == 0x19d1 and item.pid == 0x0001 and "x.6" in item.location :
+        print(dir(item))
+        print(item.name)
+        with serial.Serial(item.name, 115200, timeout=1) as ser:
+            while 1:
+                ser.write(b"#FOTA\n")
+                data = ser.read(128)
+                if data and data.startswith(b"#FOTA") :
+                    print("设备响应", data)
+                    with open("fota_uart.bin", "rb") as f :
+                        while 1 :
+                            fdata = f.read(256)
+                            if not fdata :
+                                print("发送完毕,退出")
+                                sys.exit(0)
+                            print("发送升级包数据", len(fdata))
+                            ser.write(fdata)
+                            data = ser.read(128)
+                            if data :
+                                print("设备响应", data)
+                else :
+                    print("设备没响应", data)
+                break
+
+

+ 3 - 0
module/Air780E/demo/fs/abc.txt

@@ -0,0 +1,3 @@
+ABC
+DEF
+XYZ

+ 124 - 0
module/Air780E/demo/fs/main.lua

@@ -0,0 +1,124 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fsdemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+local function fs_test()
+    -- 根目录/是可写
+    local f = io.open("/boot_time", "rb")
+    local c = 0
+    if f then
+        local data = f:read("*a")
+        log.info("fs", "data", data, data:toHex())
+        c = tonumber(data)
+        f:close()
+    end
+    log.info("fs", "boot count", c)
+    c = c + 1
+    f = io.open("/boot_time", "wb")
+    --if f ~= nil then
+    log.info("fs", "write c to file", c, tostring(c))
+    f:write(tostring(c))
+    f:close()
+    --end
+
+    log.info("io.writeFile", io.writeFile("/abc.txt", "ABCDEFG"))
+
+    log.info("io.readFile", io.readFile("/abc.txt"))
+    local f = io.open("/abc.txt", "rb")
+    local c = 0
+    if f then
+        local data = f:read("*a")
+        log.info("fs", "data2", data, data:toHex())
+        f:close()
+    end
+
+    -- seek和tell测试
+    local f = io.open("/abc.txt", "rb")
+    local c = 0
+    if f then
+        f:seek("end", 0)
+        f:seek("set", 0)
+        local data = f:read("*a")
+        log.info("fs", "data3", data, data:toHex())
+        f:close()
+    end
+
+    if fs then
+        -- 根目录是可读写的
+        log.info("fsstat", fs.fsstat("/"))
+        -- /luadb/ 是只读的
+        log.info("fsstat", fs.fsstat("/luadb/"))
+    end
+
+    local ret, files = io.lsdir("/")
+    log.info("fs", "lsdir", json.encode(files))
+
+    ret, files = io.lsdir("/luadb/")
+    log.info("fs", "lsdir", json.encode(files))
+
+    -- 读取刷机时加入的文件, 并演示按行读取
+    -- 刷机时选取的非lua文件, 均存放在/luadb/目录下, 单层无子文件夹
+    f = io.open("/luadb/abc.txt", "rb")
+    if f then
+        while true do
+            local line = f:read("l")
+            if not line or #line == 0 then
+                break
+            end
+            log.info("fs", "read line", line)
+        end
+        f:close()
+        log.info("fs", "close f")
+    else
+        log.info("fs", "pls add abc.txt!!")
+    end
+
+    -- 文件夹操作
+    sys.wait(3000)
+    io.mkdir("/iot/")
+    f = io.open("/iot/1.txt", "w+")
+    if f then
+        f:write("hi, LuatOS " .. os.date())
+        f:close()
+    else
+        log.info("fs", "open file for write failed")
+    end
+    f = io.open("/iot/1.txt", "r")
+    if f then
+        local data = f:read("*a")
+        f:close()
+        log.info("fs", "writed data", data)
+    else
+        log.info("fs", "open file for read failed")
+    end
+
+    -- 2023.6.6 新增 io.readFile支持配置起始位置和长度
+    io.writeFile("/test.txt", "0123456789")
+    log.info("stream", io.readFile("/test.txt", "rb", 3, 5))
+end
+
+
+
+sys.taskInit(function()
+    -- 为了显示日志,这里特意延迟一秒
+    -- 正常使用不需要delay
+    sys.wait(1000)
+    fs_test()
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 105 - 0
module/Air780E/demo/fskv/main.lua

@@ -0,0 +1,105 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "fskvdemo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+sys.taskInit(function()
+    sys.wait(1000) -- 免得日志刷没了, 生产环境不需要
+
+    -- 检查一下当前固件是否支持fskv
+    if not fskv then
+        while true do
+            log.info("fskv", "this demo need fskv")
+            sys.wait(1000)
+        end
+    end
+
+    -- 初始化kv数据库
+    fskv.init()
+    log.info("fskv", "init complete")
+    -- 先放入一堆值
+    local bootime = fskv.get("boottime")
+    if bootime == nil or type(bootime) ~= "number" then
+        bootime = 0
+    else
+        bootime = bootime + 1
+    end
+    fskv.set("boottime", bootime)
+
+    fskv.set("my_bool", true)
+    fskv.set("my_int", 123)
+    fskv.set("my_number", 1.23)
+    fskv.set("my_str", "luatos")
+    fskv.set("my_table", {name="wendal",age=18})
+    
+    fskv.set("my_str_int", "123")
+    fskv.set("1", "123") -- 单字节key
+    --fskv.set("my_nil", nil) -- 会提示失败,不支持空值
+
+
+    log.info("fskv", "boottime",      type(fskv.get("boottime")),    fskv.get("boottime"))
+    log.info("fskv", "my_bool",      type(fskv.get("my_bool")),    fskv.get("my_bool"))
+    log.info("fskv", "my_int",       type(fskv.get("my_int")),     fskv.get("my_int"))
+    log.info("fskv", "my_number",    type(fskv.get("my_number")),  fskv.get("my_number"))
+    log.info("fskv", "my_str",       type(fskv.get("my_str")),     fskv.get("my_str"))
+    log.info("fskv", "my_table",     type(fskv.get("my_table")),   json.encode(fskv.get("my_table")))
+    log.info("fskv", "my_str_int",     type(fskv.get("my_str_int")),   fskv.get("my_str_int"))
+    log.info("fskv", "1 byte key",     type(fskv.get("1")),   json.encode(fskv.get("1")))
+
+    -- 删除测试
+    fskv.del("my_bool")
+    local t = fskv.get("my_bool")
+    log.info("fskv", "my_bool",      type(t),    t)
+
+    -- 查询kv数据库状态
+    -- local used, total,kv_count = fskv.stat()
+    -- log.info("fdb", "kv", used,total,kv_count)
+
+    -- fskv.clr()
+    -- local used, total,kv_count = fskv.stat()
+    -- log.info("fdb", "kv", used,total,kv_count)
+    
+
+    -- 压力测试
+    -- local start = mcu.ticks()
+    -- local count = 1000
+    -- for i=1,count do
+    --     -- sys.wait(10)
+    --     -- count = count - 1
+    --     -- fskv.set("BENT1", "--" .. os.date() .. "--")
+    --     -- fskv.set("BENT2", "--" .. os.date() .. "--")
+    --     -- fskv.set("BENT3", "--" .. os.date() .. "--")
+    --     -- fskv.set("BENT4", "--" .. os.date() .. "--")
+    --     fskv.get("my_bool")
+    -- end
+    -- log.info("fskv", mcu.ticks() - start)
+
+    if fskv.sett then
+        -- 设置数据, 字符串,数值,table,布尔值,均可
+        -- 但不可以是nil, function, userdata, task
+        log.info("fdb", fskv.sett("mytable", "wendal", "goodgoodstudy"))
+        log.info("fdb", fskv.sett("mytable", "upgrade", true))
+        log.info("fdb", fskv.sett("mytable", "timer", 1))
+        log.info("fdb", fskv.sett("mytable", "bigd", {name="wendal",age=123}))
+        
+        -- 下列语句将打印出4个元素的table
+        log.info("fdb", fskv.get("mytable"), json.encode(fskv.get("mytable")))
+        -- 注意: 如果key不存在, 或者原本的值不是table类型,将会完全覆盖
+        -- 例如下列写法,最终获取到的是table,而非第一行的字符串
+        log.info("fdb", fskv.set("mykv", "123"))
+        log.info("fdb", fskv.sett("mykv", "age", "123")) -- 保存的将是 {age:"123"}
+
+        -- 删除测试
+        log.info("fdb", fskv.set("mytable", {age=18, name="wendal"}))
+        log.info("fdb", fskv.sett("mytable", "name", nil))
+        log.info("fdb", fskv.get("mytable"), json.encode(fskv.get("mytable")))
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 92 - 0
module/Air780E/demo/ftp/main.lua

@@ -0,0 +1,92 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ftpdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要ftp库, 大部分能联网的设备都具有这个库
+ftp也是内置库, 无需require
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用ftp库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        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()
+        -- TODO 获取mac地址作为device_id
+    elseif mobile then
+        -- Air780E/Air600E系列
+        --mobile.simid(2)
+        -- LED = gpio.setup(27, 0, gpio.PULLUP)
+        device_id = mobile.imei()
+        sys.waitUntil("IP_READY", 30000)
+    end
+
+    -- -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
+    -- if crypto.cipher_suites then
+    --     log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
+    -- end
+    while true do
+        sys.wait(1000)
+        log.info("ftp 启动")
+        print(ftp.login(nil,"121.43.224.154",21,"ftp_user","3QujbiMG").wait())
+    
+        print(ftp.command("NOOP").wait())
+        print(ftp.command("SYST").wait())
+
+        print(ftp.command("TYPE I").wait())
+        print(ftp.command("PWD").wait())
+        print(ftp.command("MKD QWER").wait())
+        print(ftp.command("CWD /QWER").wait())
+
+        print(ftp.command("CDUP").wait())
+        print(ftp.command("RMD QWER").wait())
+
+        print(ftp.command("LIST").wait())
+
+        -- io.writeFile("/1222.txt", "23noianfdiasfhnpqw39fhawe;fuibnnpw3fheaios;fna;osfhisao;fadsfl")
+        -- print(ftp.push("/1222.txt","/12222.txt").wait())
+        
+        print(ftp.pull("/122224.txt","/122224.txt").wait())
+
+        local f = io.open("/122224.txt", "r")
+        if f then
+            local data = f:read("*a")
+            f:close()
+            log.info("fs", "writed data", data)
+        else
+            log.info("fs", "open file for read failed")
+        end
+
+        print(ftp.command("DELE /12222.txt").wait())
+        print(ftp.push("/122224.txt","/12222.txt").wait())
+        print(ftp.close().wait())
+        log.info("meminfo", rtos.meminfo("sys"))
+        sys.wait(15000)
+    end
+
+
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 134 - 0
module/Air780E/demo/gmssl/main.lua

@@ -0,0 +1,134 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gmssldemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+
+    sys.wait(1000)
+    log.info("gmssl", "start")
+    -- 未加密字符串
+    local originStr = "!!from LuatOS!!"
+
+    -- SM2 , 非对称加密, 类似于RSA,但属于椭圆算法
+    -- 就当前实现还是比较慢的
+    if gmssl.sm2encrypt then -- 部分BSP不支持
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+
+        -- GMSSL默认格式
+        log.info("==== SM2 默认GMSSL模式")
+        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr)
+        log.info("sm2默认模式", "加密后", encodeStr and  string.toHex(encodeStr))
+        if encodeStr then
+            log.info("sm2默认模式", "解密后", gmssl.sm2decrypt(private,encodeStr))
+        end
+        
+
+        -- 网站兼容模式 https://i.goto327.top/CryptTools/SM2.aspx
+        -- 密文格式 C1C3C2, 新国标, 一般是这种
+        log.info("==== SM2 网站兼容模式")
+        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true)
+        log.info("sm2网站兼容模式 C1C3C2", "加密后", encodeStr and  string.toHex(encodeStr))
+        if encodeStr then
+            log.info("sm2网站兼容模式 C1C3C2", "解密后", gmssl.sm2decrypt(private,encodeStr, true))
+        else
+            log.info("解密失败")
+        end
+        -- 密文格式 C1C2C3, 老国标, 老的Java库通常支持这种
+        log.info("==== SM2 网站兼容模式, 但C1C2C3")
+        local encodeStr = gmssl.sm2encrypt(pkx,pky,originStr, true, true)
+        log.info("sm2网站兼容模式 C1C2C3", "加密后", encodeStr and  string.toHex(encodeStr))
+        if encodeStr then
+            log.info("sm2网站兼容模式 C1C2C3", "解密后", gmssl.sm2decrypt(private,encodeStr, true, true))
+        else
+            log.info("解密失败")
+        end
+    end
+
+    -- SM3 算法, hash类
+    if gmssl.sm3update then
+        log.info("=== SM3测试")
+        encodeStr = gmssl.sm3update("lqlq666lqlq946")
+        log.info("gmssl.sm3update",string.toHex(encodeStr))
+    end
+
+    if gmssl.sm4encrypt then
+        log.info("=== SM4测试")
+        local passwd = "1234567890123456"
+        local iv = "1234567890666666"
+        -- SM4 算法, 对称加密
+        originStr = ">>SM4 ECB ZeroPadding test<<"
+        --加密模式:ECB;填充方式:ZeroPadding;密钥:1234567890123456;密钥长度:128 bit
+        encodeStr = gmssl.sm4encrypt("ECB", "ZERO", originStr, passwd)
+        log.info("sm4.ecb.zero", "加密后", string.toHex(encodeStr))
+        log.info("sm4.ecb.zero", "解密后", gmssl.sm4decrypt("ECB","ZERO",encodeStr,passwd))
+
+        originStr = ">>SM4 ECB Pkcs5Padding test<<"
+        --加密模式:ECB;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit
+        encodeStr = gmssl.sm4encrypt("ECB", "PKCS5", originStr, passwd)
+        log.info("sm4.ecb.pks5", "加密后", string.toHex(encodeStr))
+        log.info("sm4.ecb.pks5", "解密后", gmssl.sm4decrypt("ECB","PKCS5",encodeStr,passwd))
+
+        originStr = ">>SM4 CBC Pkcs5Padding test<<"
+        --加密模式:CBC;填充方式:Pkcs5Padding;密钥:1234567890123456;密钥长度:128 bit;偏移量:1234567890666666
+        encodeStr = gmssl.sm4encrypt("CBC","PKCS5", originStr, passwd, iv)
+        log.info("sm4.cbc.pks5", "加密后", string.toHex(encodeStr))
+        log.info("sm4.cbc.pks5", "解密后", gmssl.sm4decrypt("CBC","PKCS5",encodeStr,passwd, iv))
+
+        -- 完全对齐16字节的对比测试
+        originStr = "1234567890123456"
+        encodeStr = gmssl.sm4encrypt("ECB","PKCS7",originStr,passwd)
+        log.info("sm4.ecb.pkcs7", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","PKCS5",originStr,passwd)
+        log.info("sm4.ecb.pkcs5", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","ZERO",originStr,passwd)
+        log.info("sm4.ecb.zero", encodeStr:toHex())
+        encodeStr = gmssl.sm4encrypt("ECB","NONE",originStr,passwd)
+        log.info("sm4.ecb.none", encodeStr:toHex())
+    end
+
+    -- SM2签名和验签
+    if gmssl.sm2sign then
+        local originStr = string.fromHex("434477813974bf58f94bcf760833c2b40f77a5fc360485b0b9ed1bd9682edb45")
+        local pkx = "ABE87C924B7ECFDEA1748A06E89003C9F7F4DC5C3563873CE2CAE46F66DE8141"
+        local pky = "9514733D38CC026F2452A6A3A3A4DA0C28F864AFA5FE2C45E0EB6B761FBB5286"
+        local private = "129EDC282CD2E9C1144C2E7315F926D772BC96600D2771E8BE02060313FE00D5"
+
+        -- 不带id的情况,即默认id="1234567812345678"
+        local sig = gmssl.sm2sign(private, originStr, nil)
+        log.info("sm2sign", sig and sig:toHex())
+        if sig then
+            local ret = gmssl.sm2verify(pkx, pky, originStr, nil, sig)
+            log.info("sm2verify", ret or "false")
+        end
+
+        -- 带id的情况
+        local id = "1234"
+        local sig = gmssl.sm2sign(private, originStr, id)
+        log.info("sm2sign", sig and sig:toHex())
+        if sig then
+            local ret = gmssl.sm2verify(pkx, pky, originStr, id, sig)
+            log.info("sm2verify", ret or "false")
+        end
+    end
+
+    log.info("gmssl", "ALL Done")
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 35 - 0
module/Air780E/demo/gpio/AGPIO/main.lua

@@ -0,0 +1,35 @@
+-- 本示例对比了普通GPIO和AGPIO的进入休眠模式前后的区别。
+-- Luatools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+local gpio_number = 11 -- 普通GPIO GPIO号为8,休眠后掉电
+local Agpio_number = 27 -- AGPIO GPIO号为27,也是核心板上的绿灯,休眠后可保持电平(休眠后绿灯常亮)
+
+gpio.setup(gpio_number, 1)
+gpio.setup(Agpio_number, 1)
+
+sys.taskInit(function()
+    sys.wait(8000)
+    -- 关闭USB电源
+    -- pm.power(pm.USB, false)
+    -- 进入低功耗模式
+    pm.power(pm.WORK_MODE, 3)
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 39 - 0
module/Air780E/demo/gpio/GPIO上拉下拉模式/main.lua

@@ -0,0 +1,39 @@
+-- Luatools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+--配置gpio27为中断下拉模式
+--配置gpio24为中断下拉模式
+--请根据实际需求更改gpio编号和上下拉
+local gpio_pin1 = 7
+local gpio_pin2 = 27
+-- 按键防抖函数
+gpio.debounce(gpio_pin1, 50)
+gpio.debounce(gpio_pin2, 50)
+
+-- 设置GPIO7引脚为上拉输入模式
+gpio.setup(gpio_pin1, nil, gpio.PULLUP)
+
+-- 设置GPIO27引脚为下拉输入模式
+gpio.setup(gpio_pin2, nil, gpio.PULLDOWN)
+
+
+sys.timerLoopStart(function ()
+    log.info("GPIO",gpio_pin1,"电平",gpio.get(gpio_pin1))
+    log.info("GPIO",gpio_pin2,"电平",gpio.get(gpio_pin2))
+end,1000)
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 27 - 0
module/Air780E/demo/gpio/GPIO中断(触发)模式/main.lua

@@ -0,0 +1,27 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio_irq"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- 配置gpio24为中断模式,上升沿(gpio.RISING)和下降沿(gpio.FALLING)均触发(gpio.BOTH)
+-- 请根据实际需求更改gpio编号和触发模式
+local gpio_pin = 24
+gpio.debounce(gpio_pin, 100)
+gpio.setup(gpio_pin, function()
+    log.info("gpio", gpio_pin, "被触发")
+end, gpio.PULLUP, gpio.BOTH)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 33 - 0
module/Air780E/demo/gpio/GPIO中断(计数)模式/main.lua

@@ -0,0 +1,33 @@
+-- Luatools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+--配置gpio24为中断计数模式
+--请根据实际需求更改gpio编号和上下拉
+local gpio_pin = 24
+gpio.setup(gpio_pin, gpio.count, gpio.PULLUP, gpio.FALLING)
+
+--配置PWM4输出 2KHZ 占空比50%的方波作为信号源
+pwm.open(4,2000,50) 
+
+--每隔1S统计一次中断触发的次数
+sys.taskInit(function()
+    while true do
+        sys.wait(999)
+        log.info("irq cnt", gpio.count(gpio_pin))
+    end
+end)
+
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 39 - 0
module/Air780E/demo/gpio/GPIO翻转测速/main.lua

@@ -0,0 +1,39 @@
+-- Luatools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+local test_gpio_number = 27
+
+gpio.setup(test_gpio_number, 0, gpio.PULLUP)
+
+sys.taskInit(function()
+    sys.wait(100)
+    while true do
+        sys.wait(100)
+        -- 通过GPIO27脚输出输出8组电平变化
+        -- 0xA9就是输出的电平高低状态,即 0000000010101001
+        gpio.pulse(test_gpio_number, 0xA9, 8, 0)
+        log.info("gpio----------->pulse2")
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 41 - 0
module/Air780E/demo/gpio/GPIO输入模式/main.lua

@@ -0,0 +1,41 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio_irq"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- 配置gpio24为输入模式
+-- 配置GPIO27(即开发板上LED灯)为输出模式
+
+-- 请根据实际需求更改gpio编号和上下拉
+
+local inputpin = 24
+local ledpin = 27
+
+local input = gpio.setup(inputpin,nil)
+local led = gpio.setup(ledpin, 1)
+
+gpio.debounce(inputpin, 50)
+--GPIO24检测到有高低电平输入后,会返回GPIO24当前获取到的电平为高还是低,高返回值为1,低返回值为0
+--将这个返回值,传给GPIO27(LED),为0 则GPIO27输出低电平(LED灯灭),为1则输出高电平(LED灯亮)
+sys.taskInit(function ()
+    while true do
+        led(input())
+        sys.wait(500)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 42 - 0
module/Air780E/demo/gpio/GPIO输出模式/main.lua

@@ -0,0 +1,42 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpiodemo"
+VERSION = "1.0.1"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+local gpio_number = 27
+
+LED = gpio.setup(gpio_number, 1)
+
+sys.taskInit(function()
+    -- 开始呼吸灯
+    local count = 0
+    while 1 do
+        -- 呼吸灯程序
+        LED(1)
+        log.info("GPIO", "Go Go Go", count, rtos.bsp())
+        sys.wait(500)--点亮时间 500ms
+        LED(0)
+        sys.wait(500)--熄灭时间 500ms
+        count = count + 1
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 0 - 0
module/Air780E/demo/gpio/IO复用/main.lua


+ 43 - 0
module/Air780E/demo/gpio/gpio/main.lua

@@ -0,0 +1,43 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpiodemo"
+VERSION = "1.0.1"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+local gpio_number = 27
+
+LED = gpio.setup(gpio_number, 1)
+
+sys.taskInit(function()
+    -- 开始流水灯
+    local count = 0
+    while 1 do
+        -- 流水灯程序
+        LED(1)
+        log.info("GPIO", "Go Go Go", count, rtos.bsp())
+        sys.wait(500)--点亮时间 500ms
+        LED(0)
+        sys.wait(500)--熄灭时间 500ms
+        count = count + 1
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 64 - 0
module/Air780E/demo/gpio/gpio_button/main.lua

@@ -0,0 +1,64 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+local button_timer_outtime = 10 --按键定时器: 10ms
+local button_shake_time = 1     --按键消抖时间: button_shake_time*button_timer_outtime
+local button_long_time = 100    --按键长按时间: button_shake_time*button_timer_outtime
+
+local button_detect = true
+local button_state = false
+local button_cont = 0
+
+local BTN_PIN = 1 -- 按实际开发板选取
+
+-- 若固件支持防抖, 启用防抖
+if gpio.debounce then
+    gpio.debounce(BTN_PIN, 5)
+end
+
+button = gpio.setup(BTN_PIN, function() 
+        if not button_detect then return end
+        button_detect = false
+        button_state = true
+    end, 
+    gpio.PULLUP,
+    gpio.FALLING)
+
+button_timer = sys.timerLoopStart(function()
+    if button_state then
+        if button() == 0 then
+            button_cont = button_cont + 1
+            if button_cont > button_long_time then
+                print("long pass")
+            end
+        else 
+            if button_cont < button_shake_time then
+            else
+                if button_cont < button_long_time then
+                    print("pass")
+                else
+                    print("long pass")
+                end
+            end
+            button_cont = 0
+            button_state = false
+            button_detect = true
+        end
+    end
+end,button_timer_outtime) 
+
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 31 - 0
module/Air780E/demo/gpio/gpio_count_irq/main.lua

@@ -0,0 +1,31 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio2demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+--配置gpio7为输入模式,下拉,并会触发中断
+--请根据实际需求更改gpio编号和上下拉
+local gpio_pin = 7
+gpio.setup(gpio_pin, gpio.count, gpio.PULLUP, gpio.FALLING)
+pwm.open(1,2000,50) --2k 50%占空比作为触发源
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.taskInit(function()
+    while true do
+        sys.wait(999)
+        log.info("irq cnt", gpio.count(gpio_pin))
+    end
+end)
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 41 - 0
module/Air780E/demo/gpio/gpio_irq/main.lua

@@ -0,0 +1,41 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "gpio_irq"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+if wdt then
+    -- 添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+-- 配置gpio24为输入模式
+-- 配置GPIO27(即开发板上LED灯)为输出模式
+
+-- 请根据实际需求更改gpio编号和上下拉
+
+local inputpin = 24
+local ledpin = 27
+
+local input = gpio.setup(inputpin,nil)
+local led = gpio.setup(ledpin, 1)
+
+gpio.debounce(inputpin, 50)
+--GPIO24检测到有高低电平输入后,会返回GPIO24当前获取到的电平为高还是低,高返回值为1,低返回值为0
+--将这个返回值,传给GPIO27(LED),为0 则GPIO27输出低电平(LED灯灭),为1则输出高电平(LED灯亮)
+sys.taskInit(function ()
+    while true do
+        led(input())
+        sys.wait(500)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 31 - 0
module/Air780E/demo/gpio/powerkey/main.lua

@@ -0,0 +1,31 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "pwrkey_demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+local function pinx()
+    -- AIR780E                          -- 35是虚拟GPIO,见https://wiki.luatos.com/chips/air780e/iomux.html#id1
+    return 35
+end
+
+
+local powerkey_pin = pinx()                                         -- 赋值powerkey引脚编号
+
+if powerkey_pin ~= 255 then
+    gpio.setup(powerkey_pin, function() 
+        log.info("pwrkey", gpio.get(powerkey_pin))
+    end, gpio.PULLUP)
+else
+    log.info("bsp not support")
+end
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 35 - 0
module/Air780E/demo/gpio/usbconnect/main.lua

@@ -0,0 +1,35 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "usb_connect_demo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+local function pinx()
+    -- AIR780E                          -- 33是虚拟GPIO,见https://wiki.luatos.com/chips/air780e/iomux.html#id1
+    return 24, 33
+end
+
+
+local led_pin, vbus_pin = pinx()                                    -- 赋值led,vbus引脚编号
+
+if led_pin ~= 255 and vbus_pin ~= 255 then
+    local led = gpio.setup(led_pin, 1) --如果真的把USB拔出,可能无法打印出信息,所以拿个IO输出和USB一样状态的电平
+    led(gpio.get(vbus_pin)) --IO输出和USB一样的状态
+    gpio.setup(vbus_pin, function() 
+        log.info("usb", gpio.get(vbus_pin))
+        led(gpio.get(vbus_pin))   --IO输出和USB一样的状态
+    end, gpio.PULLUP, gpio.BOTH)
+    gpio.debounce(vbus_pin, 500, 1)  --加入消抖是为了尽量能看到输出
+    log.info("usb", gpio.get(vbus_pin))
+else
+    log.info("bsp not support") 
+end
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 46 - 0
module/Air780E/demo/gtfont/main.lua

@@ -0,0 +1,46 @@
+--- 模块功能:lcddemo
+-- @module lcd
+-- @author Dozingfiretruck
+-- @release 2021.01.25
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lcddemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--添加硬狗防止程序卡死
+wdt.init(9000)--初始化watchdog设置为9s
+sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+
+-- spi_id,pin_reset,pin_dc,pin_cs,bl
+function lcd_pin()
+    return 0,1,10,8,22
+end
+
+local spi_id,pin_reset,pin_dc,pin_cs,bl = lcd_pin() 
+
+spi_gtfont = spi.deviceSetup(1,7,0,0,8,20*1000*1000,spi.MSB,1,0) --此处根据自己实际接线修改
+
+if spi_id ~= lcd.HWID_0 then
+    spi_lcd = spi.deviceSetup(spi_id,pin_cs,0,0,8,20*1000*1000,spi.MSB,1,0)
+    port = "device"
+else
+    port = spi_id
+end
+
+
+lcd.init("st7789",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 240,h = 320,xoffset = 0,yoffset = 0},spi_lcd)
+
+gtfont.init(spi_gtfont)
+lcd.drawGtfontUtf8("啊啊啊",32,0,0)
+lcd.drawGtfontUtf8Gray("啊啊啊",32,4,0,40)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 23 - 0
module/Air780E/demo/hello_world/main.lua

@@ -0,0 +1,23 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "helloworld"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+log.info("main", "hello world")
+
+print(_VERSION)
+
+sys.timerLoopStart(function()
+    print("hi, LuatOS")
+    print("mem.lua", rtos.meminfo())
+    print("mem.sys", rtos.meminfo("sys"))
+end, 3000)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 30 - 0
module/Air780E/demo/hmeta/main.lua

@@ -0,0 +1,30 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "hmetademo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+sys.taskInit(function()
+    while hmeta do
+        -- hmeta识别底层模组类型的
+        -- 不同的模组可以使用相同的bsp,但根据封装的不同,根据内部数据仍可识别出具体模块
+        log.info("hmeta", hmeta.model(), hmeta.hwver and hmeta.hwver())
+        log.info("bsp",   rtos.bsp())
+        sys.wait(3000)
+    end
+    log.info("这个bsp不支持hmeta库哦")
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 3 - 0
module/Air780E/demo/http/luatos_uploadFile.txt

@@ -0,0 +1,3 @@
+测试文本   adcc1234x衣二三
+	84as1c188
+-*accxxx6-4

+ 306 - 0
module/Air780E/demo/http/main.lua

@@ -0,0 +1,306 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "httpdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要http库, 大部分能联网的设备都具有这个库
+http也是内置库, 无需require
+
+1. 如需上传大文件,请使用 httpplus 库, 对应demo/httpplus
+2. 
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用http库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        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 mobile 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)
+    elseif http then
+        sys.waitUntil("IP_READY")
+    else
+        while 1 do
+            sys.wait(1000)
+            log.info("http", "当前固件未包含http库")
+        end
+    end
+    log.info("已联网")
+    sys.publish("net_ready")
+end)
+
+function demo_http_get()
+    -- 最普通的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)
+    local code, headers, body = http.request("GET", "https://www.luatos.com/").wait()
+    log.info("http.get", code, headers, body)
+
+    -- 按需打印
+    -- code 响应值, 若大于等于 100 为服务器响应, 小于的均为错误代码
+    -- headers是个table, 一般作为调试数据存在
+    -- body是字符串. 注意lua的字符串是带长度的byte[]/char*, 是可以包含不可见字符的
+    -- log.info("http", code, json.encode(headers or {}), #body > 512 and #body or body)
+end
+
+function demo_http_post_json()
+    -- 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)
+end
+
+function demo_http_post_form()
+    -- POST request 演示
+    local req_headers = {}
+    req_headers["Content-Type"] = "application/x-www-form-urlencoded"
+    local params = {
+        ABC = "123",
+        DEF = 345
+    }
+    local body = ""
+    for k, v in pairs(params) do
+        body = body .. tostring(k) .. "=" .. tostring(v):urlEncode() .. "&"
+    end
+    local code, headers, body = http.request("POST","http://echohttp.wendal.cn/post", 
+            req_headers,
+            body -- POST请求所需要的body, string, zbuff, file均可
+    ).wait()
+    log.info("http.post.form", code, headers, body)
+end
+
+-- local function http_download_callback(content_len,body_len,userdata)
+--     print("http_download_callback",content_len,body_len,userdata)
+-- end
+
+-- local http_userdata = "123456789"
+
+function demo_http_download()
+
+    -- POST and download, task内的同步操作
+    local opts = {}                 -- 额外的配置项
+    opts["dst"] = "/data.bin"       -- 下载路径,可选
+    opts["timeout"] = 30000         -- 超时时长,单位ms,可选
+    -- opts["adapter"] = socket.ETH0  -- 使用哪个网卡,可选
+    -- opts["callback"] = http_download_callback
+    -- opts["userdata"] = http_userdata
+
+    for k, v in pairs(opts) do
+        print("opts",k,v)
+    end
+    
+    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)
+end
+
+function demo_http_post_file()
+        -- -- 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",
+                }
+            }
+        )
+end
+
+
+local function demo_http_get_gzip()
+    -- 这里用 和风天气 的API做演示
+    -- 这个API的响应, 总会gzip压缩过, 需要配合miniz库进行解压
+    local code, headers, body = http.request("GET", "https://devapi.qweather.com/v7/weather/now?location=101010100&key=0e8c72015e2b4a1dbff1688ad54053de").wait()
+    log.info("http.gzip", code)
+    if code == 200 then
+        local re = miniz.uncompress(body:sub(11), 0)
+        log.info("和风天气", re)
+        if re then
+            local jdata = json.decode(re)
+            log.info("jdata", jdata)
+            if jdata then
+                log.info("和风天气", jdata.code)
+                if jdata.now then
+                    log.info("和风天气", "天气", jdata.now.text)
+                    log.info("和风天气", "温度", jdata.now.temp)
+                end
+            end
+        end
+    end
+end
+
+sys.taskInit(function()
+    sys.wait(100)
+    -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
+    -- if crypto.cipher_suites then
+    --     log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
+    -- end
+
+    -------------------------------------
+    -------- HTTP 演示代码 --------------
+    -------------------------------------
+    sys.waitUntil("net_ready") -- 等联网
+
+    while 1 do
+        -- 演示GET请求
+        demo_http_get()
+        -- 表单提交
+        -- demo_http_post_form()
+        -- POST一个json字符串
+        -- demo_http_post_json()
+        -- 上传文件, mulitform形式
+        -- demo_http_post_file()
+        -- 文件下载
+        -- demo_http_download()
+        -- gzip压缩的响应, 以和风天气为例
+        -- demo_http_get_gzip()
+
+        sys.wait(1000)
+        -- 打印一下内存状态
+        log.info("sys", rtos.meminfo("sys"))
+        log.info("lua", rtos.meminfo("lua"))
+        sys.wait(600000)
+    end
+end)
+
+---- MultipartForm上传文件
+-- url string 请求URL地址
+-- req_headers table 请求头
+-- params table 需要传输的数据参数
+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.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 74 - 0
module/Air780E/demo/httpdns/main.lua

@@ -0,0 +1,74 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "httpdnsdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要http库, 大部分能联网的设备都具有这个库
+http也是内置库, 无需require
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用http库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+httpdns = require "httpdns"
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        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()
+        -- TODO 获取mac地址作为device_id
+    elseif mobile 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
+    log.info("已联网")
+    sys.publish("net_ready")
+end)
+
+sys.taskInit(function()
+    sys.waitUntil("net_ready")
+    while 1 do
+        sys.wait(1000)
+        -- 通过阿里DNS获取结果
+        local ip = httpdns.ali("air32.cn")
+        log.info("httpdns", "air32.cn", ip)
+
+
+        -- 通过腾讯DNS获取结果
+        local ip = httpdns.tx("openluat.com")
+        log.info("httpdns", "openluat.com", ip)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 36 - 0
module/Air780E/demo/httpplus/abc.txt

@@ -0,0 +1,36 @@
+# luatos-soc-2023
+
+#### Description
+{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 127 - 0
module/Air780E/demo/httpplus/main.lua

@@ -0,0 +1,127 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "httpdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo需要socket库, 大部分能联网的设备都具有这个库
+socket是内置库, 无需require
+]]
+
+-- sys库是标配
+_G.sys = require("sys")
+httpplus = require "httpplus"
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+sys.taskInit(function()
+    -----------------------------
+    -- 统一联网函数, 可自行删减
+    ----------------------------
+    if wlan and wlan.connect then
+        -- wifi 联网, ESP32系列均支持
+        local ssid = "luatos1234"
+        local password = "12341234"
+        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()
+        -- TODO 获取mac地址作为device_id
+    elseif mobile 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)
+    elseif http then
+        sys.waitUntil("IP_READY")
+    else
+        while 1 do
+            sys.wait(1000)
+            log.info("http", "当前固件未包含http库")
+        end
+    end
+    log.info("已联网")
+    sys.publish("net_ready")
+end)
+
+function test_httpplus()
+    sys.waitUntil("net_ready")
+    -- 调试开关
+    httpplus.debug = true
+
+    -- socket.sslLog(3)
+    -- local code, resp =httpplus.request({method="POST", url="https://abc:qq@whoami.k8s.air32.cn/goupupup"})
+    -- log.info("http", code, resp)
+
+    -- 预期返回302
+    -- local code, resp = httpplus.request({method="POST", url="https://air32.cn/goupupup"})
+    -- log.info("http", code, resp)
+
+    -- local code, resp = httpplus.request({method="POST", url="https://httpbin.air32.cn/post", files={abcd="/luadb/libfastlz.a"}})
+    -- log.info("http", code, resp)
+
+    -- local code, resp = httpplus.request({method="POST", url="https://httpbin.air32.cn/anything", forms={abcd="12345"}})
+    -- log.info("http", code, resp)
+
+    -- local code, resp = httpplus.request({method="POST", url="https://httpbin.air32.cn/post", files={abcd="/luadb/abc.txt"}})
+    -- log.info("http", code, resp)
+
+    -- 简单GET请求
+    local code, resp = httpplus.request({url="https://httpbin.air32.cn/"})
+    log.info("http", code, resp)
+    
+    -- 简单POST请求
+    -- local code, resp = httpplus.request({url="https://httpbin.air32.cn/post", body="123456", method="POST"})
+    -- log.info("http", code, resp)
+    
+    -- 文件上传
+    -- local code, resp = httpplus.request({url="https://httpbin.air32.cn/post", files={myfile="/luadb/abc.txt"}})
+    -- log.info("http", code, resp)
+    
+    -- 自定义header的GET请求
+    -- local code, resp = httpplus.request({url="https://httpbin.air32.cn/get", headers={Auth="12312234"}})
+    -- log.info("http", code, resp)
+    
+    -- 带鉴权信息的GET请求
+    -- local code, resp = httpplus.request({url="https://wendal:123@httpbin.air32.cn/get", headers={Auth="12312234"}})
+    -- log.info("http", code, resp)
+    
+    -- PUT请求
+    -- local code, resp = httpplus.request({url="https://httpbin.air32.cn/put", method="PUT", body="123"})
+    -- log.info("http", code, resp)
+
+    -- 表单POST
+    -- local code, resp = httpplus.request({url="https://httpbin.air32.cn/post", forms={abc="123"}})
+    -- log.info("http", code, resp)
+
+    -- 响应体chucked编码测试
+    local code, resp = httpplus.request({url="https://httpbin.air32.cn/stream/1"})
+    log.info("http", code, resp)
+    if code == 200 then
+        log.info("http", "headers", json.encode(resp.headers))
+        local body = resp.body:query()
+        log.info("http", "body", body:toHex())
+        log.info("http", "body", body)
+        log.info("http", "body", json.decode(body:trim()))
+        -- log.info("http", "body", json.decode(resp.body))
+    end
+end
+
+sys.taskInit(test_httpplus)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 38 - 0
module/Air780E/demo/i2c/main.lua

@@ -0,0 +1,38 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "i2c 24c02 demo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+sys = require("sys")
+
+--1010 000x
+--7bit地址,不包含最后一位读写位
+local addr = 0x50
+-- 按照实际芯片更改编号哦
+local i2cid = 0
+
+sys.taskInit(function()
+    log.info("i2c initial",i2c.setup(i2cid))
+    while true do
+        --第一种方式
+        i2c.send(i2cid, addr, string.char(0x01).."1234abcd")
+        sys.wait(100)
+        i2c.send(i2cid, addr, string.char(0x01))
+        local data = i2c.recv(i2cid, addr, 8)
+        log.info("i2c", "data1",data:toHex(),data)
+
+        --第二种方式
+        i2c.writeReg(i2cid, addr, 0x01, "abcd1234")
+        sys.wait(100)
+        local data = i2c.readReg(i2cid, addr, 0x01, 8)
+        log.info("i2c", "data2",data:toHex(),data)
+        sys.wait(1000)
+    end
+
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 130 - 0
module/Air780E/demo/i2s/main.lua

@@ -0,0 +1,130 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "i2sdemo"
+VERSION = "1.0.0"
+
+--[[
+本demo暂时只在air101/103/601测试过
+对于EC618系列的模块,例如Air780E/Air700E,请使用audio库进行快捷播放
+
+本demo需要外挂ES8311 codec芯片, 可使用海凌科的w800音频开发板进行测试
+
+https://detail.tmall.com/item.htm?abbucket=2&id=670202333872
+]]
+
+-- sys库是标配
+sys = require("sys")
+
+if wdt then
+    --添加硬狗防止程序卡死,在支持的设备上启用这个功能
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+sys.taskInit(function()
+    sys.wait(500)
+    local multimedia_id = 0
+    local i2c_id = 0
+    local i2s_id = 0
+    local i2s_mode = 0
+    local i2s_sample_rate = 44100
+    local i2s_bits_per_sample = 16
+    local i2s_channel_format = 0
+    local i2s_communication_format = 0
+    local i2s_channel_bits = 32
+
+    local pa_pin = 20
+    local pa_on_level = 1
+    local pa_delay = 20
+    local power_pin = 255
+    local power_delay = 0
+
+    local voice_vol = 70
+
+    i2c.setup(i2c_id,i2c.FAST)
+    i2s.setup(i2s_id, i2s_mode, i2s_sample_rate, i2s_bits_per_sample, i2s_channel_format, i2s_communication_format,i2s_channel_bits)
+
+    audio.config(multimedia_id, pa_pin, pa_on_level, power_delay, pa_delay, power_pin)
+    audio.setBus(multimedia_id, audio.BUS_I2S,{chip = "es8311",i2cid = i2c_id , i2sid = i2s_id})	--通道0的硬件输出通道设置为I2S
+
+    -- 播放参数设置
+    audio.start(multimedia_id, audio.PCM, 1, 16000, 16)
+    -- 音量设置
+    audio.vol(multimedia_id, 50)
+    audio.pm(multimedia_id,audio.RESUME)
+    -- PCM播放演示, 16k采样率, 16bit采样深度
+    local file_size = fs.fsize("/luadb/test.pcm")
+    -- print("/luadb/test.pcm size",file_size)   
+    local f = io.open("/luadb/test.pcm", "rb")
+    if f then 
+        while 1 do
+            local data = f:read(4096)
+            -- print("-------------")
+            if not data or #data == 0 then
+                break
+            end
+            audio.write(0, data)
+            sys.wait(100)
+        end
+        f:close()
+    end
+
+    -- mp3测试
+    -- 推荐使用ffmpeg对mp3文件进行预处理, 必须转成单声道
+    --  ffmpeg -i abc.mp3 -ac 1 -map_metadata -1 -y out.mp3
+    -- Air101/Air103/Air601支持采样率 8~44.1k, 深度8-16bit, 以下是转成16k采样率
+    --  ffmpeg -i abc.mp3 -ac 1 -map_metadata -1 -ar 16000 -y out.mp3
+    local path = "/luadb/out.mp3"
+    local decoder = codec.create(codec.MP3)
+    log.info("decoder", decoder)
+    local result, audio_format, num_channels, sample_rate, bits_per_sample, is_signed= codec.info(decoder, path)
+    log.info("info", result, audio_format, num_channels, sample_rate, bits_per_sample, is_signed)
+    if result then
+        -- 按mp3实际情况切换采样率和采样深度
+        audio.start(0, audio.PCM, 1, sample_rate, bits_per_sample) 
+        -- 音频数据缓存区大小
+        local buff = zbuff.create(8*1024)
+        -- log.info("sys", rtos.meminfo("sys"))
+        -- log.info("buff", buff)
+        while 1 do
+            -- log.info("尝试解码")
+            local result = codec.data(decoder, buff, 4096)
+            -- log.info("解析结果", result)
+            if result then
+                while 1 do
+                    -- 判断底层缓冲区是否空闲, 不空闲就需要等待
+                    local max, remain = i2s.txStat(0)
+                    if max == 0 then
+                        sys.wait(120)
+                        break
+                    end
+                    if remain > (max / 2) then
+                        sys.wait(10) -- sys.waitUntil("AUDIO_INC", 10)
+                    else
+                        break -- 已经足够空闲,写入数据就好
+                    end
+                end
+                audio.write(0, buff)
+                -- log.info("音频数据已写入", buff:used())
+            else
+                break
+            end
+        end
+    end
+    -- 释放解码器资源
+    codec.release(decoder)
+end)
+
+-- sys.taskInit(function()
+--     while 1 do
+--         -- 打印内存状态, 调试用
+--         sys.wait(1000)
+--         log.info("lua", rtos.meminfo())
+--         log.info("sys", rtos.meminfo("sys"))
+--     end
+-- end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

BIN
module/Air780E/demo/i2s/test.pcm


BIN
module/Air780E/demo/i2s/test_16k.mp3


+ 218 - 0
module/Air780E/demo/iconv/main.lua

@@ -0,0 +1,218 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "my_test"
+VERSION = "1.2"
+PRODUCT_KEY = "s1uUnY6KA06ifIjcutm5oNbG3MZf5aUv" -- 换成自己的
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+
+--- unicode小端编码 转化为 gb2312编码
+-- @string ucs2s unicode小端编码数据
+-- @return string data,gb2312编码数据
+-- @usage local data = common.ucs2ToGb2312(ucs2s)
+function ucs2ToGb2312(ucs2s)
+    local cd = iconv.open("gb2312", "ucs2")
+    return cd:iconv(ucs2s)
+end
+
+--- gb2312编码 转化为 unicode小端编码
+-- @string gb2312s gb2312编码数据
+-- @return string data,unicode小端编码数据
+-- @usage local data = common.gb2312ToUcs2(gb2312s)
+function gb2312ToUcs2(gb2312s)
+    local cd = iconv.open("ucs2", "gb2312")
+    return cd:iconv(gb2312s)
+end
+
+--- unicode大端编码 转化为 gb2312编码
+-- @string ucs2s unicode大端编码数据
+-- @return string data,gb2312编码数据
+-- @usage data = common.ucs2beToGb2312(ucs2s)
+function ucs2beToGb2312(ucs2s)
+    local cd = iconv.open("gb2312", "ucs2be")
+    return cd:iconv(ucs2s)
+end
+
+--- gb2312编码 转化为 unicode大端编码
+-- @string gb2312s gb2312编码数据
+-- @return string data,unicode大端编码数据
+-- @usage local data = common.gb2312ToUcs2be(gb2312s)
+function gb2312ToUcs2be(gb2312s)
+    local cd = iconv.open("ucs2be", "gb2312")
+    return cd:iconv(gb2312s)
+end
+
+--- unicode小端编码 转化为 utf8编码
+-- @string ucs2s unicode小端编码数据
+-- @return string data,utf8编码数据
+-- @usage data = common.ucs2ToUtf8(ucs2s)
+function ucs2ToUtf8(ucs2s)
+    local cd = iconv.open("utf8", "ucs2")
+    return cd:iconv(ucs2s)
+end
+
+--- utf8编码 转化为 unicode小端编码
+-- @string utf8s utf8编码数据
+-- @return string data,unicode小端编码数据
+-- @usage local data = common.utf8ToUcs2(utf8s)
+function utf8ToUcs2(utf8s)
+    local cd = iconv.open("ucs2", "utf8")
+    return cd:iconv(utf8s)
+end
+
+--- unicode大端编码 转化为 utf8编码
+-- @string ucs2s unicode大端编码数据
+-- @return string data,utf8编码数据
+-- @usage data = common.ucs2beToUtf8(ucs2s)
+function ucs2beToUtf8(ucs2s)
+    local cd = iconv.open("utf8", "ucs2be")
+    return cd:iconv(ucs2s)
+end
+
+--- utf8编码 转化为 unicode大端编码
+-- @string utf8s utf8编码数据
+-- @return string data,unicode大端编码数据
+-- @usage local data = common.utf8ToUcs2be(utf8s)
+function utf8ToUcs2be(utf8s)
+    local cd = iconv.open("ucs2be", "utf8")
+    return cd:iconv(utf8s)
+end
+
+--- utf8编码 转化为 gb2312编码
+-- @string utf8s utf8编码数据
+-- @return string data,gb2312编码数据
+-- @usage local data = common.utf8ToGb2312(utf8s)
+function utf8ToGb2312(utf8s)
+    local cd = iconv.open("ucs2", "utf8")
+    local ucs2s = cd:iconv(utf8s)
+    cd = iconv.open("gb2312", "ucs2")
+    return cd:iconv(ucs2s)
+end
+
+--- gb2312编码 转化为 utf8编码
+-- @string gb2312s gb2312编码数据
+-- @return string data,utf8编码数据
+-- @usage local data = common.gb2312ToUtf8(gb2312s)
+function gb2312ToUtf8(gb2312s)
+    local cd = iconv.open("ucs2", "gb2312")
+    local ucs2s = cd:iconv(gb2312s)
+    cd = iconv.open("utf8", "ucs2")
+    return cd:iconv(ucs2s)
+end
+
+--------------------------------------------------------------------------------------------------------
+--[[
+函数名:ucs2ToGb2312
+功能  :unicode小端编码 转化为 gb2312编码,并打印出gb2312编码数据
+参数  :
+        ucs2s:unicode小端编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testucs2ToGb2312(ucs2s)
+    print("ucs2ToGb2312")
+    local gb2312num = ucs2ToGb2312(ucs2s)--调用的是common.ucs2ToGb2312,返回的是编码所对应的字符串
+    --print("gb2312  code:",gb2312num)
+    print("gb2312  code:",string.toHex(gb2312num))
+end
+
+--[[
+函数名:gb2312ToUcs2
+功能  :gb2312编码 转化为 unicode十六进制小端编码数据并打印
+参数  :
+        gb2312s:gb2312编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testgb2312ToUcs2(gb2312s)
+    print("gb2312ToUcs2")
+    local ucs2num = gb2312ToUcs2(gb2312s)
+    print("unicode little-endian code:" .. string.toHex(ucs2num)) -- 要将二进制转换为十六进制,否则无法输出
+end
+
+--[[
+函数名:ucs2beToGb2312
+功能  :unicode大端编码 转化为 gb2312编码,并打印出gb2312编码数据,
+大端编码数据是与小端编码数据位置调换
+参数  :
+        ucs2s:unicode大端编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testucs2beToGb2312(ucs2s)
+    print("ucs2beToGb2312")
+    local gb2312num = ucs2beToGb2312(ucs2s) -- 转化后的数据直接变成字符可以直接输出
+    print("gb2312 code :" .. string.toHex(gb2312num))
+end
+
+--[[
+函数名:gb2312ToUcs2be
+功能  :gb2312编码 转化为 unicode大端编码,并打印出unicode大端编码
+参数  :
+        gb2312s:gb2312编码数据,注意输入参数的字节数
+返回值:unicode大端编码数据
+]]
+function testgb2312ToUcs2be(gb2312s)
+    print("gb2312ToUcs2be")
+    local ucs2benum = gb2312ToUcs2be(gb2312s)
+    print("unicode big-endian code :" .. string.toHex(ucs2benum))
+end
+
+--[[
+函数名:ucs2ToUtf8
+功能  :unicode小端编码 转化为 utf8编码,并打印出utf8十六进制编码数据
+参数  :
+        ucs2s:unicode小端编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testucs2ToUtf8(ucs2s)
+    print("ucs2ToUtf8")
+    local utf8num = ucs2ToUtf8(ucs2s)
+    print("utf8  code:" .. string.toHex(utf8num))
+
+end
+
+--[[
+函数名:utf8ToGb2312
+功能  :utf8编码 转化为 gb2312编码,并打印出gb2312编码数据
+参数  :
+        utf8s:utf8编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testutf8ToGb2312(utf8s)
+    print("utf8ToGb2312")
+    local gb2312num = utf8ToGb2312(utf8s)
+    print("gb2312 code:" .. string.toHex(gb2312num))
+
+end
+
+--[[
+函数名:gb2312ToUtf8
+功能  :gb2312编码 转化为 utf8编码,并打印出utf8编码数据
+参数  :
+        gb2312s:gb2312s编码数据,注意输入参数的字节数
+返回值:
+]]
+local function testgb2312ToUtf8(gb2312s)
+    print("gb2312ToUtf8")
+    local utf8s = gb2312ToUtf8(gb2312s)
+    print("utf8s code:" .. utf8s)
+
+end
+
+
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(1000)
+        testucs2ToGb2312(string.fromHex("1162")) -- "1162"是"我"字的ucs2编码,这里调用了string.fromHex将参数转化为二进制,也就是两个字节。
+        testgb2312ToUcs2(string.fromHex("CED2")) -- "CED2"是"我"字的gb2312编码
+        testucs2beToGb2312(string.fromHex("6211")) -- "6211"是"我"字的ucs2be编码
+        testgb2312ToUcs2be(string.fromHex("CED2"))
+        testucs2ToUtf8(string.fromHex("1162"))
+        testutf8ToGb2312(string.fromHex("E68891")) -- "E68891"是"我"字的utf8编码
+        testgb2312ToUtf8(string.fromHex("CED2"))
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 132 - 0
module/Air780E/demo/io_queue/main.lua

@@ -0,0 +1,132 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ioqueue"
+VERSION = "1.0.0"
+-- 仅支持ioqueue的平台能使用!!
+-- sys库是标配
+_G.sys = require("sys")
+
+function pinx() 
+    gpio.setup(10,nil,nil)
+    gpio.setup(11,nil,nil)
+    return 1, 10,11
+end
+
+sys.taskInit(function()
+
+    local _,tick_us = mcu.tick64()
+    local hw_timer_id, capture_pin,out_pin = pinx()
+    local buff1 = zbuff.create(100)
+    local buff2 = zbuff.create(100)
+    local cnt1,cnt2,i,lastTick,bit1Tick,nowTick,j,bit
+	mcu.hardfault(0)
+	sys.wait(2000)
+    bit1Tick = 100 * tick_us
+    while 1 do
+		log.info('start dht11')
+        --测试单总线DHT11
+        ioqueue.stop(hw_timer_id)   --确保硬件定时器1是空闲的
+        ioqueue.init(hw_timer_id,100,1) --io队列设置100个命令,重复1次,实际上用不到那么多命令
+        ioqueue.setgpio(hw_timer_id, capture_pin, true, gpio.PULLUP)   --数据线拉高,上拉输入
+        ioqueue.setdelay(hw_timer_id, 10000, 0, false)  --单次延迟10ms
+        ioqueue.setgpio(hw_timer_id, capture_pin, false, 0, 0)   --数据线拉低
+        ioqueue.setdelay(hw_timer_id, 18000, 0, false)  --单次延迟18ms
+        ioqueue.set_cap(hw_timer_id, capture_pin, gpio.PULLUP, gpio.FALLING, 100000 * tick_us)   --设置成下降沿中断捕获,最大计时100000us, 上拉输入,这里已经代替了输出20~40us高电平
+        for i = 1,42,1 do
+            ioqueue.capture(hw_timer_id)    --捕获42次外部中断发生时的tick值,2个start信号+40bit数据
+        end
+        ioqueue.cap_done(hw_timer_id, capture_pin)  --停止捕获
+        ioqueue.setgpio(hw_timer_id, capture_pin, true, gpio.PULLUP)   --数据线拉高,上拉输入
+        ioqueue.start(hw_timer_id)
+        sys.waitUntil("IO_QUEUE_DONE_"..hw_timer_id)
+        ioqueue.stop(hw_timer_id)
+        --开始解析捕获的数据
+        cnt1,cnt2 = ioqueue.get(hw_timer_id, buff1, buff2)
+        if cnt2 ~= 42 then
+            log.info('test fail')
+            goto TEST_OUT
+        end
+        lastTick = buff2:query(6 + 2, 4, false) --以第二次中断的tick作为起始tick,第一次的tick没有用
+        j = 0
+        bit = 8
+        buff1[0] = 0
+        for i = 2,41,1 do
+			
+            --检查一下是不是对应pin的下降沿中断,不过也不太需要
+            if buff2[i * 6 + 0] ~= capture_pin or buff2[i * 6 + 1] ~= 0 then
+                log.error("capture", i, buff2[i * 6 + 0], buff2[i * 6 + 1])
+            end
+            --通过计算tick差值来确定是bit1还是bit0
+            nowTick = buff2:query(i * 6 + 2, 4, false)
+            buff1[j] = buff1[j] << 1 
+            if (nowTick - lastTick) > bit1Tick then
+               buff1[j] = buff1[j] + 1
+            end
+            bit = bit - 1
+            if bit == 0 then
+                j = j + 1
+                bit = 8
+            end
+            lastTick = nowTick
+        end
+        buff1[5] = buff1[0] + buff1[1] + buff1[2] + buff1[3]
+        if buff1[4] ~= buff1[5] then
+            log.info('check fail', buff1[4], buff1[5])
+        else
+            log.info("湿度", buff1[0] .. '.' .. buff1[1], "温度", buff1[2] .. '.' ..  buff1[3])
+        end
+        ::TEST_OUT::
+        ioqueue.release(hw_timer_id)
+
+		log.info('output 1 start')
+		 --测试高精度固定间隔定时输出,1us间隔翻转电平
+        ioqueue.init(hw_timer_id, 100, 100)
+        ioqueue.setgpio(hw_timer_id, out_pin, false,0,1)   --设置成输出口,电平1
+        ioqueue.setdelay(hw_timer_id, 0, tick_us - 3, true)  --设置成连续延时,每次1个us,如果不准,对time_tick微调,延时开始
+        for i = 0,40,1 do
+            ioqueue.output(hw_timer_id, out_pin, 0)
+            ioqueue.delay(hw_timer_id)     --连续延时1次
+            ioqueue.output(hw_timer_id, out_pin, 1)
+            ioqueue.delay(hw_timer_id)     --连续延时1次
+        end
+        ioqueue.start(hw_timer_id)
+        sys.waitUntil("IO_QUEUE_DONE_"..hw_timer_id)
+        log.info('output 1 done')
+        ioqueue.stop(hw_timer_id)
+        ioqueue.release(hw_timer_id)
+        sys.wait(500)
+
+		log.info('output 2 start')
+        --测试高精度可变间隔定时输出
+        ioqueue.init(hw_timer_id, 100, 100)
+        ioqueue.setgpio(hw_timer_id, out_pin, false,0,1)   --设置成输出口,电平1
+        ioqueue.setdelay(hw_timer_id, 0, tick_us - 3)  --单次延迟1us,如果不准,对time_tick微调
+        ioqueue.output(hw_timer_id, out_pin, 0) --低电平
+        ioqueue.setdelay(hw_timer_id, 1, tick_us - 3)  --单次延迟2us
+        ioqueue.output(hw_timer_id, out_pin, 1) --高电平
+        ioqueue.setdelay(hw_timer_id, 2, tick_us - 3)  --单次延迟3us
+        ioqueue.output(hw_timer_id, out_pin, 0) --低电平
+        ioqueue.setdelay(hw_timer_id, 3, tick_us - 3)  --单次延迟4us
+        ioqueue.output(hw_timer_id, out_pin, 1) --高电平
+        ioqueue.setdelay(hw_timer_id, 4, tick_us - 3)  --单次延迟5us
+        ioqueue.output(hw_timer_id, out_pin, 0) --低电平
+        ioqueue.setdelay(hw_timer_id, 5, tick_us - 3)  --单次延迟6us
+        ioqueue.output(hw_timer_id, out_pin, 1) --高电平
+        ioqueue.start(hw_timer_id)
+        sys.waitUntil("IO_QUEUE_DONE_"..hw_timer_id)
+		log.info('output 2 done')
+        ioqueue.stop(hw_timer_id)
+        ioqueue.release(hw_timer_id)
+        sys.wait(500)
+		
+
+		
+
+		
+
+    end
+end)
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 52 - 0
module/Air780E/demo/iotauth/main.lua

@@ -0,0 +1,52 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "iotauthdemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+local sys = require "sys"
+
+log.info("main", PROJECT, VERSION)
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+sys.taskInit(function()
+    sys.wait(2000)
+    -- 以下演示的, 均为 mqtt 所需的密钥计算, 可配合demo/socket 或 demo/mqtt 下的示例一起使用
+
+    -- 中移动OneNet
+    local client_id,user_name,password = iotauth.onenet("qDPGh8t81z", "45463968338A185E", "MTIzNDU2")
+    log.info("onenet",client_id,user_name,password)
+
+    -- 华为云
+    local client_id,user_name,password = iotauth.iotda("6203cc94c7fb24029b110408_88888888","123456789")
+    log.info("iotda",client_id,user_name,password)
+
+    -- 涂鸦
+    local client_id,user_name,password = iotauth.tuya(" 6c95875d0f5ba69607nzfl","fb803786602df760")
+    log.info("tuya",client_id,user_name,password)
+
+    -- 百度云服务
+    local client_id,user_name,password = iotauth.baidu("abcd123","mydevice","ImSeCrEt0I1M2jkl")
+    log.info("baidu",client_id,user_name,password)
+
+    -- 腾讯云
+    local client_id,user_name,password = iotauth.qcloud("LD8S5J1L07","test","acyv3QDJrRa0fW5UE58KnQ==")
+    log.info("qcloud",client_id,user_name,password)
+
+    -- 阿里云
+    local client_id,user_name,password = iotauth.aliyun("123456789","abcdefg","Y877Bgo8X5owd3lcB5wWDjryNPoB")
+    log.info("aliyun",client_id,user_name,password)
+
+end)
+
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 161 - 0
module/Air780E/demo/iotcloud/oneNET/main.lua

@@ -0,0 +1,161 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "oneNET_demo"
+VERSION = "1.0.0"
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用mqtt库需要下列语句]]
+_G.sysplus = require("sysplus")
+lbsLoc2 = require("lbsLoc2")
+local iotcloud = require("iotcloud")
+mobile.simid(2, true)
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+local produt_id = "4qM5N1Sa4T"
+local userid = "226691"
+local userkey = "pk1M3FKXBvvmjF8If/xDfSFFmr96NZCEg00sxlLBMjjh9vOD5hpIs42rmAYnMh5b3m9B1+0rmYdqzUyoQVrxow=="
+local device_name = mobile.imei()
+local send_data_time = 5 * 60 * 1000 -- 定时发送数据的时间,单位ms
+
+-- 统一联网函数
+sys.taskInit(function()
+    local device_id = mcu.unique_id():toHex()
+
+    -- 默认都等到联网成功
+    sys.waitUntil("IP_READY")
+    sys.publish("net_ready", device_id)
+end)
+
+sys.taskInit(function()
+    -- 等待联网
+    local ret, device_id = sys.waitUntil("net_ready")
+
+    --------    以下接入方式根据自己需要修改,相关参数修改为自己的    ---------
+
+    -- ONENET云
+    -- 动态注册
+    iotcloudc = iotcloud.new(iotcloud.ONENET, {
+        device_name = device_name,
+        produt_id = produt_id,
+        userid = userid,
+        userkey = userkey
+    })
+    -- 一型一密
+    -- iotcloudc = iotcloud.new(iotcloud.ONENET,{produt_id = "xxx",product_secret = "xxx"})
+    -- 一机一密
+    -- iotcloudc = iotcloud.new(iotcloud.ONENET,{produt_id = "xxx",device_name = "xxx",device_secret = "xxx"})
+
+    if iotcloudc then
+        iotcloudc:connect()
+    end
+
+end)
+
+-- 发布和订阅的主题
+
+local oneNET_sub = "$sys/" .. produt_id .. "/" .. device_name .. "/thing/property/post/reply"
+
+local oneNET_pub = "$sys/" .. produt_id .. "/" .. device_name .. "/thing/property/post"
+
+local function oneNET_send_data()
+    log.info("oneNET 链接成功,准备开始发送数据")
+    while 1 do
+        -- 没有mobile库就没有基站定位
+        mobile.reqCellInfo(15)
+        -- 由于基站定位需要等待扫描周围基站,推荐扫描时间为15S
+        sys.waitUntil("CELL_INFO_UPDATE", 15000)
+        local lat, lng, t = lbsLoc2.request(5000)
+        log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
+        -- 如果没扫描到基站则给lat和lng赋值为0
+        if lat and lng then
+            log.info("扫描到了,有位置信息")
+        else
+            lat = "0"
+            lng = "0"
+        end
+        -- 读取CPU温度, 单位为0.001摄氏度, 是内部温度, 非环境温度
+        adc.open(adc.CH_CPU)
+        local cpu_temp = adc.get(adc.CH_CPU)
+        adc.close(adc.CH_CPU)
+        local gpio_pin = 6 -- GPIO编号
+        local gpio_state = gpio.get(gpio_pin)
+        local send_data = {
+            id = "123",
+            verson = VERSION,
+            params = {
+                gpio_state = {
+                    value = gpio_state
+                },
+                cpu_temp = {
+                    value = cpu_temp / 1000
+                },
+                lbs_lat = {
+                    value = tonumber(lat)
+                },
+                lbs_lng = {
+                    value = tonumber(lng)
+                    -- value = lng
+                }
+            }
+        }
+        local send_data = json.encode(send_data)
+        log.info("发送的数据为", send_data)
+        -- 正式发布数据
+        iotcloudc:publish(oneNET_pub, send_data)
+        -- 循环发送数据的定时时间
+        sys.wait(send_data_time)
+    end
+
+end
+
+local con = 0
+--oneNET断开后的处理函数,
+local function oneNET_DISCONNECT()
+    log.info("云平台断开了,隔一分钟重连一次,如果10次都没有连上则重启设备")
+    while con < 10 do
+        sys.wait(60*1000)
+        log.info("oneNET reconnection",con)
+        iotcloudc:connect()
+    end
+    pm.reboot()
+end
+sys.subscribe("iotcloud", function(cloudc, event, data, payload)
+    -- 注意,此处不是协程内,复杂操作发消息给协程内进行处理
+    if event == iotcloud.CONNECT then -- 云平台联上了
+        log.info("iotcloud", "CONNECT", "oneNET平台连接成功")
+        iotcloudc:subscribe({
+            [oneNET_sub] = 1
+        }) -- 订阅服务器下发数据的主题
+        -- 链接成功,启动一个task专门用来定时发消息
+        sys.taskInit(oneNET_send_data)
+
+    elseif event == iotcloud.RECEIVE then
+        log.info("收到服务器下发的数据")
+        log.info("iotcloud", "topic", data, "payload", payload)
+
+        -- 用户处理代码
+        if payload then
+            payload = json.decode(payload)
+            if payload["code"] == 200 then
+                log.info("服务器收到了刚刚上传的数据", payload["msg"])
+            else
+                log.info("服务器接收数据有误", "错误码为", payload["code"], "错误信息为",
+                    payload["msg"])
+            end
+        end
+
+    elseif event == iotcloud.SEND then
+        log.info("发送数据成功")
+
+    elseif event == iotcloud.DISCONNECT then -- 云平台断开了
+       sys.taskInit(oneNET_DISCONNECT)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 140 - 0
module/Air780E/demo/ipv6/client/main.lua

@@ -0,0 +1,140 @@
+--[[
+IPv6客户端演示, 仅EC618系列支持, 例如Air780E/Air600E/Air780UG/Air700E
+]]
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ipv6_client"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+-- 处理未识别的网络消息
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+-- 演示task
+function ipv6test()
+    -- 启用IPv6, 默认关闭状态,必须在驻网前开启
+    -- 注意, 启用IPv6, 联网速度会慢2~3秒
+    mobile.ipv6(true)
+
+    log.info("ipv6", "等待联网")
+    sys.waitUntil("IP_READY")
+    log.info("ipv6", "联网完成")
+    sys.wait(100)
+
+    socket.setDNS(nil, 1, "119.29.29.29")
+    socket.setDNS(nil, 2, "114.114.114.114")
+
+    -- 开始正在的逻辑, 发起socket链接,等待数据/上报心跳
+    local taskName = "ipv6client"
+    local topic = taskName .. "_txrx"
+    local txqueue = {}
+    sysplus.taskInitEx(ipv6task, taskName, netCB, taskName, txqueue, topic)
+    while 1 do
+        local result, tp, data = sys.waitUntil(topic, 30000)
+        if not result then
+            -- 等很久了,没数据上传/下发, 发个日期心跳包吧
+            table.insert(txqueue, string.char(0))
+            sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "uplink" then
+            -- 上行数据, 主动上报的数据,那就发送呀
+            table.insert(txqueue, data)
+            sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "downlink" then
+            -- 下行数据,接收的数据, 从ipv6task来的
+            -- 其他代码可以通过 sys.publish()
+            log.info("socket", "收到下发的数据了", #data)
+        end
+    end
+end
+
+
+
+function ipv6task(d1Name, txqueue, rxtopic)
+    -- 测试方式1, 连netlab外网版,带ipv6
+    -- 注意, 这里需要登录外网的netlab才有ipv6
+    -- 网站链接: https://netlab.luatos.org/ 
+    -- local host = "2603:c023:1:5fcc:c028:8ed:49a7:6e08"
+    -- local port = 55389 -- 页面点击"打开TCP" 后获取实际端口
+
+    -- 测试方式2, 连另外一个780e设备
+    local host = "864040064024194.dyndns.u8g2.com"
+    -- local host = "mirrors6.tuna.tsinghua.edu.cn"
+    -- local host = "2408:8456:e37:95d8::1"
+    local port = 14000
+
+    local rx_buff = zbuff.create(1024)
+    local netc = socket.create(nil, d1Name)
+    socket.config(netc)
+    log.info("任务id", d1Name)
+
+    while true do
+        log.info("socket", "开始连接服务器")
+        local result = libnet.connect(d1Name, 15000, netc, host, port, true)
+        if result then
+			log.info("socket", "服务器连上了")
+			libnet.tx(d1Name, 0, netc, "helloworld")
+        else
+            log.info("socket", "服务器没连上了!!!")
+		end
+		while result do
+            -- log.info("socket", "调用rx接收数据")
+			local succ, param = socket.rx(netc, rx_buff)
+			if not succ then
+				log.info("服务器断开了", succ, param, ip, port)
+				break
+			end
+			if rx_buff:used() > 0 then
+				log.info("socket", "收到服务器数据,长度", rx_buff:used())
+                local data = rx_buff:query() -- 获取数据
+                sys.publish(rxtopic, "downlink", data)
+				rx_buff:del()
+			end
+            -- log.info("libnet", "调用wait开始等待消息")
+			result, param, param2 = libnet.wait(d1Name, 15000, netc)
+            log.info("libnet", "wait", result, param, param2)
+			if not result then
+                -- 网络异常了
+				log.info("socket", "服务器断开了", result, param)
+				break
+            elseif #txqueue > 0 then
+                while #txqueue > 0 do
+                    local data = table.remove(txqueue, 1)
+                    if not data then
+                        break
+                    end
+                    result,param = libnet.tx(d1Name, 15000, netc,data)
+                    log.info("libnet", "发送数据的结果", result, param)
+                    if not result then
+                        log.info("socket", "数据发送异常", result, param)
+                        break
+                    end
+                end
+            end
+		end
+		libnet.close(d1Name, 5000, netc)
+		-- log.info(rtos.meminfo("sys"))
+		sys.wait(5000)
+    end
+end
+
+sys.taskInit(ipv6test)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 45 - 0
module/Air780E/demo/ipv6/server/index.html

@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+    <header>
+        <meta charset="utf-8"/>
+        <title>Http Server Get-Start</title>
+        <!-- fetch api-->
+        <script type="text/javascript">
+            function led(key) {
+                fetch("/led/" + key)
+            }
+            function gpio1(key) {
+                fetch("/gpio1/" + key)
+            }
+            function gpio24(key) {
+                fetch("/gpio24/" + key)
+            }
+        </script>
+    </header>
+    <body>
+        <h2>点击按钮, led灯会亮起或熄灭</h2>
+        <div>
+            <div>
+                <button onclick="led(1)">LED亮</button>
+            </div>
+            <div>
+                <button onclick="led(0)">LED灭</button>
+            </div>
+            <div>
+                <button onclick="gpio1(1)">GPIO1 输出高电平</button>
+            </div>
+            <div>
+                <button onclick="gpio1(0)">GPIO1 输出低电平</button>
+            </div>
+            <div>
+                <button onclick="gpio24(1)">GPIO24 输出高电平</button>
+            </div>
+            <div>
+                <button onclick="gpio24(0)">GPIO24 输出低电平</button>
+            </div>
+        </div>
+        <div>
+            <h4>Power by <a href="https://wiki.luatos.com">LuatOS</a></h4>
+        </div>
+    </body>
+</html>

+ 212 - 0
module/Air780E/demo/ipv6/server/main.lua

@@ -0,0 +1,212 @@
+--[[
+IPv6服务端演示, 仅EC618系列支持, 例如Air780E/Air600E/Air780UG/Air700E
+]]
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ipv6_server"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- 一定要添加sys.lua !!!!
+sys = require("sys")
+sysplus = require("sysplus")
+libnet = require "libnet"
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+-- 处理未识别的网络消息
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+LED = gpio.setup(27, 0)
+GPIO1 = gpio.setup(1, 0)
+GPIO24 = gpio.setup(24, 0)
+HTTP_200_EMTRY = "HTTP/1.0 200 OK\r\nServer: LuatOS\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
+
+-- 演示task
+function ipv6test()
+
+    -- 启用IPv6, 默认关闭状态,必须在驻网前开启
+    -- 注意, 启用IPv6, 联网速度会慢2~3秒
+    mobile.ipv6(true)
+
+    log.info("ipv6", "等待联网")
+    sys.waitUntil("IP_READY")
+    log.info("ipv6", "联网完成")
+    sys.wait(1000)
+
+    -- 打印一下本地ip, 一般只有ipv6才可能是公网ip, ipv4基本不可能
+    -- 而且ipv6不一样是外网ip, 这是运营商决定的, 模块无能为力
+    ip, mask, gw, ipv6 = socket.localIP()
+    log.info("本地IP地址", ip, ipv6)
+	if not ipv6 then
+		log.info("没有IPV6地址,无法演示")
+		-- return
+	end
+
+    log.info("shell", "telnet -6 " .. ipv6 .. " 14000")
+
+
+    -- 开始正在的逻辑, 发起socket链接,等待数据/上报心跳
+    local taskName = "ipv6server"
+    local topic = taskName .. "_txrx"
+    local txqueue = {}
+    sysplus.taskInitEx(ipv6task, taskName, netCB, taskName, txqueue, topic)
+    while 1 do
+        local result, tp, data = sys.waitUntil(topic, 60000)
+        if not result then
+            -- 等很久了,没数据上传/下发, 发个日期心跳包吧
+            --table.insert(txqueue, string.char(0))
+            --sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "uplink" then
+            -- 上行数据, 主动上报的数据,那就发送呀
+            table.insert(txqueue, data)
+            sys_send(taskName, socket.EVENT, 0)
+        elseif tp == "downlink" then
+            -- 下行数据,接收的数据, 从ipv6task来的
+            -- 其他代码可以通过 sys.publish()
+            log.info("socket", "收到下发的数据了", #data, data)
+            -- 下面是模拟一个http服务, 因为httpsrv库还没好,先用着吧
+            if data:startsWith("GET / ") then
+                local httpresp = "HTTP/1.0 200 OK\r\n"
+                httpresp = httpresp .. "Server: LuatOS\r\nContent-Type: text/html\r\nConnection: close\r\n"
+                local fdata = io.readFile("/luadb/index.html")
+                httpresp = httpresp .. string.format("Content-Length: %d\r\n\r\n", #fdata)
+                httpresp = httpresp .. fdata
+                table.insert(txqueue, httpresp)
+                table.insert(txqueue, "close")
+                sys_send(taskName, socket.EVENT, 0)
+            elseif  data:startsWith("GET /led/") then
+                if data:startsWith("GET /led/1") then
+                    log.info("led", "亮起")
+                    LED(1)
+                else
+                    log.info("led", "熄灭")
+                    LED(0)
+                end
+                table.insert(txqueue, HTTP_200_EMTRY)
+                table.insert(txqueue, "close")
+                sys_send(taskName, socket.EVENT, 0)
+            elseif  data:startsWith("GET /gpio24/") then
+                if data:startsWith("GET /gpio24/1") then
+                    log.info("gpio24", "亮起")
+                    GPIO24(1)
+                else
+                    log.info("gpio24", "熄灭")
+                    GPIO24(0)
+                end
+                table.insert(txqueue, HTTP_200_EMTRY)
+                table.insert(txqueue, "close")
+                sys_send(taskName, socket.EVENT, 0)
+            elseif  data:startsWith("GET /gpio1/") then
+                if data:startsWith("GET /gpio1/1") then
+                    log.info("gpio1", "亮起")
+                    GPIO1(1)
+                else
+                    log.info("gpio1", "熄灭")
+                    GPIO1(0)
+                end
+                table.insert(txqueue, HTTP_200_EMTRY)
+                table.insert(txqueue, "close")
+                sys_send(taskName, socket.EVENT, 0)
+            elseif data:startsWith("GET ") or data:startsWith("POST ")  or data:startsWith("HEAD ") then
+                table.insert(txqueue, HTTP_200_EMTRY)
+                table.insert(txqueue, "close")
+                sys_send(taskName, socket.EVENT, 0)
+            end
+        end
+    end
+end
+
+
+
+function ipv6task(d1Name, txqueue, rxtopic)
+    -- 本地监听的端口
+    local port = 14000
+
+
+    local rx_buff = zbuff.create(1024)
+    local tx_buff = zbuff.create(4 * 1024)
+    local netc = socket.create(nil, d1Name)
+    socket.config(netc, 14000)
+    log.info("任务id", d1Name)
+
+    while true do
+        log.info("socket", "开始监控")
+        local result = libnet.listen(d1Name, 0, netc)
+        if result then
+			log.info("socket", "监听成功")
+            result = socket.accept(netc, nil)    --只支持1对1
+            if result then
+			    log.info("客户端连上了")
+            end
+        else
+            log.info("socket", "监听失败!!")
+		end
+		while result do
+            -- log.info("socket", "调用rx接收数据")
+			local succ, param = socket.rx(netc, rx_buff)
+			if not succ then
+				log.info("客户端断开了", succ, param, ip, port)
+				break
+			end
+			if rx_buff:used() > 0 then
+				log.info("socket", "收到客户端数据,长度", rx_buff:used())
+                local data = rx_buff:query() -- 获取数据
+                sys.publish(rxtopic, "downlink", data)
+				rx_buff:del()
+			end
+            -- log.info("libnet", "调用wait开始等待消息")
+			result, param, param2 = libnet.wait(d1Name, 15000, netc)
+            log.info("libnet", "wait", result, param, param2)
+			if not result then
+                -- 网络异常了
+				log.info("socket", "客户端断开了", result, param)
+				break
+            elseif #txqueue > 0 then
+                local force_close = false
+                while #txqueue > 0 do
+                    local data = table.remove(txqueue, 1)
+                    if not data then
+                        break
+                    end
+                    log.info("socket", "上行数据长度", #data)
+                    if data == "close" then
+                        --sys.wait(1000)
+                        force_close = true
+                        break
+                    end
+                    tx_buff:del()
+                    tx_buff:copy(nil, data)
+                    result,param = libnet.tx(d1Name, 15000, netc, tx_buff)
+                    log.info("libnet", "发送数据的结果", result, param)
+                    if not result then
+                        log.info("socket", "数据发送异常", result, param)
+                        break
+                    end
+                end
+                if force_close then
+                    break
+                end
+            end
+		end
+        log.info("socket", "连接已断开,继续下一个循环")
+		libnet.close(d1Name, 5000, netc)
+		-- log.info(rtos.meminfo("sys"))
+		sys.wait(50)
+    end
+end
+
+sys.taskInit(ipv6test)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 68 - 0
module/Air780E/demo/json/main.lua

@@ -0,0 +1,68 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "jsondemo"
+VERSION = "1.0.0"
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+
+log.info("main", PROJECT, VERSION)
+
+-- json库支持将 table 转为 字符串, 或者反过来, 字符串 转 table
+-- 若转换失败, 会返回nil值, 强烈建议在使用时添加额外的判断
+sys.taskInit(function()
+    while 1 do
+        sys.wait(1000)
+        -- table 转为 字符串
+        local t = {abc=123, def="123", ttt=true}
+        local jdata = json.encode(t)
+        log.info("json", jdata)
+
+        -- 字符串转table
+        local str = "{\"abc\":1234545}" -- 字符串可以来源于任何地方,网络,文本,用户输入,都可以
+        local t = json.decode(str)
+        if t then -- 若解码失败, 会返回nil
+            log.info("json", "decode", t.abc)
+        end
+
+        -- lua中的table是 数组和hashmap的混合体
+        -- 这对json来说会有一些困扰, 尤其是空的table
+        local t = {abc={}}
+        -- 假设从业务上需要输出 {"abc":[]}
+        -- 实际会输出 {"abc": {}} , 空table是优先输出 hashmap 形式, 而非数组形式
+        log.info("json", "encode", json.encode(t))
+        -- 混合场景, json场景应避免使用
+        t.abc.def = "123"
+        t.abc[1] = 345
+        -- 输出的内容是 {"abc":{"1":345,"def":"123"}}
+        log.info("json", "encode2", json.encode(t))
+
+        -- 浮点数演示
+        -- 默认%.7g
+        log.info("json", json.encode({abc=1234.300}))
+        -- 限制小数点到1位
+        log.info("json", json.encode({abc=1234.300}, "1f"))
+
+        -- 2023.6.8 处理\n在encode之后变成\b的问题
+        local tmp = "ABC\r\nDEF\r\n"
+        local tmp2 = json.encode({str=tmp})
+        log.info("json", tmp2)
+        local tmp3 = json.decode(tmp2)
+        log.info("json", "tmp3", tmp3.str, tmp3.str == tmp)
+        -- break
+
+        log.info("json.null", json.encode({name=json.null}))
+        log.info("json.null", json.decode("{\"abc\":null}").abc == json.null)
+        log.info("json.null", json.decode("{\"abc\":null}").abc == nil)
+
+        -- 以下代码仅64bit固件可正确运行
+        local tmp = [[{ "timestamp": 1691998307973}]]
+        local abc, err = json.decode(tmp)
+        log.info("json", abc, err)
+        log.info("json", abc and abc.timestamp)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 217 - 0
module/Air780E/demo/jt808/JT808Prot.lua

@@ -0,0 +1,217 @@
+local JT808Prot = {}
+local paraCtrl = require "paraCtrl"
+
+--终端消息ID
+JT808Prot.T_COMMON_RSP = 0x0001
+JT808Prot.T_LOC_RPT = 0x0200
+JT808Prot.T_HEART_RPT = 0x0002
+
+JT808Prot.PARA_HEART_FREQ = 0x0001
+JT808Prot.PARA_TCP_RSP_TIMEOUT = 0x0002
+JT808Prot.PARA_TCP_RESEND_CNT = 0x0003
+JT808Prot.PARA_LOC_RPT_STRATEGY = 0x0020
+JT808Prot.PARA_LOC_RPT_MODE = 0x0021
+JT808Prot.PARA_SLEEP_LOC_RPT_FREQ = 0x0027
+JT808Prot.PARA_ALARM_LOC_RPT_FREQ = 0x0028
+JT808Prot.PARA_WAKE_LOC_RPT_FREQ = 0x0029
+JT808Prot.PARA_WAKE_LOC_RPT_DISTANCE = 0x002C
+JT808Prot.PARA_SLEEP_LOC_RPT_DISTANCE = 0x002E
+JT808Prot.PARA_ALARM_LOC_RPT_DISTANCE = 0x002F
+JT808Prot.PARA_FENCE_RADIS = 0x0031
+JT808Prot.PARA_ALARM_FILTER = 0x0050
+JT808Prot.PARA_KEY_FLAG = 0x0054
+JT808Prot.PARA_SPEED_LIMIT = 0x0055
+JT808Prot.PARA_SPEED_EXCEED_TIME = 0x0056
+
+JT808Prot.CONTROL_RESET = 4
+
+--平台消息ID
+JT808Prot.S_COMMON_RSP = 0x8001
+JT808Prot.S_REGISTER_RSP = 0x8100
+JT808Prot.S_SET_PARA = 0x8103
+JT808Prot.S_CONTROL = 0x8105
+
+local tSendSeq = 0
+
+local function encodeBcdNum(d,n)
+    if d:len()<n then
+        return (string.rep("0",n-d:len())..d):fromHex()
+    else
+        return (d:sub(1,n)):fromHex()
+    end
+end
+
+local function calCrc(d)
+    local sum = 0
+    for i=1,d:len() do
+        sum = sum~d:byte(i)
+    end
+    return sum
+end
+
+--终端消息封包
+--返回值1:打包后的字符串
+--返回值2:流水号
+function JT808Prot.encode(msgId,...)
+
+    local function cmnRsp(svrSeq,svrId,result)
+        return pack.pack(">HHb",svrSeq,svrId,result)
+    end
+
+    local function locRpt(alarm,status,lat,lng,alt,spd,course,tm,extInfo)
+        -- return pack.pack(">ddddHHHAA",alarm,status,lat,lng,alt,spd,course,tm,extInfo)
+        return pack.pack(">ddddHHHAA",alarm,status,lat,lng,math.modf(alt),math.modf(spd),math.modf(course),tm,extInfo)
+    end
+
+    local procer =
+    {
+        [JT808Prot.T_COMMON_RSP] = cmnRsp,
+        [JT808Prot.T_LOC_RPT] = locRpt,
+        [JT808Prot.T_HEART_RPT] = function() return "" end,
+    }
+    local msgBody = procer[msgId](...)    --消息体
+
+
+
+    local msgHead = pack.pack(">HHAH",  --消息头
+                    msgId, --消息ID
+                    msgBody:len(), --消息体属性,暂未实现分包和数据加密
+                    encodeBcdNum(paraCtrl.getTerminalNum(),12), --终端手机号
+                    tSendSeq --消息流水号
+                    )
+    local curSeq = tSendSeq
+    tSendSeq = (tSendSeq==0xFFFF) and 0 or (tSendSeq+1)
+    --校验码
+    local crc = calCrc(msgHead..msgBody)
+
+    --转义
+    local s = msgHead..msgBody..string.char(crc)
+    s = s:gsub("\125","\125\1") -- 7D -> 7D 01
+    s = s:gsub("\126","\125\2") -- 7E -> 7D 02
+    return string.char(0x7E)..s..string.char(0x7E),curSeq
+end
+
+--返回值1:未处理的数据
+--返回值2:解析后的packet,解析失败为nil,解释成功为table类型,table中有一个boolean类型的result变量进一步表示结果
+function JT808Prot.decode(s)
+    local _,tail,msg = s:find("\126(.-)\126")
+    local decPacket,msgAttr = {}
+    if not msg then
+        log.warn("prot.decode","wait packet complete")
+        return s,nil
+    end
+
+    --反转义
+    msg = msg:gsub("\125\2","\126") -- 7D 02 -> 7E
+    msg = msg:gsub("\125\1","\125") -- 7D 01 -> 7D
+
+    if msg:len()<13 then
+        log.error("prot.decode","packet len is too short")
+        return s:sub(tail+1,-1),nil
+    end
+
+    --验证校验码
+    if calCrc(msg:sub(1,-2))~=msg:byte(-1) then
+        log.error("prot.decode","packet len is too short")
+        return s:sub(tail+1,-1),nil
+    end
+
+
+    --消息头和消息体
+    msg = msg:sub(1,-2)
+
+    --消息ID
+    _,decPacket.msgId = pack.unpack(msg,">H")
+
+    --消息流水号
+    decPacket.msgSeq = pack.unpack(msg,">H")
+
+    --消息体属性
+    _,msgAttr = pack.unpack(msg:sub(3,4),">H")
+    --分包标志
+    local msgMultiPacket = bit.isset(msgAttr,13)
+    --数据加密标志
+    local msgEncrypt = bit.band(bit.rshift(msgAttr,10),0x07)
+    --消息体长度
+    local msgLen = bit.band(msgAttr,0x03FF)
+
+    local msgBodyHead = msgMultiPacket and 17 or 13
+    local msgBody = msg:sub(msgBodyHead,-1)
+    decPacket.result = msgBody:len()==msgLen
+    if not decPacket.result then
+        log.error("prot.decode","body len no match")
+        return s:sub(tail+1,-1),decPacket
+    end
+
+    local function cmnRsp(body)
+        if body:len()~=5 then
+            log.error("prot.decode.cmnRsp","len~=5 error",body:len())
+            return false
+        end
+
+        _,decPacket.tmnlSeq,decPacket.tmnlId,decPacket.rspResult = pack.unpack(body,">HHb")
+    end
+
+    local function setPara(body)
+        if body:len()<5 then
+            log.error("prot.decode.setPara","len<5 error",body:len())
+            return false
+        end
+
+        local cnt,i = body.byte(1)
+        local tmp,id = body:sub(2,-1)
+        while tmp:len() > 0 do
+            _,id = pack.unpack(tmp,">i")
+            if not list[id] then
+                log.error("prot.decode.setPara","unsupport para",id)
+                return false
+            end
+            local paraLen = tmp:byte(5)
+            if tmp:len() < paraLen+5 then
+                log.error("prot.decode.setPara","para data incomplete",id)
+                return false
+            end
+            if not paraCtrl.setPara(id,paraLen,tmp:sub(6,5+paraLen)) then
+                log.error("prot.decode.setPara","para proc error",id)
+                return false
+            end
+            tmp = tmp:sub(6+tmpLen,-1)
+        end
+
+        return true
+    end
+
+    local function control(body)
+        if body:len()<1 then
+            log.error("prot.decode.control","len<1 error",body:len())
+            return false
+        end
+
+        decPacket.controlCmd = body:byte(1)
+        return true
+    end
+
+
+    local procer =
+    {
+        [JT808Prot.S_COMMON_RSP] = cmnRsp,
+        [JT808Prot.S_SET_PARA] = setPara,
+        [JT808Prot.S_CONTROL] = control,
+    }
+
+    if not procer[decPacket.msgId] then
+        log.error("prot.decode","invalid id",decPacket.msgId)
+        decPacket.result = false
+        return s:sub(tail+1,-1),decPacket
+    end
+
+
+    if procer[decPacket.msgId](msgBody)==false then
+        log.error("prot.decode","procer fail")
+        decPacket.result = false
+    end
+
+    return s:sub(tail+1,-1),decPacket
+end
+
+return JT808Prot

+ 89 - 0
module/Air780E/demo/jt808/gpsMng.lua

@@ -0,0 +1,89 @@
+local gpsMng = {}
+
+local gps_uart_id = 2
+
+libgnss.clear() -- 清空数据,兼初始化
+
+uart.setup(gps_uart_id, 115200)
+
+function exec_agnss()
+    if http then
+        -- AGNSS 已调通
+        while 1 do
+            local code, headers, body = http.request("GET", "http://download.openluat.com/9501-xingli/HXXT_GPS_BDS_AGNSS_DATA.dat").wait()
+            -- local code, headers, body = http.request("GET", "http://nutzam.com/6228.bin").wait()
+            log.info("gnss", "AGNSS", code, body and #body or 0)
+            if code == 200 and body and #body > 1024 then
+                -- uart.write(gps_uart_id, "$reset,0,h01\r\n")
+                -- sys.wait(200)
+                -- uart.write(gps_uart_id, body)
+                for offset=1,#body,512 do
+                    log.info("gnss", "AGNSS", "write >>>", #body:sub(offset, offset + 511))
+                    uart.write(gps_uart_id, body:sub(offset, offset + 511))
+                    sys.wait(100) -- 等100ms反而更成功
+                end
+                io.writeFile("/6228.bin", body)
+                break
+            end
+            sys.wait(60*1000)
+        end
+    end
+    sys.wait(20)
+    -- 读取之前的位置信息
+    local gnssloc = io.readFile("/gnssloc")
+    if gnssloc then
+        str = "$AIDPOS," .. gnssloc
+        log.info("POS", str)
+        uart.write(gps_uart_id, str .. "\r\n")
+        str = nil
+        gnssloc = nil
+    else
+        -- TODO 发起基站定位
+        uart.write(gps_uart_id, "$AIDPOS,3432.70,N,10885.25,E,1.0\r\n")
+    end
+end
+sys.taskInit(function()
+    -- Air780EG工程样品的GPS的默认波特率是9600, 量产版是115200,以下是临时代码
+    log.info("GPS", "start")
+    pm.power(pm.GPS, true)
+    -- 绑定uart,底层自动处理GNSS数据
+    -- 第二个参数是转发到虚拟UART, 方便上位机分析
+    libgnss.bind(gps_uart_id, uart.VUART_0)
+    -- libgnss.on("raw", function(data)
+    --     -- 默认不上报, 需要的话自行打开
+    --     data = data:split("\r\n")
+    --     if data == nil then
+    --         return
+    --     end
+    -- end)
+    sys.wait(200) -- GPNSS芯片启动需要时间
+    -- 调试日志,可选
+    -- libgnss.debug(true)
+    -- 显示串口配置
+    -- uart.write(gps_uart_id, "$CFGPRT,1\r\n")
+    -- sys.wait(20)
+    -- 增加显示的语句
+    -- uart.write(gps_uart_id, "$CFGMSG,0,1,1\r\n") -- GLL
+    -- sys.wait(20)
+    -- uart.write(gps_uart_id, "$CFGMSG,0,5,1\r\n") -- VTG
+    -- sys.wait(20)
+    -- uart.write(gps_uart_id, "$CFGMSG,0,6,1\r\n") -- ZDA
+    -- sys.wait(20)
+    exec_agnss()
+end)
+
+sys.taskInit(function ()
+    while true do
+        log.info("nmea", "isFix", libgnss.isFix())
+        sys.wait(10000)
+    end
+
+end)
+
+--获取时间
+function gpsMng.getTime()
+    local tTime = libgnss.getZda()
+    return (string.format("%02d%02d%02d%02d%02d%02d",tTime.year-2000,tTime.month,tTime.day,tTime.hour+8,tTime.min,tTime.sec)):fromHex()
+end
+
+return gpsMng

+ 83 - 0
module/Air780E/demo/jt808/main.lua

@@ -0,0 +1,83 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "my_test"
+VERSION = "1.2"
+PRODUCT_KEY = " " --自己iot平台下的PRODUCT_KEY
+-- sys库是标配
+_G.sys = require("sys")
+_G.sysplus = require("sysplus")
+
+--[[本demo实现了jt808协议的基本框架,可以通过tcp上报位置信息和心跳包,后续功能可按照此框架添加即可;
+    使用前需修改下tcp的ip地址和端口;
+    如果是780eg模块,可以直接烧录,如果是780e外挂定位模块,需要注意串口号!]]--
+----------------------------------------
+-- 报错信息自动上报到平台,默认是iot.openluat.com
+-- 支持自定义, 详细配置请查阅API手册
+-- 开启后会上报开机原因, 这需要消耗流量,请留意
+if errDump then
+    errDump.config(true, 600)
+end
+----------------------------------------
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+-- 如果运营商自带的DNS不好用,可以用下面的公用DNS
+-- socket.setDNS(nil,1,"223.5.5.5")
+-- socket.setDNS(nil,2,"114.114.114.114")
+
+-- socket.sntp()
+--socket.sntp("ntp.aliyun.com") --自定义sntp服务器地址
+--socket.sntp({"ntp.aliyun.com","ntp1.aliyun.com","ntp2.aliyun.com"}) --sntp自定义服务器地址
+-- sys.subscribe("NTP_UPDATE", function()
+--     log.info("sntp", "time", os.date())
+-- end)
+-- sys.subscribe("NTP_ERROR", function()
+--     log.info("socket", "sntp error")
+--     socket.sntp()
+-- end)
+
+-----------------------------------------------------------------------------------------------------------------
+sys.taskInit(function()
+    -- 检查一下当前固件是否支持fskv
+    if not fskv then
+        while true do
+            log.info("fskv", "this demo need fskv")
+            sys.wait(1000)
+        end
+    end
+
+    -- 初始化kv数据库
+    fskv.init()
+    fskv.set("authCode", " ")  --注册成功后的鉴权码
+    fskv.set("heartFreq",60)  --心跳上报间隔,单位秒
+    fskv.set("tcpSndTimeout",10)  --TCP等待应答超时时间,单位秒
+    fskv.set("tcpResendMaxCnt", 3)  --TCP重传次数
+    fskv.set("locRptStrategy", 0)   --位置汇报策略,0:定时汇报;1:定距汇报;2:定时和定距汇报
+    fskv.set("locRptMode",0)      --位置汇报方案,0:根据 ACC 状态; 1:根据登录状态和 ACC 状态,先判断登录状态,若登录再根据 ACC 状态
+    fskv.set("sleepLocRptFreq", 60)   --休眠时位置汇报时间间隔,单位为秒
+    fskv.set("alarmLocRptFreq",5)  --紧急报警时位置汇报时间间隔,单位为秒
+    fskv.set("wakeLocRptFreq", 20)   --缺省位置汇报时间间隔,单位为秒
+    fskv.set("sleepLocRptDistance", 500)    --休眠时汇报距离间隔,单位为米
+    fskv.set("alarmLocRptDistance", 5)     --紧急报警时位置汇报时间间隔,单位为米
+    fskv.set("wakeLocRptDistance", 50)    --缺省位置汇报时间间隔,单位为米
+    fskv.set("fenceRadis", 100)     --电子围栏半径,单位为米
+    fskv.set("alarmFilter",0)    --报警屏蔽字,与位置汇报消息中的报警标志相对应,相应位为 1,则相应报警被屏蔽
+    fskv.set("keyFlag", 0)   --关键标志,与位置信息汇报消息中的报警标志相对应,相应位为 1 则对相应报警为关键报警
+    fskv.set("speedLimit", 100)  --最高速度,单位为公里每小时(km/h)
+    fskv.set("speedExceedTime", 60)   --超速持续时间,单位为秒(s)
+end)
+
+-------------------------------------------------------------------------------------------------------------
+
+local gpsMng = require "gpsMng"
+require "JT808Prot"
+require "socket_demo"
+-- dtuDemo("112.125.89.8",35960)
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 86 - 0
module/Air780E/demo/jt808/paraCtrl.lua

@@ -0,0 +1,86 @@
+local paraCtrl = {}
+
+--终端自身的手机号码
+function paraCtrl.getTerminalNum()
+    return "13937000000"
+end
+
+
+--省域ID
+function paraCtrl.getProvinceId()
+    return 0
+end
+
+--区县ID
+function paraCtrl.getCityId()
+    return 0
+end
+
+--制造商ID
+function paraCtrl.getManufactureId()
+    return "00001"
+end
+
+--终端型号
+function paraCtrl.getTerminalModule()
+    return "GT808"..string.rep(string.char(0),20-("GT808"):len())
+end
+
+--终端ID
+function paraCtrl.getTerminalId()
+    --return ("12341234001".."000"):fromHex()
+    return ("00000000000000"):fromHex()
+end
+
+--车辆颜色
+function paraCtrl.getCarColor()
+    return 0
+end
+
+--车辆标识
+function paraCtrl.getCarNumber()
+    return "41048063212"
+end
+
+
+
+
+function paraCtrl.setPara(id,len,data)
+    local value
+    if len==1 then
+        value = data:byte(1)
+    elseif len==2 then
+        _,value = pack.unpack(data,">H")
+    elseif len==4 then
+        _,value = pack.unpack(data,">i")
+    end
+
+    local numberPara =
+    {
+        [JT808Prot.PARA_HEART_FREQ] = "heartFreq",
+        [JT808Prot.PARA_TCP_RSP_TIMEOUT] = "tcpSndTimeout",
+        [JT808Prot.PARA_TCP_RESEND_CNT] = "tcpResendMaxCnt",
+        [JT808Prot.PARA_LOC_RPT_STRATEGY] = "locRptStrategy",
+        [JT808Prot.PARA_LOC_RPT_MODE] = "locRptMode",
+        [JT808Prot.PARA_SLEEP_LOC_RPT_FREQ] = "sleepLocRptFreq",
+        [JT808Prot.PARA_ALARM_LOC_RPT_FREQ] = "alarmLocRptFreq",
+        [JT808Prot.PARA_WAKE_LOC_RPT_FREQ] = "wakeLocRptFreq",
+        [JT808Prot.PARA_WAKE_LOC_RPT_DISTANCE] = "sleepLocRptDistance",
+        [JT808Prot.PARA_SLEEP_LOC_RPT_DISTANCE] = "alarmLocRptDistance",
+        [JT808Prot.PARA_ALARM_LOC_RPT_DISTANCE] = "wakeLocRptDistance",
+        [JT808Prot.PARA_FENCE_RADIS] = "fenceRadis",
+        [JT808Prot.PARA_ALARM_FILTER] = "alarmFilter",
+        [JT808Prot.PARA_KEY_FLAG] = "keyFlag",
+        [JT808Prot.PARA_SPEED_LIMIT] = "speedLimit",
+        [JT808Prot.PARA_SPEED_EXCEED_TIME] = "speedExceedTime",
+    }
+
+    if numberPara[id] then
+        fskv.set(numberPara[id],value)
+        return true
+    end
+
+    return false
+end
+
+return paraCtrl

+ 211 - 0
module/Air780E/demo/jt808/socket_demo.lua

@@ -0,0 +1,211 @@
+local libnet = require "libnet"
+local JT808Prot = require "JT808Prot"
+local gpsMng = require "gpsMng"
+
+
+local d1Online = false
+local d1Name = "D1_TASK"
+local tx_buff = zbuff.create(1024)
+local rx_buff = zbuff.create(1024)
+local ip, port="112.125.89.8", 40042
+
+local function netCB(msg)
+	log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+end
+
+--数据发送的消息队列
+local msgQuene = {}
+function insertMsg(data,user)
+    table.insert(msgQuene,{data=data,user=user})
+    return true
+end
+ --终端通用应答
+function T_commonRsp(seq,id,result,cbFnc)
+    local data = JT808Prot.encode(JT808Prot.T_COMMON_RSP,seq,id,result and 0 or 1)
+    if not insertMsg(data,{cb=function(r) log.info("socketOutMsg.commonRsp","send result",r) cbFnc(r) end}) then
+        if cbFnc then cbFnc(false) end
+    end
+end
+
+--位置上报task
+local coLocRpt
+function createLocRptTask()
+	return sys.taskInit(function()
+		log.info("libgnss.isFix()", libgnss.isFix())
+		while true do
+			if libgnss.isFix() then
+				local tLocation = libgnss.getRmc(2)
+				local lat = tLocation.lat*1000000
+				local lng = tLocation.lng*1000000
+				local spd = tLocation.speed
+				local speed = (spd*1852 - (spd*1852 %1000))/1000
+				local Course = tLocation.course
+				local gga = libgnss.getGga(2)
+				local altitude=gga.altitude
+				-- log.info("发送位置信息.locRpt", lat, lng)
+				local data, seq = JT808Prot.encode(JT808Prot.T_LOC_RPT,
+					0,
+					0,
+					tonumber(lat),
+					tonumber(lng),
+					altitude, --海拔
+					speed,            --速度
+					Course,  --方向
+					gpsMng.getTime(),
+					"")
+				log.info(" 打包后的字符串和流水号LocRpt", data, seq)
+				if insertMsg(data, { cb = function(r)
+						log.info("socketOutMsg.locRpt位置上报", "send result", r)
+						sys.publish("SEND_LOC_RPT_CNF", r)
+					end }) then
+					sys.waitUntil("SEND_LOC_RPT_CNF")
+				end
+			else
+				log.info("定位失败,位置上报失败")
+			end
+			sys.wait(fskv.get("wakeLocRptFreq") * 1000)
+		end
+	end)
+end
+
+--心跳上报task
+local coHeartRpt
+function createHeartRptTask()
+	return sys.taskInit(function()
+		while true do
+			local data, seq = JT808Prot.encode(JT808Prot.T_HEART_RPT)
+			log.info(" 打包后的字符串和流水号Heart", data, seq)
+			if insertMsg(data, { cb = function(r)
+					log.info("发送心跳信息.heartRpt", "send result", r)
+					sys.publish("SEND_HEART_RPT_CNF", r)
+				end }) then
+				sys.waitUntil("SEND_HEART_RPT_CNF")
+			end
+			sys.wait(fskv.get("heartFreq") * 1000)
+		end
+	end)
+end
+
+--平台通用应答
+local function s_commonRsp(packet)
+    log.info("s_commonRsp",packet.tmnlSeq,packet.tmnlId,packet.rspResult)
+    coroutine.resume(socketTask.coMonitor,'feed monitor')
+end
+--设置终端参数
+local function s_setPara(packet)
+    log.info("s_setPara",packet.result,packet.msgSeq,packet.msgId)
+    T_commonRsp(packet.msgSeq,packet.msgId,packet.result)
+end
+--终端控制
+local function s_control(packet)
+    log.info("s_control",packet.controlCmd,packet.result,packet.msgSeq,packet.msgId)
+    T_commonRsp(packet.msgSeq,packet.msgId,packet.result,function(r)
+        if packet.controlCmd==JT808Prot.CONTROL_RESET then
+            sys.timerStart(sys.restart,2000,"server control reset")
+        end
+    end)
+end
+local cmds =
+{
+    [JT808Prot.S_COMMON_RSP] = s_commonRsp,  --平台通用应答
+    [JT808Prot.S_SET_PARA] = s_setPara,   --设置终端参数
+    [JT808Prot.S_CONTROL] = s_control,     --终端控制
+}
+
+local tCache = {}
+--tcp接收数据处理函数
+function inproc(data)
+	table.insert(tCache, data)
+	local cacheData = table.concat(tCache) --连接字符串
+	tCache = {}
+	while cacheData:len() > 0 do
+		local unProcData, packet = JT808Prot.decode(cacheData)
+		cacheData = unProcData or ""
+		if packet then
+			if packet.msgId and cmds[packet.msgId] and packet.result then
+				cmds[packet.msgId](packet)
+			else
+				log.warn("inproc", "invalid packet")
+			end
+		else
+			if cacheData:len() > 0 then
+				table.insert(tCache, 1, cacheData)
+				sys.timerStart(function() tCache = {} end, 10000)
+			end
+			break
+		end
+	end
+end
+
+
+
+local function socketTask(ip, port)
+	local netc
+	local result, param, is_err
+
+	netc = socket.create(nil, d1Name)
+	-- socket.debug(netc, true)
+	socket.config(netc, nil, nil, nil)
+	-- socket.config(netc, nil, true)
+	while true do
+		-- log.info(rtos.meminfo("sys"))
+		--result = libnet.waitLink(d1Name, 0, netc)
+		result = libnet.connect(d1Name, 15000, netc, ip, port)
+		-- result = libnet.connect(d1Name, 5000, netc, "112.125.89.8",34607)
+		d1Online = result
+		if result then
+			log.info("服务器连上了")
+			createLocRptTask()
+			createHeartRptTask()
+		end
+		while result do
+			succ, param, _, _ = socket.rx(netc, rx_buff)
+			if not succ then
+				log.info("服务器断开了", succ, param, ip, port)
+				break
+			end
+			if rx_buff:used() > 0 then
+				log.info("收到服务器数据,长度", rx_buff:used())
+				inproc(rx_buff:toStr(0, rx_buff:used()))  --读出接收数据并处理
+				rx_buff:del()
+			end
+			while #msgQuene>0 do
+				local outMsg = table.remove(msgQuene,1)
+				tx_buff:write(outMsg.data)
+				if tx_buff:used() > 0 then
+					result, param = libnet.tx(d1Name, 15000, netc, tx_buff)
+					log.info("发送结果", result)
+				end
+				if not result then
+					log.info("发送失败了", result )
+					break
+				end
+				if outMsg.user and outMsg.user.cb then outMsg.user.cb(result,outMsg.data,outMsg.user.para) end
+				if not result then return end
+				tx_buff:del()
+			end
+			if tx_buff:len() > 1024 then
+				tx_buff:resize(1024)
+			end
+			if rx_buff:len() > 1024 then
+				rx_buff:resize(1024)
+			end
+			-- 阻塞等待新的消息到来,比如服务器下发,串口接收到数据
+			result, param = libnet.wait(d1Name, 1000, netc)
+			if not result then
+				log.info("服务器断开了", result, param)
+				break
+			end
+		end
+		d1Online = false
+		libnet.close(d1Name, 5000, netc)
+		tx_buff:clear(0)
+		rx_buff:clear(0)
+		sys.wait(1000)
+	end
+end
+
+
+sysplus.taskInitEx(socketTask, d1Name, netCB, ip, port)
+
+

+ 95 - 0
module/Air780E/demo/lbsLoc/main.lua

@@ -0,0 +1,95 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lbsLocdemo"
+VERSION = "1.0.0"
+
+--注意:因使用了sys.wait()所有api需要在协程中使用
+
+--[[注意:此处的PRODUCT_KEY仅供演示使用,不保证一直能用,量产项目中一定要使用自己在iot.openluat.com中创建的项目productKey]]
+PRODUCT_KEY = ""
+
+--[[本demo需要lbsLoc库与libnet库, 库位于script\libs, 需require]]
+local lbsLoc = require("lbsLoc")
+
+-- sys库是标配
+_G.sys = require("sys")
+--[[特别注意, 使用lbsLoc库需要下列语句]]
+_G.sysplus = require("sysplus")
+
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+
+-- 功能:获取基站对应的经纬度后的回调函数
+-- 参数:-- result:number类型,0表示成功,1表示网络环境尚未就绪,2表示连接服务器失败,3表示发送数据失败,4表示接收服务器应答超时,5表示服务器返回查询失败;为0时,后面的5个参数才有意义
+		-- lat:string类型,纬度,整数部分3位,小数部分7位,例如031.2425864
+		-- lng:string类型,经度,整数部分3位,小数部分7位,例如121.4736522
+        -- addr:目前无意义
+        -- time:string类型或者nil,服务器返回的时间,6个字节,年月日时分秒,需要转为十六进制读取
+            -- 第一个字节:年减去2000,例如2017年,则为0x11
+            -- 第二个字节:月,例如7月则为0x07,12月则为0x0C
+            -- 第三个字节:日,例如11日则为0x0B
+            -- 第四个字节:时,例如18时则为0x12
+            -- 第五个字节:分,例如59分则为0x3B
+            -- 第六个字节:秒,例如48秒则为0x30
+        -- locType:numble类型或者nil,定位类型,0表示基站定位成功,255表示WIFI定位成功
+local function getLocCb(result, lat, lng, addr, time, locType)
+    log.info("testLbsLoc.getLocCb", result, lat, lng)
+    -- 获取经纬度成功
+    if result == 0 then
+        log.info("服务器返回的时间", time:toHex())
+        log.info("定位类型,基站定位成功返回0", locType)
+    end
+    -- 广播给其他需要定位数据的task
+    -- sys.publish("lbsloc_result", result, lat, lng)
+end
+
+sys.taskInit(function()
+    sys.waitUntil("IP_READY", 30000)
+    while 1 do
+        mobile.reqCellInfo(15)
+        sys.waitUntil("CELL_INFO_UPDATE", 3000)
+        lbsLoc.request(getLocCb)
+        sys.wait(60000)
+    end
+end)
+
+-- -- 以下为基站+wifi混合定位
+-- 注意, 免费版的基站+wifi混合定位,大部分情况下只会返回基站定位的结果
+-- 收费版本请咨询销售
+-- sys.subscribe("WLAN_SCAN_DONE", function ()
+--     local results = wlan.scanResult()
+--     log.info("scan", "results", #results)
+--     if #results > 0 then
+--         local reqWifi = {}
+--         for k,v in pairs(results) do
+--             log.info("scan", v["ssid"], v["rssi"], v["bssid"]:toHex())
+--             local bssid = v["bssid"]:toHex()
+--             bssid = string.format ("%s:%s:%s:%s:%s:%s", bssid:sub(1,2), bssid:sub(3,4), bssid:sub(5,6), bssid:sub(7,8), bssid:sub(9,10), bssid:sub(11,12))
+--             reqWifi[bssid]=v["rssi"]
+--         end
+--         lbsLoc.request(getLocCb,nil,nil,nil,nil,nil,nil,reqWifi)
+--     else
+--         lbsLoc.request(getLocCb) -- 没有wifi数据,进行普通定位
+--     end
+-- end)
+
+-- sys.taskInit(function()
+--     sys.waitUntil("IP_READY", 30000)
+--     wlan.init()
+--     while 1 do
+--         mobile.reqCellInfo(15)
+--         sys.waitUntil("CELL_INFO_UPDATE", 3000)
+--         wlan.scan()
+--         sys.wait(60000)
+--     end
+-- end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 35 - 0
module/Air780E/demo/lbsLoc2/main.lua

@@ -0,0 +1,35 @@
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lbsLoc2demo"
+VERSION = "1.0.0"
+
+
+-- sys库是标配
+sys = require("sys")
+
+local lbsLoc2 = require("lbsLoc2")
+
+-- Air780E的AT固件默认会为开机键防抖, 导致部分用户刷机很麻烦
+if rtos.bsp() == "EC618" and pm and pm.PWK_MODE then
+    pm.power(pm.PWK_MODE, false)
+end
+
+sys.taskInit(function()
+    sys.waitUntil("IP_READY", 30000)
+    -- mobile.reqCellInfo(60)
+    -- sys.wait(1000)
+    while mobile do -- 没有mobile库就没有基站定位
+        mobile.reqCellInfo(15)--进行基站扫描
+        sys.waitUntil("CELL_INFO_UPDATE", 3000)--等到扫描成功,超时时间3S
+        local lat, lng, t = lbsLoc2.request(5000)--仅需要基站定位给出的经纬度
+        --local lat, lng, t = lbsLoc2.request(5000,nil,nil,true)--需要经纬度和当前时间
+        --(时间格式{"year":2024,"min":56,"month":11,"day":12,"sec":44,"hour":14})
+        log.info("lbsLoc2", lat, lng, (json.encode(t or {})))
+        sys.wait(60000)
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

BIN
module/Air780E/demo/lcd/logo.jpg


+ 101 - 0
module/Air780E/demo/lcd/main.lua

@@ -0,0 +1,101 @@
+--- 模块功能:lcddemo
+-- @module lcd
+-- @author Dozingfiretruck
+-- @release 2021.01.25
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lcddemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+
+--[[
+-- LCD接法示例
+LCD管脚       Air780E管脚   
+GND          GND          
+VCC          3.3V       
+SCL          (GPIO11) 
+SDA          (GPIO09)
+RES          (GPIO01)
+DC           (GPIO10)       
+CS           (GPIO08) 
+BL(可以不接)  (GPIO22)          
+
+
+提示:
+1. 只使用SPI的时钟线(SCK)和数据输出线(MOSI), 其他均为GPIO脚
+2. 数据输入(MISO)和片选(CS), 虽然是SPI, 但已复用为GPIO, 并非固定,是可以自由修改成其他脚
+3. 若使用多个SPI设备, 那么RES/CS请选用非SPI功能脚
+4. BL可以不接的, 若使用Air10x屏幕扩展板,对准排针插上即可
+]]
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+-- spi_id,pin_reset,pin_dc,pin_cs,bl
+function lcd_pin()
+    return 0,1,10,8,22  --Air780E
+end
+
+local spi_id,pin_reset,pin_dc,pin_cs,bl = lcd_pin() 
+
+if spi_id ~= lcd.HWID_0 then
+    spi_lcd = spi.deviceSetup(spi_id,pin_cs,0,0,8,20*1000*1000,spi.MSB,1,0)
+    port = "device"
+else
+    port = spi_id
+end
+
+    --[[ 此为合宙售卖的1.8寸TFT LCD LCD 分辨率:128X160 屏幕ic:st7735 购买地址:https://item.taobao.com/item.htm?spm=a1z10.5-c.w4002-24045920841.19.6c2275a1Pa8F9o&id=560176729178]]
+    lcd.init("st7735",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 128,h = 160,xoffset = 0,yoffset = 0},spi_lcd)
+    
+    --[[ 此为合宙售卖的0.96寸TFT LCD LCD 分辨率:160X80 屏幕ic:st7735s 购买地址:https://item.taobao.com/item.htm?id=661054472686]]
+    --lcd.init("st7735v",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 1,w = 160,h = 80,xoffset = 0,yoffset = 24},spi_lcd)
+    
+    --[[ 此为合宙售卖的ec718系列专用硬件双data驱动TFT LCD LCD 分辨率:320x480 屏幕ic:nv3037 购买地址:https://item.taobao.com/item.htm?id=764253232987&skuId=5258482696347&spm=a1z10.1-c-s.w4004-24087038454.8.64961170w5EdoA]]
+    -- lcd.init("nv3037",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 320,h = 480,xoffset = 0,yoffset = 0,interface_mode=lcd.DATA_2_LANE},spi_lcd)
+    
+    -- lcd.init("st7789",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 0,w = 240,h = 320,xoffset = 0,yoffset = 0},spi_lcd)
+
+    --如果显示颜色相反,请解开下面一行的注释,关闭反色
+    --lcd.invoff()
+    --0.96寸TFT如果显示依旧不正常,可以尝试老版本的板子的驱动
+    -- lcd.init("st7735s",{port = port,pin_dc = pin_dc, pin_pwr = bl, pin_rst = pin_reset,direction = 2,w = 160,h = 80,xoffset = 0,yoffset = 0},spi_lcd)
+
+-- 不在内置驱动的, 看demo/lcd_custom
+
+sys.taskInit(function()
+    -- 开启缓冲区, 刷屏速度回加快, 但也消耗2倍屏幕分辨率的内存
+    -- lcd.setupBuff()          -- 使用lua内存
+    -- lcd.setupBuff(nil, true) -- 使用sys内存, 只需要选一种
+    -- lcd.autoFlush(false)
+
+    while 1 do 
+        lcd.clear()
+        log.info("wiki", "https://wiki.luatos.com/api/lcd.html")
+        -- API 文档 https://wiki.luatos.com/api/lcd.html
+        if lcd.showImage then
+            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
+            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
+            lcd.showImage(40,0,"/luadb/logo.jpg")
+            sys.wait(100)
+        end
+        log.info("lcd.drawLine", lcd.drawLine(20,20,150,20,0x001F))
+        log.info("lcd.drawRectangle", lcd.drawRectangle(20,40,120,70,0xF800))
+        log.info("lcd.drawCircle", lcd.drawCircle(50,50,20,0x0CE0))
+        sys.wait(1000)
+    end
+end)
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 141 - 0
module/Air780E/demo/lcd_custom/main.lua

@@ -0,0 +1,141 @@
+--- 模块功能:lcddemo
+-- @module lcd
+-- @author Dozingfiretruck
+-- @release 2021.01.25
+
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "lcddemo"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+_G.sys = require("sys")
+
+--添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000)--初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
+end
+
+--[[
+    ===============================================
+    ===============================================
+    ===============================================
+    这个demo必须修改才能运行, 把注释看完 特别主要:2023.11.29之后要自定义方向命令,即 direction0 direction90 direction180 direction270,使用哪个方向给哪个就好
+    ===============================================
+    ===============================================
+    ===============================================
+]]
+
+-- spi_id,pin_reset,pin_dc,pin_cs,bl
+local function lcd_pin()
+    return 0,1,10,8,22
+end
+
+local spi_id,pin_reset,pin_dc,pin_cs,bl = lcd_pin() 
+
+if spi_id ~= lcd.HWID_0 then
+    spi_lcd = spi.deviceSetup(spi_id,pin_cs,0,0,8,20*1000*1000,spi.MSB,1,0)
+    port = "device"
+else
+    port = spi_id
+end
+
+--[[ 下面为custom方式示例,自己传入lcd指令来实现驱动,示例以st7735s做展示 ]]
+--[[ 注意修改下面的pin_xx对应的gpio信息, 数值与pin.XXX 均可]]
+--[[
+    initcmd的含义, 分3种指令, 每个指令都是int32, 前2个字节是命令, 后2个字节是值
+    0001 delay      延时,   例如 0x00010002 , 延时2ms
+    0000/0002 cmd   发命令, 例如 0x0002004
+    0003 data       发数据, 例如 0x0003004
+]]
+
+-- lcd.init("custom",{
+--     port = port,
+--     pin_dc = pin_dc, 
+--     pin_pwr = bl,
+--     pin_rst = pin_reset,
+--     direction = 0,
+--     direction0 = 0x08,
+--     w = 128,
+--     h = 160,
+--     xoffset = 2,
+--     yoffset = 1,
+--     sleepcmd = 0x10,
+--     wakecmd = 0x11,
+--     initcmd = {
+--         0x00020011,0x00010078,0x00020021, -- 反显
+--         0x000200B1,0x00030002,0x00030035,
+--         0x00030036,0x000200B2,0x00030002,
+--         0x00030035,0x00030036,0x000200B3,
+--         0x00030002,0x00030035,0x00030036,
+--         0x00030002,0x00030035,0x00030036,
+--         0x000200B4,0x00030007,0x000200C0,
+--         0x000300A2,0x00030002,0x00030084,
+--         0x000200C1,0x000300C5,0x000200C2,
+--         0x0003000A,0x00030000,0x000200C3,
+--         0x0003008A,0x0003002A,0x000200C4,
+--         0x0003008A,0x000300EE,0x000200C5,
+--         0x0003000E,0x00020036,0x000300C0,
+--         0x000200E0,0x00030012,0x0003001C,
+--         0x00030010,0x00030018,0x00030033,
+--         0x0003002C,0x00030025,0x00030028,
+--         0x00030028,0x00030027,0x0003002F,
+--         0x0003003C,0x00030000,0x00030003,
+--         0x00030003,0x00030010,0x000200E1,
+--         0x00030012,0x0003001C,0x00030010,
+--         0x00030018,0x0003002D,0x00030028,
+--         0x00030023,0x00030028,0x00030028,
+--         0x00030026,0x0003002F,0x0003003B,
+--         0x00030000,0x00030003,0x00030003,
+--         0x00030010,0x0002003A,0x00030005,
+--         0x00020029,
+--     },
+-- },
+-- spi_lcd)
+
+--[[ 下面为custom方式示例,自己传入lcd指令来实现驱动,示例以st7789做展示 ]]
+-- lcd.init("custom",{
+--     port = port,
+--     pin_dc = pin_dc, 
+--     pin_pwr = bl,
+--     pin_rst = pin_reset,
+--     direction = 0,
+--     direction0 = 0x00,
+--     w = 240,
+--     h = 320,
+--     xoffset = 0,
+--     yoffset = 0,
+--     sleepcmd = 0x10,
+--     wakecmd = 0x11,
+--     initcmd = {--0001 delay  0002 cmd  0003 data
+--         0x02003A,0x030005,
+--         0x0200B2,0x03000C,0x03000C,0x030000,0x030033,0x030033,
+--         0x0200B7,0x030035,
+--         0x0200BB,0x030032,
+--         0x0200C2,0x030001,
+--         0x0200C3,0x030015,
+--         0x0200C4,0x030020,
+--         0x0200C6,0x03000F,
+--         0x0200D0,0x0300A4,0x0300A1,
+--         0x0200E0,0x0300D0,0x030008,0x03000E,0x030009,0x030009,0x030005,0x030031,0x030033,0x030048,0x030017,0x030014,0x030015,0x030031,0x030034,
+--         0x0200E1,0x0300D0,0x030008,0x03000E,0x030009,0x030009,0x030015,0x030031,0x030033,0x030048,0x030017,0x030014,0x030015,0x030031,0x030034,
+--         0x00020021, -- 如果发现屏幕反色,注释掉此行
+--     },
+--     },
+--     spi_lcd)
+
+sys.taskInit(function() 
+    sys.wait(500)
+
+    log.info("lcd.drawLine", lcd.drawLine(20, 20, 150, 20, 0x001F))
+    log.info("lcd.drawRectangle", lcd.drawRectangle(20, 40, 120, 70, 0xF800))
+    log.info("lcd.drawCircle", lcd.drawCircle(50, 50, 20, 0x0CE0))
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

Некоторые файлы не были показаны из-за большого количества измененных файлов