Răsfoiți Sursa

add:提交Air780EPM代码到LuatOS文件下的Module下的Air780EPM文件夹

陆相成 10 luni în urmă
părinte
comite
2635fafce5
100 a modificat fișierele cu 3452 adăugiri și 0 ștergeri
  1. 21 0
      module/Air780EPM/LICENSE
  2. 36 0
      module/Air780EPM/README.en.md
  3. 23 0
      module/Air780EPM/README.md
  4. BIN
      module/Air780EPM/core/LuatOS-SoC_V2003_Air780EPM/LuatOS-SoC_V2003_Air780EPM.soc
  5. 32 0
      module/Air780EPM/core/LuatOS-SoC_V2003_Air780EPM/release_note.txt
  6. BIN
      module/Air780EPM/core/LuatOS-SoC_V2004_Air780EPM.soc
  7. BIN
      module/Air780EPM/core/LuatOS-SoC_V2005_Air780EPM.soc
  8. 32 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/adc780epm.lua
  9. 24 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/bf30a2.lua
  10. 189 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/camera780epm.lua
  11. 53 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gc0310.lua
  12. 58 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gc032a.lua
  13. 26 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gpio780epm.lua
  14. 75 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/lcd7796.lua
  15. BIN
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/logo.jpg
  16. 44 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/loopback.lua
  17. 30 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/main.lua
  18. 85 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/modbus780epm.lua
  19. 260 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/modbus_rtu.lua
  20. 20 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/pwm780epm.lua
  21. 24 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/uart2_setup.lua
  22. 29 0
      module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/uart3_setup.lua
  23. 17 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/airbuzzer.lua
  24. 55 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/airlcd.lua
  25. 94 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/camera780epm_simple.lua
  26. 60 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/can_test.lua
  27. 53 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/gc0310.lua
  28. 335 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/main.lua
  29. 233 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/russia.lua
  30. 140 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/statusbar.lua
  31. 35 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/test_wlan.lua
  32. 47 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/wlan_http.lua
  33. 52 0
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/json/pins_Air780EPM.json
  34. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/485test.jpg
  35. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D1.jpg
  36. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D2.jpg
  37. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D3.jpg
  38. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D4.jpg
  39. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D5.jpg
  40. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D6.jpg
  41. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D7.jpg
  42. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D8.jpg
  43. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D9.jpg
  44. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Dbottom.jpg
  45. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Dtop.jpg
  46. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L1.jpg
  47. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L2.jpg
  48. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L3.jpg
  49. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L4.jpg
  50. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L5.jpg
  51. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L6.jpg
  52. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L7.jpg
  53. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L8.jpg
  54. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L9.jpg
  55. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Lbottom.jpg
  56. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/P1.jpg
  57. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/can_testFAIL.jpg
  58. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/can_testPASS.jpg
  59. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose1.jpg
  60. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose2.jpg
  61. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose3.jpg
  62. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed1.jpg
  63. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed2.jpg
  64. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed3.jpg
  65. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/cloudy.jpg
  66. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/cloudyday.jpg
  67. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/default.jpg
  68. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/final_function.jpg
  69. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/function4.jpg
  70. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/function5.jpg
  71. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/humidity.jpg
  72. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/lan_test_fail.jpg
  73. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/lan_test_pass.jpg
  74. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power1.jpg
  75. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power2.jpg
  76. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power3.jpg
  77. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power4.jpg
  78. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/rain.jpg
  79. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal0.jpg
  80. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal1.jpg
  81. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal2.jpg
  82. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal3.jpg
  83. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal4.jpg
  84. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/snow.jpg
  85. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/sunny.jpg
  86. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/temp.jpg
  87. BIN
      module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/wind.jpg
  88. 311 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/dhcpsrv.lua
  89. 113 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/dnsproxy.lua
  90. 51 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/lan.lua
  91. 24 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/main.lua
  92. 22 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/broker.emqx.io-ca.crt
  93. 22 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/ca.crt
  94. 69 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/client.crt
  95. 27 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/client.key
  96. 31 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/main.lua
  97. 58 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan.lua
  98. 53 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_ftp.lua
  99. 268 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_http.lua
  100. 221 0
      module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_multilink_mqtt.lua

+ 21 - 0
module/Air780EPM/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 OpenLuat
+
+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.

+ 36 - 0
module/Air780EPM/README.en.md

@@ -0,0 +1,36 @@
+# LuatOS-Air780EPM
+
+#### Description
+LuatOS-Air780EPM
+
+#### 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/)

+ 23 - 0
module/Air780EPM/README.md

@@ -0,0 +1,23 @@
+# LuatOS-Air780EPM
+
+#### 介绍
+
+本代码库 是 合宙 Air780EPM 模组的代码中心, 包括固件, 演示代码, 案例代码等
+
+如需查阅文档, 请访问合宙文档中心的[Air780EPM模块文档中心](https://docs.openluat.com/air780epm)
+
+#### 目录说明
+
+* core  [固件文件](core/)
+* demo  [演示代码](demo/)
+* case  [案例代码](case/)
+
+## 授权协议
+
+[MIT License](LICENSE)
+
+```lua
+print("感谢您使用LuatOS ^_^")
+print("Thank you for using LuatOS ^_^")
+```
+

BIN
module/Air780EPM/core/LuatOS-SoC_V2003_Air780EPM/LuatOS-SoC_V2003_Air780EPM.soc


+ 32 - 0
module/Air780EPM/core/LuatOS-SoC_V2003_Air780EPM/release_note.txt

@@ -0,0 +1,32 @@
+Air780EPM第一版固件V2003
+支持的功能
+1、GPIO 
+2、UART 
+3、I2C  
+4、SPI  
+5、ADC  
+6、PWM  
+7、WDT  
+8、PM  
+9、RTC 
+10、WLAN 
+11、SMS  
+12、CRYPTO  
+13、CJSON  
+14、ZBUFF  
+15、PACK  
+16、MINIZ 
+17、HMETA 
+18、FSKV 
+19、EINK
+20、MQTT 
+21、FTP 
+22、WEBSOCKET 
+23、IOTAUTH 
+24、BIT64 
+25、ICONV 
+26、PROTOBUF 
+27、RSA      
+28、GMSSL    
+29、CAMERA 
+30、LCD

BIN
module/Air780EPM/core/LuatOS-SoC_V2004_Air780EPM.soc


BIN
module/Air780EPM/core/LuatOS-SoC_V2005_Air780EPM.soc


+ 32 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/adc780epm.lua

@@ -0,0 +1,32 @@
+sys.taskInit(function()
+    sys.wait(2000)
+    log.info("780EPM开发板adc通道测试")
+    adc.setRange(adc.ADC_RANGE_MAX) -- 设置内部分压到3.6V,需要用2004版本固件
+
+    while true do
+        -- -- 遍历ADC通道
+        for i = 0, 3 do
+            if adc.open(i) then
+                local voltage = adc.get(i)
+                log.info("adc" .. i .. "当前电压", voltage, "mV")
+                -- sys.wait(1000)
+            else
+                log.info("adc" .. i .. "打开失败")
+            end
+        end
+
+        -- 获取CPU温度
+        if adc.open(adc.CH_CPU) then
+            local cpuTemp = adc.get(adc.CH_CPU)
+            log.info("CPU当前温度", cpuTemp / 1000, "℃")
+        end
+
+        -- 获取VBAT电压
+        if adc.open(adc.CH_VBAT) then
+            local vbatVoltage = adc.get(adc.CH_VBAT)
+            log.info("vbat当前电压", vbatVoltage, "mV")
+        end
+
+        sys.wait(2000)
+    end
+end)

+ 24 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/bf30a2.lua

@@ -0,0 +1,24 @@
+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

+ 189 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/camera780epm.lua

@@ -0,0 +1,189 @@
+-- 实际使用时选1个就行
+-- require "bf30a2"
+require "gc032a"
+-- require "gc0310"
+httpplus = require "httpplus"
+
+gpio.setup(2, 1) -- GPIO2打开给camera电源供电
+gpio.setup(28, 1) -- 1.2版本 GPIO28打开给lcd电源供电
+
+gpio.setup(14, nil) -- 关闭GPIO14,防止camera复用关系出问题
+gpio.setup(15, nil) -- 关闭GPIO15,防止camera复用关系出问题
+
+local SCAN_MODE = 0 -- 写1演示扫码
+local scan_pause = true
+local getRawStart = false
+local RAW_MODE = 0 -- 写1演示获取原始图像
+-- SCAN_MODE和RAW_MODE都没有写1就是拍照
+
+-- 根据不同的BSP返回不同的值
+-- spi_id,pin_reset,pin_dc,pin_cs,bl
+local function lcd_pin()
+    local rtos_bsp = rtos.bsp()
+    if string.find(rtos_bsp, "780EPM") then
+        return lcd.HWID_0, 36, 0xff, 0xff, 25 -- 注意:EC718P有硬件lcd驱动接口, 无需使用spi,当然spi驱动也支持
+    else
+        log.info("main", "你用的不是780EPM,请更换demo测试", rtos_bsp)
+        return
+    end
+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
+
+lcd.init("st7796", {
+    port = port,
+    pin_dc = pin_dc,
+    pin_pwr = bl,
+    pin_rst = pin_reset,
+    direction = 0,
+    -- direction0 = 0x00,
+    w = 320,
+    h = 480,
+    xoffset = 0,
+    yoffset = 0,
+    sleepcmd = 0x10,
+    wakecmd = 0x11
+})
+
+local uartid = uart.VUART_0 -- 根据实际设备选取不同的uartid
+-- 初始化
+local result = uart.setup(uartid, -- 串口id
+600000, -- 波特率
+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)
+--按下boot(下载)按键,进行拍照
+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
+--拍照完成后向USB虚拟串口发送拍的照片,用户可以使用串口调试工具保存原始文件,然后改文件后缀名为jpg
+local function sendFile()
+    sys.taskInit(function()
+        local fileHandle = io.open("/testCamera.jpg", "rb")
+        if not fileHandle then
+            log.error("打开文件失败")
+            return
+        else
+            log.info("文件打开成功,文件大小为", io.fileSize("/testCamera.jpg"))
+        end
+
+        while true do
+            local data = fileHandle:read(1460)
+            -- log.info("我看看原始data", data)
+            if not data then
+                break
+            end
+            log.info("虚拟uart发送数据", uart.write(uartid, data))
+            sys.wait(10)
+        end
+        fileHandle:close() --发送完文件后关闭文件
+    end)
+end
+
+sys.taskInit(function()
+    log.info("摄像头启动")
+    -- spi的id和摄像头的id
+    local cspiId, i2cId = 1, 1
+
+    local camera_id
+    -- 配置iic
+    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) -- 打开LCD预览功能
+    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.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"))
+              
+            else
+                log.debug("摄像头拍照")
+                -- camera_id = gc0310Init(cspiId,i2cId,25500000,SCAN_MODE,SCAN_MODE)
+                camera.capture(camera_id, "/testCamera.jpg", 1) -- 2和3需要非常多非常多的psram,尽量不要用
+                -- 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)
+                log.info("rawbuff长度", rawbuff:len())
+                sendFile() --也可以上传文件到HTTP服务器,可以结合示例"780EPM_拍照发给HTTP服务器后进入psm+模式"使用
+                rawbuff:resize(60 * 1024)
+                log.info("sys ram", rtos.meminfo("sys"))
+                log.info("lua ram", rtos.meminfo("psram"))
+            end
+
+        end
+    end
+
+end)

+ 53 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gc0310.lua

@@ -0,0 +1,53 @@
+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

+ 58 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gc032a.lua

@@ -0,0 +1,58 @@
+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

+ 26 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/gpio780epm.lua

@@ -0,0 +1,26 @@
+-- LED引脚判断赋值结束
+local P1, P2, P3 = 1, 2, 16 --给这三个开发板引出的不连续的GPIO编号单独取出来
+
+sys.taskInit(function()
+    while 1 do
+        sys.wait(500) -- 置高时间
+        -- 先给这些GPIO置高
+        log.info("gpio1/2/16/20-33设置为高电平")
+        gpio.setup(P1, 1)
+        gpio.setup(P2, 1)
+        gpio.setup(P3, 1)
+        for i = 20, 33 do
+            gpio.setup(i, 1)
+        end
+        sys.wait(500)
+        -- 等待500ms后再将这些GPIO电平反转
+        log.info("gpio1/2/16/20-33设置为低电平")
+        gpio.toggle(P1)
+        gpio.toggle(P2)
+        gpio.toggle(P3)
+        for i = 20, 33 do
+            gpio.toggle(i)
+        end
+
+    end
+end)

+ 75 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/lcd7796.lua

@@ -0,0 +1,75 @@
+-- sys库是标配
+_G.sys = require("sys")
+
+-- 添加硬狗防止程序卡死
+if wdt then
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+end
+
+gpio.setup(28, 1) -- 1.2硬件版本 GPIO28打开给lcd电源供电
+
+local rtos_bsp = rtos.bsp()
+-- local chip_type = hmeta.chip()
+-- 根据不同的BSP返回不同的值
+-- 根据不同的BSP返回不同的值
+-- spi_id,pin_reset,pin_dc,pin_cs,bl
+local function lcd_pin()
+    local rtos_bsp = rtos.bsp()
+    if string.find(rtos_bsp, "780EPM") then
+        return lcd.HWID_0, 36, 0xff, 0xff, 25 -- 注意:EC718P有硬件lcd驱动接口, 无需使用spi,当然spi驱动也支持
+    else
+        log.info("main", "你用的不是780EPM,请更换demo测试", rtos_bsp)
+        return
+    end
+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
+
+lcd.init("st7796", {
+    port = port,
+    pin_dc = pin_dc,
+    pin_pwr = bl,
+    pin_rst = pin_reset,
+    direction = 0,
+    -- direction0 = 0x00,
+    w = 320,
+    h = 480,
+    xoffset = 0,
+    yoffset = 0,
+    sleepcmd = 0x10,
+    wakecmd = 0x11
+})
+
+
+sys.taskInit(function()
+    -- 开启缓冲区, 刷屏速度会加快, 但也消耗2倍屏幕分辨率的内存
+    -- lcd.setupBuff()          -- 使用lua内存
+    -- lcd.setupBuff(nil, true) -- 使用sys内存, 只需要选一种
+    -- lcd.autoFlush(false)
+    while 1 do
+        lcd.clear() --全局刷屏
+        log.info("wiki API 文档", "https://wiki.luatos.com/api/lcd.html")
+        if lcd.showImage then
+            -- 注意, jpg需要是常规格式, 不能是渐进式JPG
+            -- 如果无法解码, 可以用画图工具另存为,新文件就能解码了
+        --以左上角第一个像素点为原点向右为X轴向下为Y轴,以(40,0)坐标点为图片的第一个像素点,显示该图片
+            lcd.showImage(40, 0, "/luadb/logo.jpg")
+            sys.wait(100)
+        end
+        --以左上角第一个像素点为原点,向右为X轴向下为Y轴,在(20,20)和(150,20)两个坐标点之间画一条线
+        -- log.info("lcd.drawLine", lcd.drawLine(20, 20, 150, 20, 0x001F))
+        --以左上角第一个像素点为原点,向右为X轴向下为Y轴,在(20,40)和(120,70)两个坐标点之间绘制一个框
+        -- log.info("lcd.drawRectangle", lcd.drawRectangle(20, 40, 120, 70, 0xF800))
+        --以左上角第一个像素点为原点,向右为X轴向下为Y轴,(50,60)坐标点为圆心,画一个半径为20个像素点的圆
+        -- log.info("lcd.drawCircle", lcd.drawCircle(50, 60, 20, 0x0CE0))
+        lcd.flush() --清除屏幕缓冲区,不填默认全局清除
+        sys.wait(1000)
+    end
+end)

BIN
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/logo.jpg


+ 44 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/loopback.lua

@@ -0,0 +1,44 @@
+local uart3 = require("uart3_setup")
+local uart2 = require("uart2_setup")
+
+-- 定义测试参数
+local baud_rates = {2000000, 921600, 460800, 230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1200,600,300,200,100,1}
+local data_bits = {7, 8}
+local stop_bits = {0.5, 1, 1.5, 2}
+local parities = {uart.None, uart.Even, uart.Odd}
+local bit_orders = {uart.LSB, uart.MSB}
+local buff_size = { 1024, 2048, 4096}
+
+-- 测试函数
+local function test_uart_loopback()
+    for _, baud_rate in ipairs(baud_rates) do
+        for _, data_bit in ipairs(data_bits) do
+            for _, stop_bit in ipairs(stop_bits) do
+                for _, parity in ipairs(parities) do
+                    for _, bit_order in ipairs(bit_orders) do
+                        for _, buff in ipairs(buff_size) do
+                            -- 设置uart3
+                            local result1 = uart3.setup_uart3(baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+                            -- 设置UART2
+                            local result2 = uart2.setup_uart2(baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+                            -- 注册UART事件
+                            -- uart3.setup_uart3_event()
+                            -- uart2.setup_uart2_event()
+                            -- 测试数据发送
+                            local test_data = "Hello UART Loopback!\r\n"
+                            log.info("uart3发送数据" .. test_data .. "给uart2",uart.write(3, test_data))
+                            
+                            -- 等待一段时间,确保接收数据 
+                            sys.wait(1000)
+                        end
+                    end
+                end
+            end
+        end
+    end
+    print("All tests complete.")
+end
+
+-- 执行测试
+sys.taskInit(test_uart_loopback)
+

+ 30 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/main.lua

@@ -0,0 +1,30 @@
+PROJECT = "780EPM_development_board"
+VERSION = "1.0.2"
+
+sys = require("sys")
+log.style(1)
+
+
+ pm.ioVol(pm.IOVOL_ALL_GPIO, 3000)--所有IO电平开到3V,适配camera等多种外设
+--  mcu.hardfault(0)    --死机后停机,一般用于调试状态
+--用到哪个就开哪个,如果lcd和camera同时用到,只用开camera就好
+
+--  require"lcd7796"--只测试LCD
+
+--  require"camera780epm"--LCD和camera一起测试,默认为GC032A 30W像素,也可以改成bf30a2 8w像素,打开对应注释即可
+
+-- require"modbus780epm"--开发板485接口测试,接的uart1
+
+-- require"pwm780epm"--开发板蜂鸣器(pwm驱动)测试
+
+-- require "loopback"--开发板uart2和uart3回环测试,测试时需要短接uart2和uart3
+
+-- require"adc780epm"--开发板adc通道测试
+
+-- require "gpio780epm"--开发板gpio全测试
+
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 85 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/modbus780epm.lua

@@ -0,0 +1,85 @@
+
+-- 如果你用的是合宙DTU整机系列,才需要打开,否则按自己设计的PCB来
+gpio.setup(1, 1) -- 485转TTL芯片供电打开
+-- gpio.setup(24, 1) -- 外置供电电源打开
+
+modbus_rtu = require("modbus_rtu")
+local uartid = 1
+-- 初始化modbus_rtu
+modbus_rtu.init({
+    uartid = uartid, -- 接收/发送数据的串口id
+    baudrate = 4800, -- 波特率
+    gpio_485 = 25, -- 转向GPIO编号(1.2版本开发板是GPIO25)
+    tx_delay = 50000 -- 转向延迟时间,单位us(4800的最佳转向时间为50000,9600为20000,可以咨询下位机厂家推荐的转向延迟时间)
+    -- 下面这些数据不填也行,不填底层默认为如下参数
+    -- databits = 8,--数据位
+    -- stopbits = 1,--停止位
+    -- parity = uart.None,--校验位
+    -- endianness = uart.LSB,--大小端
+    -- buffer_size = 1024,--缓冲区大小
+    -- rx_level = 0,--rx初始电平
+})
+
+-- 定义modbus_rtu数据接收回调
+local function on_modbus_rtu_receive(frame)
+    log.info("modbus_rtu frame received:", json.encode(frame))
+    if frame.fun == 0x03 then -- 功能码0x03表示读取保持寄存器
+        local byte = frame.byte
+        local payload = frame.payload
+        -- log.info("modbus_rtu payload (hex):", payload:toHex())
+
+        -- 解析数据(假设数据为16位寄存器值)
+        local values_big = {} -- 大端序解析结果
+        for i = 1, #payload, 2 do
+            local msb = payload:byte(i)
+            local lsb = payload:byte(i + 1)
+
+            -- 大端序解析
+            local result_big = (msb * 256) + lsb
+            table.insert(values_big, result_big)
+        end
+
+        -- 输出大端序的解析结果
+        log.info("输出大端序的解析结果:", table.concat(values_big, ", "))
+
+        -- 第一个寄存器是湿度,第二个是温度,除以10以获取实际值
+        if #values_big == 2 then
+            log.info("测试同款485温湿度计")
+            local humidity = values_big[1] / 10
+            local temperature = values_big[2] / 10
+
+            -- 打印湿度和温度
+            log.info(string.format("湿度: %.1f%%", humidity))
+            log.info(string.format("温度: %.1f°C", temperature))
+
+            -- 发布湿度和温度
+            sys.publish("modbus_rtu_data", {humidity, temperature})
+        else
+            log.info("用户自己的485下位机,共有" .. #values_big .. "组数据")
+            for index, value in ipairs(values_big) do
+                log.info(string.format("寄存器 %d: %d (大端序)", index, value))
+            end
+
+        end
+    else
+        log.info("功能码不是03")
+    end
+end
+
+-- 设置modbus_rtu数据接收回调
+modbus_rtu.set_receive_callback(uartid, on_modbus_rtu_receive)
+
+local function send_modbus_rtu_command()
+    local addr = 0x01 -- 设备地址,此处填客户自己的
+    local fun = 0x03 -- 功能码(03为读取保持寄存器),此处填客户自己的
+    local data = string.char(0x00, 0x00, 0x00, 0x02) -- 起始地址和寄存器数量(此处填客户自己的起始地址进而寄存器数量)
+
+    -- modbus_rtu.send_command(1, addr, fun, data) -- 只发送一次命令并等待响应处理
+    modbus_rtu.send_command(uartid, addr, fun, data, 5000) -- 循环5S发送一次
+
+end
+
+sys.taskInit(function()
+    sys.wait(5000)
+    send_modbus_rtu_command()
+end)

+ 260 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/modbus_rtu.lua

@@ -0,0 +1,260 @@
+--[[
+@module modbus_rtu
+@summary modbus_rtu MODBUS_RTU协议 
+@version 1.0
+@date    2025.01.10
+@author  HH
+@usage
+--注意:
+--注意:
+-- 用法实例
+local modbus_rtu = require "modbus_rtu"
+
+-- 初始化modbus_rtu
+modbus_rtu.init({
+    uartid = 1, -- 接收/发送数据的串口id
+    baudrate = 4800, -- 波特率
+    gpio_485 = 25, -- 转向GPIO编号
+    tx_delay = 50000 -- 转向延迟时间,单位us
+
+-- 定义modbus_rtu数据接收回调
+local function on_modbus_rtu_receive(frame)
+    log.info("modbus_rtu frame received:", json.encode(frame))
+    if frame.fun == 0x03 then -- 功能码0x03表示读取保持寄存器
+        local byte = frame.byte
+        local payload = frame.payload
+        -- log.info("modbus_rtu payload (hex):", payload:toHex())
+
+        -- 解析数据(假设数据为16位寄存器值)
+        local values_big = {} -- 大端序解析结果
+        for i = 1, #payload, 2 do
+            local msb = payload:byte(i)
+            local lsb = payload:byte(i + 1)
+
+            -- 大端序解析
+            local result_big = (msb * 256) + lsb
+            table.insert(values_big, result_big)
+        end
+
+        -- 输出大端序的解析结果
+        log.info("输出大端序的解析结果:", table.concat(values_big, ", "))
+
+        -- 第一个寄存器是湿度,第二个是温度,除以10以获取实际值
+        if #values_big == 2 then
+            log.info("测试同款485温湿度计")
+            local humidity = values_big[1] / 10
+            local temperature = values_big[2] / 10
+
+            -- 打印湿度和温度
+            log.info(string.format("湿度: %.1f%%", humidity))
+            log.info(string.format("温度: %.1f°C", temperature))
+
+        else
+            log.info("用户自己的485下位机,共有" .. #values_big .. "组数据")
+            for index, value in ipairs(values_big) do
+                log.info(string.format("寄存器 %d: %d (大端序)", index, value))
+            end
+
+        end
+    else
+        log.info("功能码不是03")
+    end
+end
+
+-- 设置modbus_rtu数据接收回调
+modbus_rtu.set_receive_callback(1, on_modbus_rtu_receive)
+
+local function send_modbus_rtu_command()
+    local addr = 0x01 -- 设备地址,此处填客户自己的
+    local fun = 0x03 -- 功能码(03为读取保持寄存器),此处填客户自己的
+    local data = string.char(0x00, 0x00, 0x00, 0x02) -- 起始地址和寄存器数量(此处填客户自己的起始地址进而寄存器数量)
+
+    -- modbus_rtu.send_command(1, addr, fun, data) -- 只发送一次命令并等待响应处理
+    modbus_rtu.send_command(1, addr, fun, data, 5000) -- 循环5S发送一次
+
+end
+
+sys.taskInit(function()
+    sys.wait(5000)
+    send_modbus_rtu_command()
+
+end)
+
+]] local modbus_rtu = {}
+
+-- 默认配置
+local DEFAULT_CONFIG = {
+    uartid = 1, -- 串口ID
+    baudrate = 4800, -- 波特率
+    databits = 8, -- 数据位
+    stopbits = 1, -- 停止位
+    parity = uart.None, -- 校验位
+    endianness = uart.LSB, -- 字节序
+    buffer_size = 1024, -- 缓冲区大小
+    gpio_485 = 25, -- 485转向GPIO
+    rx_level = 0, -- 485模式下RX的GPIO电平
+    tx_delay = 10000 -- 485模式下TX向RX转换的延迟时间(us)
+}
+
+--[[
+modbus_rtu初始化
+@api modbus_rtu.init(config)
+@number 
+config为table,table里元素如下,用户根据自己实际情况修改对应参数,如果某个参数缺失会自动补充默认值,默认值为下
+ config= {
+    uartid = 1,          -- 串口ID
+    baudrate = 4800,     -- 波特率
+    databits = 8,        -- 数据位
+    stopbits = 1,        -- 停止位
+    parity = uart.None,  -- 校验位
+    endianness = uart.LSB, -- 字节序
+    buffer_size = 1024,  -- 缓冲区大小
+    gpio_485 = 25,       -- 485转向GPIO
+    rx_level = 0,        -- 485模式下RX的GPIO电平
+    tx_delay = 10000,    -- 485模式下TX向RX转换的延迟时间(us)
+}
+
+@table 485转串口设置 
+@return 无
+@usage
+modbus_rtu.init(config)
+--]]
+
+-- 初始化modbus_rtu
+function modbus_rtu.init(config)
+    config = config or {}
+    -- 遍历 DEFAULT_CONFIG,为缺省的参数赋值
+    for key, default_value in pairs(DEFAULT_CONFIG) do
+        if config[key] == nil then
+            config[key] = default_value
+        end
+    end
+    -- 初始化UART
+    uart.setup(config.uartid, config.baudrate, config.databits, config.stopbits, config.parity, config.endianness,
+        config.buffer_size, config.gpio_485, config.rx_level, config.tx_delay)
+    log.info("modbus_rtu 当前串口初始化配置为:", json.encode(config))
+end
+
+--[[
+对数据进行CRC16_RTU校验
+@api modbus_rtu.crc16()
+@return int 原始数据对应的CRC16值
+
+@usage
+ local crc16_data = modbus_rtu.crc16("01024B")
+log.info("crc16_data", crc16_data)
+]]
+
+function modbus_rtu.crc16(data)
+    local crc16_data = crypto.crc16_modbus(data)
+    -- log.info("crc16end = ",crc16_data)
+    return crc16_data
+end
+
+--[[
+对下位机返回过来的数据进行modbus_rtu解析
+@api  modbus_rtu.parse_frame()
+@number 下位机返回的数据(一般是hex的)
+@return 成功返回table(地址码,功能码,有效字节数 ,真实数据值,crc校验值)失败返回nil和"CRC error"
+@usage
+ local crc16_data = modbus_rtu.parse_frame("01030401E6FF9F1BA0")
+log.info("crc16_data", crc16_data.addr,crc16_data.fun,crc16_data.byte,crc16_data.payload,crc16_data.crc)
+]]
+
+function modbus_rtu.parse_frame(data)
+    local str = data or 0X00
+    local addr = str:byte(1) or 0X00 -- 地址位
+    local fun = str:byte(2) or 0X00 -- 功能码
+    local byte = str:byte(3) or 0X00 -- 有效字节数
+    local payload = str:sub(4, 4 + byte - 1) or 0X00 -- 数据部分(根据有效字节数动态截取)
+    local crc_data = str:sub(-2, -1) or 0X00
+    local idx, crc = pack.unpack(crc_data, "H") -- CRC校验值
+
+    -- 校验CRC
+    if crc == modbus_rtu.crc16(str:sub(1, -3)) then
+        log.info("modbus_rtu CRC校验成功")
+        return {
+            addr = addr,
+            fun = fun,
+            byte = byte,
+            payload = payload,
+            crc = crc
+        }
+    else
+        log.info("modbus_rtu CRC校验失败", crc)
+        return nil, "CRC error"
+    end
+end
+
+-- 确保build_frame使用正确的CRC和帧结构
+function modbus_rtu.build_frame(addr, fun, data)
+    local frame = string.char(addr, fun) .. data
+    local crc = modbus_rtu.crc16(frame)
+    -- log.info("CRC部分为",crc:toHex())
+    local pack_crc = pack.pack("H", crc)
+    -- log.info("pack后CRC为",aaa:toHex())
+    return frame .. pack_crc
+end
+
+--[[
+对发送给下位机的数据进行校验和发送次数的设置
+@api  modbus_rtu.send_command(uartid, addr, fun, data, interval)
+@number uartid 485转串口对应的串口id,main_uart为1,aux_uart为2
+@number addr 发送给下位机命令里的地址码
+@number fun 发送给下位机命令里的功能码
+@number data 发送给下位机命令里的有效字节数和命令码
+@number interval(可选) 为nil时命令只发一次,为数字时时间隔发送命令的秒数
+@return 成功返回table(地址码,功能码,有效字节数 ,真实数据值,crc校验值)失败返回nil和"CRC error"
+@usage
+ local crc16_data = modbus_rtu.parse_frame("01030401E6FF9F1BA0")
+log.info("crc16_data", crc16_data.addr,crc16_data.fun,crc16_data.byte,crc16_data.payload,crc16_data.crc)
+]]
+
+-- 发送modbus_rtu命令
+function modbus_rtu.send_command(uartid, addr, fun, data, interval)
+    local cmd = modbus_rtu.build_frame(addr, fun, data)
+    if interval then
+        -- 如果传入了interval,则启用循环发送
+        sys.timerLoopStart(function()
+            log.info("每隔" .. interval .. "秒发一次指令", cmd:toHex())
+            uart.write(uartid, cmd)
+        end, interval)
+        -- sys.timerLoopStart(uart.write, interval, uartid, cmd)
+        -- log.info("modbus_rtu 循环发送的间隔时间为", interval, "ms",cmd:toHex())
+    else
+        -- 否则只发送一次
+        uart.write(uartid, cmd)
+        -- log.info("modbus_rtu 只发送一次", cmd:toHex())
+    end
+end
+
+-- 设置modbus_rtu数据接收回调
+function modbus_rtu.set_receive_callback(uartid, callback)
+    uart.on(uartid, "receive", function(id, len)
+        local s = ""
+        repeat
+            s = uart.read(id, 128)
+            if #s > 0 then
+                log.info("modbus_rtu 收到的下位机回复:", s:toHex())
+                local frame, err = modbus_rtu.parse_frame(s)
+                if frame then
+                    callback(frame)
+                else
+                    log.info("modbus_rtu 数据错误", err)
+                end
+            end
+        until s == ""
+    end)
+end
+
+-- 设置modbus_rtu数据发送回调
+function modbus_rtu.set_sent_callback(uartid, callback)
+    uart.on(uartid, "sent", function(id)
+        log.info("modbus_rtu 数据发送:", id)
+        if callback then
+            callback(id)
+        end
+    end)
+end
+
+return modbus_rtu

+ 20 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/pwm780epm.lua

@@ -0,0 +1,20 @@
+local PWM_ID = 4
+
+mcu.altfun(mcu.PWM, 4, 46, 5, nil)--1.2版本PWM4对应的GPIO22,复用接口
+
+sys.taskInit(function()
+    log.info("pwm", "ch", PWM_ID)
+    while 1 do
+        sys.wait(5000)
+        --PWM接的蜂鸣器响的频率是4000和8000
+        log.info("pwm", ">>>>>3K")
+        pwm.open(PWM_ID, 1000, 50) -- 频率4000hz, 占空比0-100
+        sys.wait(5000)
+        log.info("pwm", ">>>>>8K")
+        pwm.open(PWM_ID, 8000, 50)
+        sys.wait(5000)
+        log.info("pwm", ">>>>>CLOSE")
+        -- pwm.open(PWM_ID, 0, 50)
+        pwm.close(PWM_ID)
+    end
+end)

+ 24 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/uart2_setup.lua

@@ -0,0 +1,24 @@
+uart2_setup = {}
+-- 设置UART2的函数
+local function setup_uart2(baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+
+    local result2 = uart.setup(2, baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+    print(string.format(
+        "uart2.setupuartid %d, 波特率 %d, 数据位 %d, 停止位 %s, 校验位 %s, 大小端 %s, 缓冲区大小 %d) = 设置结果 %d",
+        2, baud_rate, data_bit, stop_bit, tostring(parity), tostring(bit_order), buff, result2))
+    return result2
+end
+
+-- 注册UART2事件的函数
+
+uart.on(2, "receive", function(id, len)
+    local data = uart.read(id, len)
+    log.info("uart2接收到的是", id, len, data)
+    -- 将接收到的数据回写到uart3
+    uart.write(2, data)
+end)
+
+return {
+    setup_uart2 = setup_uart2
+    -- setup_uart2_event = setup_uart2_event
+}

+ 29 - 0
module/Air780EPM/demo/780EPM_1.2版本开发板全功能测试/uart3_setup.lua

@@ -0,0 +1,29 @@
+uart3_setup = {}
+
+-- 设置uart3的函数
+local function setup_uart3(baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+    -- --  每次设置前先关闭uart一次
+    -- uart.close(3)
+    local result1 = uart.setup(3, baud_rate, data_bit, stop_bit, parity, bit_order, buff)
+    print(string.format(
+        "uart3.setup(uartid %d, 波特率 %d, 数据位 %d, 停止位 %s, 校验位 %s, 大小端 %s, 缓冲区大小 %d) = 设置结果%d",
+        3, baud_rate, data_bit, stop_bit, tostring(parity), tostring(bit_order), buff, result1))
+    return result1
+end
+
+local test_data = "Hello UART Loopback!\r\n"
+
+-- 注册uart3事件的函数
+uart.on(3, "receive", function(id, len)
+    local received_data = uart.read(id, len)
+    print("uart3接收到的是", received_data)
+    if received_data == test_data then
+        print("回环的数据没有问题")
+    else
+        print("回环的数据有问题应该是 " .. test_data .. ", 结果是: " .. received_data)
+    end
+end)
+
+return {
+    setup_uart3 = setup_uart3
+}

+ 17 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/airbuzzer.lua

@@ -0,0 +1,17 @@
+local airbuzzer = {}
+
+local pwid = 4
+
+function airbuzzer.start_buzzer()
+    pwm.setup(pwid, 1000, 50)
+    pwm.start(pwid)
+    --pwm.open(pwid,1000,50)
+end
+
+function airbuzzer.stop_buzzer()
+    pwm.stop(pwid)  
+    --pwm.close(pwid)
+end
+
+return airbuzzer
+

+ 55 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/airlcd.lua

@@ -0,0 +1,55 @@
+
+local airLCD = {}
+
+function airLCD.lcd_init(sn)
+
+  if sn ~= "AirLCD_0001" then
+    return
+  end
+
+  pm.ioVol(pm.IOVOL_ALL_GPIO, 3000)--所有IO电平开到3V,电平匹配
+  gpio.setup(29, 1) -- GPIO29 打开给lcd电源供电
+
+  local rtos_bsp = rtos.bsp()
+  -- local chip_type = hmeta.chip()
+  -- 根据不同的BSP返回不同的值
+  -- 根据不同的BSP返回不同的值
+  -- spi_id,pin_reset,pin_dc,pin_cs,bl
+  local function lcd_pin()
+    local rtos_bsp = rtos.bsp()
+    if string.find(rtos_bsp, "780EPM") then
+        return lcd.HWID_0, 36, 0xff, 0xff, 25 -- 注意:EC718P有硬件lcd驱动接口, 无需使用spi,当然spi驱动也支持
+    else
+        log.info("main", "没找到合适的cat.1芯片", rtos_bsp)
+        return
+    end
+  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
+
+  lcd.init("st7796", {
+    port = port,
+    pin_dc = pin_dc,
+    pin_pwr = bl,
+    pin_rst = pin_reset,
+    direction = 0,
+    -- direction0 = 0x00,
+    w = 320,
+    h = 480,
+    xoffset = 0,
+    yoffset = 0,
+    sleepcmd = 0x10,
+    wakecmd = 0x11,
+  })
+
+  lcd.setupBuff(nil, true) -- 使用sys内存, 只需要选一种
+  lcd.autoFlush(false)
+end
+
+return airLCD

+ 94 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/camera780epm_simple.lua

@@ -0,0 +1,94 @@
+
+local AirCam0310 = {}
+
+-- 实际使用时选1个就行
+-- require "bf30a2"
+-- require "gc032a"
+require "gc0310"
+
+local camera_id = 0
+
+AirCam0310.isquit = false
+
+local function oncamfun(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
+
+
+    -- 根据不同的BSP返回不同的值
+    -- spi_id,pin_reset,pin_dc,pin_cs,bl
+local function lcd_pin()
+    return lcd.HWID_0, 36, 0xff, 0xff, 25 -- 注意:EC718P有硬件lcd驱动接口, 无需使用spi,当然spi驱动也支持
+end
+
+local function air8780epmv13_cam_int()
+    gpio.setup(2, 1) -- GPIO2打开给camera电源供电
+    -- gpio.setup(28, 1) -- GPIO28打开给lcd电源供电
+    gpio.setup(29, 1) -- GPIO28打开给lcd电源供电
+
+
+    gpio.setup(14, nil)
+    gpio.setup(15, nil)
+
+    local getRawStart = false
+    local RAW_MODE = 0 -- 写1演示获取原始图像
+    -- SCAN_MODE和RAW_MODE都没有写1就是拍照
+
+    camera.on(0, "scanned", oncamfun)
+
+    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
+end
+
+function AirCam0310.start_cam()
+    log.info("摄像头启动")
+    air8780epmv13_cam_int()
+
+    --spi的id和摄像头的id
+    local cspiId, i2cId = 1, 1
+
+    --配置iic
+    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)
+    --打开LCD预览功能
+    camera.start(camera_id)
+
+    log.info("打开LCD预览",camera.preview(camera_id, true),camera_id)
+    
+    log.info(rtos.meminfo("sys"))
+    log.info(rtos.meminfo("psram"))
+
+    while(1) do
+        sys.wait(100)
+        if AirCam0310.isquit then
+          log.info("摄像头关闭:", camera_id)
+          log.info("打开LCD预览",camera.preview(camera_id, false),camera_id)
+          camera.stop(camera_id)
+          camera.close(camera_id)
+          sys.wait(10)
+          lcd.set_direction(0)
+          break
+        end
+    end
+end
+
+return AirCam0310

+ 60 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/can_test.lua

@@ -0,0 +1,60 @@
+can_test= {}
+sys = require("sys")
+log.style(1)
+local node_a = true   -- A节点写true, B节点写false
+local can_id = 0
+local rx_id
+local tx_id
+if node_a then          -- A/B节点区分,互相传输测试
+    rx_id = 0x12345678
+    tx_id = 0x12345677
+else
+    rx_id = 0x12345677
+    tx_id = 0x12345678
+end
+local test_cnt, test_num
+local tx_buf = zbuff.create(8)
+local function can_cb(id, cb_type, param)
+    if cb_type == can.CB_MSG then
+        log.info("有新的消息")
+        local succ, id, id_type, rtr, data = can.rx(id)
+        while succ do
+            log.info(mcu.x32(id), #data, data:toHex())
+            succ, id, id_type, rtr, data = can.rx(id)
+        end
+    end
+    if cb_type == can.CB_TX then
+        if param then
+            log.info("发送成功")
+            can_test_result = true
+        else
+            log.info("发送失败")
+            can_test_result = false
+        end
+    end
+    if cb_type == can.CB_ERR then
+        log.info("CAN错误码", mcu.x32(param))
+    end
+    if cb_type == can.CB_STATE then
+        log.info("CAN新状态", param)
+    end
+end
+
+local function can_tx_test(data)
+    if node_a then
+        log.info("node a tx")
+    else
+        log.info("node b tx")
+    end
+    can.tx(can_id, tx_id, can.EXT, false, true, tx_buf)
+end
+-- can.debug(true)
+can.init(can_id, 128)
+can.on(can_id, can_cb)
+can.timing(can_id, 1000000, 5, 4, 3, 2)
+can.node(can_id, rx_id, can.EXT)
+can.mode(can_id, can.MODE_TEST)     -- 如果只是自身测试硬件好坏,可以用测试模式来验证,如果发送成功就OK
+
+return {can_tx_test = can_tx_test
+
+}

+ 53 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/gc0310.lua

@@ -0,0 +1,53 @@
+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

+ 335 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/main.lua

@@ -0,0 +1,335 @@
+PROJECT = "startupv13"
+VERSION = "1.0.0"
+
+log.info("main", PROJECT, VERSION)
+
+-- sys库是标配
+sys = require("sys")
+
+local airlcd = require "airlcd"
+local aircam = require "camera780epm_simple"
+local airrus = require "russia"
+local airstatus = require "statusbar"
+local airtestwlan = require "test_wlan"
+local airbuzzer = require "airbuzzer"
+
+local key = ""      
+
+local powertick = 0
+local boottick = 0
+local SWITCH_LONG_TIME = 500
+local ROT_LONG_TIME = 300
+local QUIT_LONG_TIME = 3000
+
+local sid = 0
+
+-- 按键事件类型:
+-- "switch": 短按开机键切换菜单;  
+-- "enter": 长按开机键进入功能菜单或者退出功能菜单
+
+-- 当前功能界面
+-- "main":      九宫格主界面
+-- "picshow":   图片显示
+-- "camshow":   摄像头预览
+-- "russia":    俄罗斯方块
+-- "LAN":       以太网 LAN
+-- "WAN":       以太网 WAN
+-- "selftest":  硬件自检
+-- "modbusTCP": modbus-TCP
+-- "modbusRTU": modbus-RTU
+-- "CAN":       CAN 测试
+local cur_fun = "main"
+local cur_sel = 0
+
+local funlist = {
+"picshow", "camshow","russia",
+"LAN", "WAN","selftest",
+"modbusTCP","modbusRTU","CAN"
+}
+
+local bkcolor = lcd.rgb565(11, 37, 102,false)
+
+local function wdtInit()
+-- 添加硬狗防止程序卡死
+  if wdt then
+    wdt.init(9000) -- 初始化watchdog设置为9s
+    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
+  end
+end
+
+local function StartCam()
+  airlcd.lcd_init("AirLCD_0001")
+  sys.taskInit(aircam.start_cam)
+  aircam.isquit = false
+end
+
+local function QuitCam()
+  aircam.isquit  = true
+  sys.wait(300)
+  airlcd.lcd_init("AirLCD_0001")
+end
+
+local function keypressed()
+  if key == "" then
+    return
+  end
+  
+  log.info("keypressed : ", key, cur_fun)
+
+  if cur_fun == "russia" then
+      if key == "quit" then
+          cur_fun = "main"
+      else
+          airrus.keypressed(key)
+      end
+      key = ""
+      return
+  end
+
+  if key == "switch" then
+    if cur_fun == "main" then
+      cur_sel = cur_sel + 1
+      if cur_sel > 9 then
+        cur_sel = 1
+      end
+      log.info("select num:", cur_sel)
+    end
+    key = ""
+  elseif key == "enter" or key == "quit" then
+    if cur_fun == "main" then
+      cur_fun = funlist[cur_sel]
+      if cur_fun == "camshow" then
+        StartCam()
+      elseif cur_fun == "russia" then
+        airrus.initrus()
+      elseif cur_fun == "LAN" then
+        
+      elseif cur_fun == "WAN" then
+        sys.taskInit(airtestwlan.test_wan)
+      elseif cur_fun == "selftest" then
+
+      elseif cur_fun == "modbusTCP" then
+
+      elseif cur_fun == "modbusRTU" then
+
+      elseif cur_fun == "CAN" then
+      end
+    else
+      cur_fun = "main"
+      if not aircam.isquit then
+        QuitCam()
+      end
+    end
+    key = ""
+  end
+  key = ""
+end
+
+local function PowerInterrupt()
+    local s1 = 0
+    local s2 = 0
+    local v = gpio.get(gpio.PWR_KEY)
+    log.info("pwrkey:", v, powertick)
+    if v == 0 then
+      powertick = mcu.ticks()
+      airbuzzer.start_buzzer()
+    elseif  v == 1 then
+      s1 = mcu.ticks()
+      airbuzzer.stop_buzzer()
+      local s2 = s1 - powertick
+      if s2 < SWITCH_LONG_TIME then
+          key = "switch"
+          if cur_fun == "russia" then
+            key = "left"
+          end
+      elseif s2 < QUIT_LONG_TIME then
+          key = "enter"
+          if cur_fun == "russia" then
+            key = "fast"
+          end
+      else
+          key = "quit"
+      end
+      powertick = s1
+      log.info("power key:", v, powertick,s2,key)
+    end
+end
+
+local function BootInterrupt()
+    local v = gpio.get(0)
+    log.info("gpio0:", v, boottick)
+    if v == 1 then
+      boottick = mcu.ticks()
+    elseif  v == 0 then
+      s1 = mcu.ticks()
+      local s2 = s1 - boottick
+      if s2 < ROT_LONG_TIME then
+        key = "right"
+      else
+        key = "up"
+      end
+      boottick = s1
+      log.info("gpio0 key:", v, boottick,s2,key)
+    end
+end
+
+local function KeyInit()
+    if not gpio.PWR_KEY then
+      log.info("bsp not support powerkey")
+      return
+    end
+  
+    gpio.setup(gpio.PWR_KEY, PowerInterrupt, gpio.PULLUP, gpio.BOTH)
+    gpio.setup(0, BootInterrupt, gpio.PULLDOWN, gpio.BOTH)
+end
+
+local function update()
+  if cur_fun == "russia" then
+    airrus.updaterus()
+  end
+
+  if not airstatus.data.weather.result and ((sid % 50) == 0)  then
+    airstatus.get_sig_strength()
+    airstatus.get_weather()
+  end
+  if airstatus.data.bat_level == 0 then
+    airstatus.get_bat_level()
+  end
+end
+
+-- 画状态栏
+local function draw_statusbar()
+  lcd.showImage(0, 0, "/luadb/signal" .. airstatus.data.sig_stren .. ".jpg")
+  lcd.showImage(64, 0, "/luadb/power" .. airstatus.data.bat_level .. ".jpg")
+  lcd.showImage(128, 0, "/luadb/temp.jpg")
+  lcd.showImage(192, 0, "/luadb/humidity.jpg")
+  lcd.showImage(0, 448, "/luadb/Lbottom.jpg")
+
+  if airstatus.data.weather.result then
+      lcd.setFont(lcd.font_opposansm32_chinese)
+      lcd.drawStr(172, 30, tostring(airstatus.data.weather.temp))
+      lcd.drawStr(236, 30, tostring(airstatus.data.weather.humidity))
+      lcd.showImage(256, 0, airstatus.data.weather_icon)
+  else
+      lcd.showImage(256, 0, "/luadb/default.jpg")
+  end
+end
+
+local function draw_wan()
+  lcd.showImage(0, 65, "/luadb/function5.jpg")
+end
+
+local function draw_lan()
+  lcd.showImage(0, 65, "/luadb/function4.jpg")
+end
+
+local function draw_selftest()
+  lcd.showImage(0, 65, "/luadb/choose1.jpg")
+  lcd.showImage(0, 194, "/luadb/choose2.jpg")
+  lcd.showImage(0, 322, "/luadb/choose3.jpg")
+end
+
+local function draw_modbusRTU()
+  lcd.showImage(0, 65, "/luadb/final_function.jpg")
+end
+
+local function draw_modbusTCP()
+  lcd.showImage(0, 65, "/luadb/final_function.jpg")
+end
+
+local function draw_CAN()
+  lcd.showImage(0, 65, "/luadb/final_function.jpg")
+end
+
+--画九宫格界面
+local function draw_main()
+  local i = 0
+  local j = 0 
+  local x,y
+  local fname
+  local sel = 0
+  
+  for i = 1,3 do
+    for j = 1,3 do
+      x = 64 + (i-1)*128 + 24
+      y = (j-1)*106 + 13
+      sel = j+(i-1)*3
+      if sel == cur_sel then
+        fname = "/luadb/" .. "D" .. sel .. ".jpg"
+      else
+        fname = "/luadb/" .. "L" .. sel .. ".jpg"
+      end
+      -- log.info("fname:", fname, x,y,sel,cur_sel)
+      lcd.showImage(y,x,fname)
+    end
+  end      
+end
+
+local function draw_pic()
+  lcd.showImage(0,64,"/luadb/P1.jpg")
+end
+
+local function draw()
+  if cur_fun == "camshow" then
+    return
+  end
+
+  lcd.clear(bkcolor)    
+  
+  draw_statusbar()
+  
+  if cur_fun == "main" then
+    draw_main()
+  elseif cur_fun == "picshow" then
+    draw_pic()
+  elseif cur_fun == "russia" then
+    airrus.drawrus()
+  elseif cur_fun == "LAN" then
+    draw_lan()
+  elseif cur_fun == "WAN" then
+    draw_wan()
+  elseif cur_fun == "selftest" then
+    draw_selftest()
+  elseif cur_fun == "modbusTCP" then
+    draw_modbusTCP()
+  elseif cur_fun == "modbusRTU" then
+    draw_modbusRTU()
+  elseif cur_fun == "CAN" then
+    draw_CAN()
+end
+  
+  lcd.showImage(0,448,"/luadb/Lbottom.jpg")
+  lcd.flush()
+end
+
+wdtInit()
+airlcd.lcd_init("AirLCD_0001")
+
+local function UITask()
+    KeyInit()
+    log.info("合宙 780EPM startup v13:" .. sid)
+
+    while 1 do
+        keypressed()
+        
+        update()
+
+        draw()
+
+        if ((sid % 10) == 0) then
+          log.info("sid: ", sid, cur_fun)
+        end
+
+        sid = sid + 1
+        sys.wait(10)
+    end
+
+end
+
+sys.taskInit(UITask)
+-- 当前是给camera 表的变量赋值让camera 退出。 未来可以让 UI task 发消息给camera 任务,让camera 任务关闭摄像头,释放LCD
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

+ 233 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/russia.lua

@@ -0,0 +1,233 @@
+
+local AirRus = {}
+
+local sid = 0
+local isquit = false
+local dir = "left"
+
+-- 全局设置
+local windowWidth, windowHeight = 320, 480
+local rows, cols = 20, 10
+local blockSize = math.floor(windowHeight / rows)  -- 每个方块大小(16像素)
+local boardLeft = (windowWidth - cols * blockSize) / 2  -- 将棋盘水平居中
+
+local board = {}       -- 用二维数组表示棋盘(0=空,1=已占用)
+local currentPiece     -- 当前下落的方块
+local timer = 0        -- 计时器,用于控制下落速度
+local dropInterval = 0.5 -- 每隔0.5秒下落一行
+
+-- 定义各个俄罗斯方块(只含一种状态,通过旋转实现其它状态)
+local tetrominoes = {
+  { {1, 1, 1, 1} },                   -- I型
+  { {1, 1}, {1, 1} },                -- O型
+  { {0, 1, 0}, {1, 1, 1} },           -- T型
+  { {1, 0, 0}, {1, 1, 1} },           -- L型
+  { {0, 0, 1}, {1, 1, 1} },           -- 反L型
+  { {1, 1, 0}, {0, 1, 1} },           -- S型
+  { {0, 1, 1}, {1, 1, 0} }            -- Z型
+}
+
+-- 初始化棋盘:每个格子初始值为0
+local function initBoard()
+  board = {}
+  for i = 1, rows do
+    board[i] = {}
+    for j = 1, cols do
+      board[i][j] = 0
+    end
+  end
+end
+
+-- 产生一个新方块(复制随机选取的一个 tetromino)
+local function newPiece()
+  local index = math.random(#tetrominoes)
+  local piece = {}
+  
+  log.info("new picce:" .. sid)
+
+  piece.shape = {}
+  for i = 1, #tetrominoes[index] do
+    piece.shape[i] = {}
+    for j = 1, #tetrominoes[index][i] do
+      piece.shape[i][j] = tetrominoes[index][i][j]
+    end
+  end
+  -- 设置初始位置,居中放置(棋盘左上角为坐标 (1,1))
+  piece.x = math.floor((cols - #piece.shape[1]) / 2) + 1
+  piece.y = 1
+  downlong = 5
+  return piece
+end
+
+-- 顺时针旋转方块(返回新的矩阵)
+local function rotateShape(shape)
+  local newShape = {}
+  local numRows = #shape
+  local numCols = #shape[1]
+  for i = 1, numCols do
+    newShape[i] = {}
+    for j = 1, numRows do
+      newShape[i][j] = shape[numRows - j + 1][i]
+    end
+  end
+  return newShape
+end
+
+-- 检查方块是否可以放在 (x, y) 位置(可传入自定义 shape 用于检测旋转后的位置)
+local function isValidPosition(piece, x, y, shape)
+  shape = shape or piece.shape
+  for i = 1, #shape do
+    for j = 1, #shape[i] do
+      if shape[i][j] == 1 then
+        local boardX = x + j - 1
+        local boardY = y + i - 1
+        if boardX < 1 or boardX > cols or boardY < 1 or boardY > rows then
+          return false
+        end
+        if board[boardY][boardX] == 1 then
+          return false
+        end
+      end
+    end
+  end
+  return true
+end
+
+-- 将当前方块固定到棋盘上,并检查消行
+local function lockPiece(piece)
+  for i = 1, #piece.shape do
+    for j = 1, #piece.shape[i] do
+      if piece.shape[i][j] == 1 then
+        local boardX = piece.x + j - 1
+        local boardY = piece.y + i - 1
+        board[boardY][boardX] = 1
+      end
+    end
+  end
+  -- 消除已填满的行
+  for i = rows, 1, -1 do
+    local full = true
+    for j = 1, cols do
+      if board[i][j] == 0 then
+        full = false
+        break
+      end
+    end
+    if full then
+      table.remove(board, i)
+      local newRow = {}
+      for j = 1, cols do newRow[j] = 0 end
+      table.insert(board, 1, newRow)
+    end
+  end
+  -- 生成新方块。如果新方块的位置无效,则退出游戏(失败)
+  currentPiece = newPiece()
+  if not isValidPosition(currentPiece, currentPiece.x, currentPiece.y) then
+    isquit = true  -- 游戏结束
+  end
+end
+
+-- 加载函数
+function AirRus.initrus()
+  isquit = false
+  math.randomseed(os.time())
+  initBoard()
+  currentPiece = newPiece()
+end
+
+-- right: 短按boot, left:短按开机,up:长按boot,fast:长按开机,quit:超长按开机
+function AirRus.keypressed(key)
+  -- log.info("key : ", key)
+  if key == "right" then
+    if isValidPosition(currentPiece, currentPiece.x + 1, currentPiece.y) then
+      currentPiece.x = currentPiece.x + 1
+    end
+    key = ""
+  elseif key == "left" then
+    if isValidPosition(currentPiece, currentPiece.x - 1, currentPiece.y) then
+      currentPiece.x = currentPiece.x - 1
+    end
+    key = ""
+  elseif key == "up" then
+    local rotated = rotateShape(currentPiece.shape)
+    if isValidPosition(currentPiece, currentPiece.x, currentPiece.y, rotated) then
+      currentPiece.shape = rotated
+    end
+    key = ""
+  elseif key == "fast" then
+    downlong = 1
+    key = ""
+  end
+end
+
+function AirRus.updaterus()
+    if isquit then
+      AirRus.initrus()
+      return
+    end
+
+    if isValidPosition(currentPiece, currentPiece.x, currentPiece.y + 1) then
+        currentPiece.y = currentPiece.y + 1
+       -- log.info(" y is:" .. currentPiece.y)
+    else
+        lockPiece(currentPiece)
+        log.info(" lockpiece y is:" .. currentPiece.y)
+    end
+end
+
+function AirRus.drawrus()
+    local bkc = lcd.rgb565(0)
+    local red1 = lcd.rgb565(0xFF0000)  --
+    local blue1 = lcd.rgb565(0x0000FF)
+
+    local redc = lcd.rgb565(0xFF0000)
+    local fblk = lcd.rgb565(0x00FF00)
+    local bblk = lcd.rgb565(0x0000FF)
+
+    log.info(" color 565 is: ", redc, fblk,bblk)
+
+    local fillcolor = 0
+    local x1,x2,y1,y2
+
+    lcd.clear(bkc)  -- 背景色深灰
+    -- 绘制棋盘中的固定方块
+    for i = 1, rows do
+      for j = 1, cols do
+        if board[i][j] == 1 then
+          fillcolor = fblk
+        else
+          fillcolor = bblk
+        end
+
+        x1 = boardLeft + (j - 1) * blockSize
+        y1 =  (i - 1) * blockSize
+        x2 = x1 + blockSize - 1
+        y2 = y1 + blockSize - 1
+        lcd.fill(x1, y1, x2,y2, fillcolor)
+        lcd.drawRectangle(x1, y1, x2,y2, bkc)
+        -- log.info("fill block:" .. fillcolor .. "x1:" .. x1  .. ", y1:" .. y1 .. ", x2:" .. x2 .. ", y2:" .. y2)
+      end
+    end
+    
+    -- 绘制当前下落的方块(红色)
+    --lcd.setColor(bkc, redc)
+    fillcolor = redc
+    for i = 1, #currentPiece.shape do
+      for j = 1, #currentPiece.shape[i] do
+        if currentPiece.shape[i][j] == 1 then
+          local gridX = currentPiece.x + j - 1
+          local gridY = currentPiece.y + i - 1
+          x1 = boardLeft + (gridX - 1) * blockSize
+          y1 = (gridY - 1) * blockSize
+          x2 = x1 + blockSize - 1
+          y2 = y1 + blockSize - 1
+          lcd.fill(x1, y1, x2,y2, fillcolor)
+          lcd.drawRectangle(x1, y1, x2,y2, bkc)
+          -- log.info("fill red block:" .. fillcolor .. "x1:" .. x1  .. ", y1:" .. y1 .. ", x2:" .. x2 .. ", y2:" .. y2)
+        end
+      end
+    end  
+    --lcd.flush()
+end
+
+return AirRus

+ 140 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/statusbar.lua

@@ -0,0 +1,140 @@
+statusbar_780epm = {}
+
+lbsLoc2 = require "lbsLoc2"
+
+--状态栏数据 
+statusbar_780epm.data = {
+    -- 电池状态
+    bat_level = 0, -- 电量等级 (0-4)
+    sig_stren = 0, -- 4G信号强度 (0-4)
+    net_ready = false,
+
+    -- 天气信息
+    weather = {
+        text = "", -- 天气文本 ("晴", "雨"等)
+        temp = "", -- 温度
+        humidity = "", -- 湿度
+        result = false, -- 是否获取成功
+    },
+    weather_icon = "/luadb/default.jpg"
+}
+
+local weather_icons = {
+      ["云"] = "/luadb/cloudy.jpg",
+      ["雨"] = "/luadb/rain.jpg",
+      ["晴"] = "/luadb/sunny.jpg",
+      ["雪"] = "/luadb/snow.jpg",
+      ["阴"] = "/luadb/cloudyday.jpg",
+      ["雾"] = "/luadb/sunny.jpg",
+      ["风"] = "/luadb/wind.jpg"
+}
+
+function statusbar_780epm.get_bat_level()
+    local data = statusbar_780epm.data
+    adc.open(adc.CH_VBAT)
+    local vbat = adc.get(adc.CH_VBAT)
+    local dump_power = vbat/4200
+    log.info("当前电量为:",dump_power,vbat)
+    dump_rate = dump_power*100
+    if dump_rate == 0 then
+        data.bat_level = 0
+    elseif dump_rate <= 25 then
+        data.bat_level = 1
+    elseif dump_rate <=50 then
+        data.bat_level = 2
+    elseif dump_rate <= 75 then
+        data.bat_level = 3
+    else
+        data.bat_level = 4
+    end
+    log.info("bat_level:",data.bat_level)
+end
+
+function statusbar_780epm.get_sig_strength()
+    local data = statusbar_780epm.data
+    local cp = mobile.status()
+    log.info("mobile status:", cp)
+
+    if cp == 1 or cp == 5 then
+        data.net_ready = true
+    else 
+        data.net_ready = false
+        return
+    end
+
+    local c1 = mobile.csq()
+    if c1 < 8 or c1 > 31 then -- "网络注册失败     
+        data.sig_stren = 1
+    elseif c1 <= 15 then -- 网络信号弱
+        data.sig_stren = 2
+    elseif c1 <= 26 then -- 网络信号正常
+        data.sig_stren = 3
+    else
+        data.sig_stren = 4
+    end
+end
+
+function statusbar_780epm.get_weather()
+    local lbs_location
+    local winfo
+    local data = statusbar_780epm.data
+
+    if not data.net_ready then
+        return
+    end
+
+    mobile.reqCellInfo(15)
+    sys.waitUntil("CELL_INFO_UPDATE", 3000)
+
+    local lbs_lat, lbs_lng ,t =  lbsLoc2.request(5000, nil, nil, true)
+    log.info("lat,lng",lbs_lat,lbs_lng)
+    if lbs_lat and lbs_lng then
+      lbs_location = lbs_lng..","..lbs_lat
+    else
+      lbs_location = "101010100"
+    end
+    
+    log.info("lbs_location",lbs_location)
+    local url = "https://devapi.qweather.com/v7/weather/now?location="..lbs_location.."&key=2c69d20742df4b3bbfa3c7006ce35210"
+    local code, headers, body = http.request("GET", url).wait(300)
+    log.info("url=",url)
+    log.info("http.gzip", code)
+    if code ~= 200 then
+        return ""
+    end
+
+    log.info("21")
+    local re = miniz.uncompress(body:sub(11), 0)
+    log.info("和风天气", re)
+
+    if re == nil or re == "" then
+        return
+    end
+
+    local jdata = json.decode(re)
+    log.info("jdata", jdata)
+    if not jdata then
+        return
+    end
+    log.info("和风天气", jdata.code,jdata.now)
+
+    if not jdata.now then
+        return
+    end
+
+    log.info("和风天气", "天气", jdata.now.text)
+
+    data.weather.text = jdata.now.text
+    data.weather.temp = jdata.now.temp
+    data.weather.humidity = jdata.now.humidity
+    data.weather.result = true
+
+    for keyword, icon in pairs(weather_icons) do
+        if string.find(data.weather.text, keyword) then
+            data.weather_icon = icon
+           break
+        end
+    end
+end
+
+return statusbar_780epm

+ 35 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/test_wlan.lua

@@ -0,0 +1,35 @@
+test_wlan = {}
+
+gpio.setup(20, 1) -- 打开lan供电
+
+local url = "http://httpbin.air32.cn"
+
+-- 测试用例函数
+function test_wlan.test_wan()
+    log.info("启动HTTP测试")
+    local tests = { -- GET 方法测试
+    {
+        method = "GET",
+        url = url .. "/get",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH
+
+        },
+        expected_code = 200,
+        description = "GET方法,无请求头、body以及额外的附加数据"
+    }}
+    -- 调试输出
+    local code = http.request("GET", "https://www.air32.cn/").wait()
+
+    -- 验证返回值
+    if code == tests.expected_code then
+        log.info("本次测试的是", tests.description, "code 符合预期结果 code = ", code)
+    else
+        log.info("本次测试的是", tests.description, "预期结果为", tests.expected_code,
+            "code 不符合预期结果 code =", code)
+    end
+end
+
+return test_wlan

+ 47 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/demo/wlan_http.lua

@@ -0,0 +1,47 @@
+wlan_http = {}
+
+sys = require("sys")
+sysplus = require("sysplus")
+gpio.setup(20, 1) -- 打开lan供电
+local url = "http://httpbin.air32.cn"
+
+-- 测试用例函数
+local function run_tests()
+    log.info("启动HTTP测试")
+    local tests = { -- GET 方法测试
+    {
+        method = "GET",
+        url = url .. "/get",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH
+
+        },
+        expected_code = 200,
+        description = "GET方法,无请求头、body以及额外的附加数据"
+    }}
+    -- 调试输出
+    local code = http.request("GET", "https://www.air32.cn/").wait()
+
+    -- 验证返回值
+    if code == tests.expected_code then
+        log.info("本次测试的是", tests.description, "code 符合预期结果 code = ", code)
+    else
+        log.info("本次测试的是", tests.description, "预期结果为", tests.expected_code,
+            "code 不符合预期结果 code =", code)
+    end
+    lcd.flush()
+
+end
+local function draw_wlan()
+    lcd.showImage(0, 65, "/luadb/function5.jpg")
+    run_tests()
+    log.info("进入功能5")
+
+end
+
+return {
+    run_tests = run_tests,
+    draw_wlan = draw_wlan
+}

+ 52 - 0
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/json/pins_Air780EPM.json

@@ -0,0 +1,52 @@
+{
+  "model": "Air780EPM",
+  "pins": [
+    [7, "PWR_KEY", "开机键"],
+    [16, "GPIO27", "网络状态灯控制,输出高时亮"],
+    [17, "UART1_RXD", "连接485收发器芯片"],
+    [18, "UART1_TXD", "连接485收发器芯片"],
+    [19, "GPIO22", "作为以太网CH390H的LAN_INT信号用"],
+    [20, "GPIO24", "作为485收发器485_EN信号用"],
+    [22, "GPIO1", "485供电LDO控制管脚用,高时输出3.3V"],
+    [23, "GPIO2", "摄像头供电LDO控制管脚用,高时输出3.3V"],
+    [25, "CAN_TXD", "直连CAN收发器CAN_TX"],
+    [26, "PWM4", "蜂鸣器控制"],
+    [28, "UART2_RXD", "默认功能,Air780EPM开发板V1.3未使用"],
+    [29, "UART2_TXD", "默认功能,Air780EPM开发板V1.3未使用"],
+    [30, "GPIO29", "LCD供电LDO控制管脚用,高时输出3.3V"],
+    [31, "GPIO30", "LCD背光控制管脚,输出高时LCD背光灭"],
+    [32, "GPIO31", "默认功能,Air780EPM开发板V1.3未使用"],
+    [33, "GPIO32", "默认功能,Air780EPM开发板V1.3未使用"],
+    [38, "DBG_RXD", "调试串口RXD"],
+    [39, "DBG_TXD", "调试串口TXD"],
+    [49, "LCD_RST", "默认功能LCD_RST"],
+    [50, "LCD_SDA", "默认功能LCD_SDA"],
+    [51, "LCD_RS", "默认功能LCD_RS"],
+    [52, "LCD_CS", "默认功能LCD_CS"],
+    [53, "LCD_CLK", "默认功能LCD_CLK"],
+    [54, "CAM_MCLK", "默认功能CAM_MCLK"],
+    [55, "CAM_RX0", "默认功能CAM_RX0"],
+    [56, "CAM_RX1", "默认功能CAM_RX1"],
+    [57, "UART3_TXD", "默认功能,Air780EPM开发板V1.3未使用"],
+    [58, "UART3_RXD", "默认功能,Air780EPM开发板V1.3未使用"],
+    [61, "VBUS", "USB插入检测,非电源功能"],
+    [66, "I2C1_SDA", "I2C1_SDA,开发板V1.3供摄像头使用"],
+    [67, "I2C1_SCL", "I2C1_SCL,开发板V1.3供摄像头使用"],
+    [78, "GPIO28", "CAN_STB信号,CAN功耗模式控制"],
+    [79, "USIM_DET", "SIM卡插入检测"],
+    [80, "CAM_BCLK", "默认功能CAM_BCLK"],
+    [81, "CAM_CS", "默认功能CAM_CS"],
+    [82, "USB_BOOT", "USB下载使能,上拉至VDD_EXT"],
+    [83, "SPI0_CS", "SPI0_CS,连接以太网CH390H"],
+    [84, "SPI0_MISO", "SPI0_MISO,连接以太网CH390H"],
+    [85, "SPI0_MOSI", "SPI0_MOSI,连接以太网CH390H"],
+    [86, "SPI0_CLK", "SPI0_CLK,连接以太网CH390H"],
+    [97, "GPIO16", "默认功能,Air780EPM开发板V1.3上实际没用"],
+    [99, "GPIO23", "Vref,一直输出高,做参考电源用"],
+    [100, "GPIO17", "IO_Volt_Set,默认功能"],
+    [101, "WAKEUP0", "默认功能,Air780EPM开发板V1.3未使用"],
+    [102, "GPIO20", "以太网CH390H供电LDO控制管脚用,高时输出3.3V"],
+    [106, "CAN_RXD", "直连CAN收发器CAN_RX"],
+    [107, "GPIO21", "默认功能,Air780EPM开发板V1.3未没用"]
+  ]
+}

BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/485test.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D4.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D5.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D6.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D7.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D8.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/D9.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Dbottom.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Dtop.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L4.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L5.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L6.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L7.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L8.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/L9.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/Lbottom.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/P1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/can_testFAIL.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/can_testPASS.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choose3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/choosed3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/cloudy.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/cloudyday.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/default.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/final_function.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/function4.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/function5.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/humidity.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/lan_test_fail.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/lan_test_pass.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/power4.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/rain.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal0.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal1.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal2.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal3.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/signal4.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/snow.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/sunny.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/temp.jpg


BIN
module/Air780EPM/demo/780EPM_1.3开发板出厂固件/pic/wind.jpg


+ 311 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/dhcpsrv.lua

@@ -0,0 +1,311 @@
+
+local dhcpsrv = {}
+
+local udpsrv = require("udpsrv")
+
+local TAG = "dhcpsrv"
+
+----
+-- 参考地址
+-- https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
+
+local function dhcp_decode(buff)
+    -- buff:seek(0)
+    local dst = {}
+    -- 开始解析dhcp
+    dst.op = buff[0]
+    dst.htype = buff[1]
+    dst.hlen = buff[2]
+    dst.hops = buff[3]
+    buff:seek(4)
+    dst.xid = buff:read(4)
+
+    _, dst.secs = buff:unpack(">H")
+    _, dst.flags = buff:unpack(">H")
+    dst.ciaddr = buff:read(4)
+    dst.yiaddr = buff:read(4)
+    dst.siaddr = buff:read(4)
+    dst.giaddr = buff:read(4)
+    dst.chaddr = buff:read(16)
+
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+
+    -- 解析magic
+    _, dst.magic = buff:unpack(">I")
+
+    -- 解析option
+    local opt = {}
+    while buff:len() > buff:used() do
+        local tag = buff:read(1):byte()
+        if tag ~= 0 then
+            local len = buff:read(1):byte()
+            if tag == 0xFF or len == 0 then
+                break
+            end
+            local data = buff:read(len)
+            if tag == 53 then
+                -- 53: DHCP Message Type
+                dst.msgtype = data:byte()
+            end
+            table.insert(opt, {tag, data})
+            -- log.info(TAG, "tag", tag, "data", data:toHex())
+        end
+    end
+    if dst.msgtype == nil then
+        return -- 没有解析到msgtype,直接返回
+    end
+    dst.opts = opt
+    return dst
+end
+
+local function dhcp_buff2ip(buff)
+    return string.format("%d.%d.%d.%d", buff:byte(1), buff:byte(2), buff:byte(3), buff:byte(4))
+end
+
+local function dhcp_print_pkg(pkg)
+    log.info(TAG, "XID",  pkg.xid:toHex())
+    log.info(TAG, "secs", pkg.secs)
+    log.info(TAG, "flags", pkg.flags)
+    log.info(TAG, "chaddr", pkg.chaddr:sub(1, pkg.hlen):toHex())
+    log.info(TAG, "yiaddr", dhcp_buff2ip(pkg.yiaddr))
+    log.info(TAG, "siaddr", dhcp_buff2ip(pkg.siaddr))
+    log.info(TAG, "giaddr", dhcp_buff2ip(pkg.giaddr))
+    log.info(TAG, "ciaddr", dhcp_buff2ip(pkg.ciaddr))
+    log.info(TAG, "magic", string.format("%08X", pkg.magic))
+    for _, opt in pairs(pkg.opts) do
+        if opt[1] == 53 then
+            log.info(TAG, "msgtype", opt[2]:byte())
+        elseif opt[1] == 60 then
+            log.info(TAG, "auth", opt[2])
+        elseif opt[1] == 57 then
+            log.info(TAG, "Maximum DHCP message size", opt[2]:byte() * 256 + opt[2]:byte(2))
+        elseif opt[1] == 61 then
+            log.info(TAG, "Client-identifier", opt[2]:toHex())
+        elseif opt[1] == 55 then
+            log.info(TAG, "Parameter request list", opt[2]:toHex())
+        elseif opt[1] == 12 then
+            log.info(TAG, "Host name", opt[2])
+        -- elseif opt[1] == 58 then
+        --     log.info(TAG, "Renewal (T1) time value", opt[2]:unpack(">I"))
+        end
+    end
+end
+
+local function dhcp_encode(pkg, buff)
+    -- 合成DHCP包
+    buff:seek(0)
+    buff[0] = pkg.op
+    buff[1] = pkg.htype
+    buff[2] = pkg.hlen
+    buff[3] = pkg.hops
+    buff:seek(4)
+    -- 写入XID
+    buff:write(pkg.xid)
+    -- 几个重要的参数
+    buff:pack(">H", pkg.secs)
+    buff:pack(">H", pkg.flags)
+    buff:write(pkg.ciaddr)
+    buff:write(pkg.yiaddr)
+    buff:write(pkg.siaddr)
+    buff:write(pkg.giaddr)
+    -- 写入MAC地址
+    buff:write(pkg.chaddr)
+    -- 跳过192字节
+    buff:seek(192, zbuff.SEEK_CUR)
+    -- 写入magic
+    buff:pack(">I", pkg.magic)
+    -- 写入option
+    for _, opt in pairs(pkg.opts) do
+        buff:write(opt[1])
+        buff:write(#opt[2])
+        buff:write(opt[2])
+    end
+    buff:write(0xFF, 0x00)
+end
+
+----
+
+local function dhcp_send_x(srv, pkg, client, msgtype)
+    local buff = zbuff.create(300)
+    pkg.op = 2
+    pkg.ciaddr = "\0\0\0\0"
+    pkg.yiaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    pkg.siaddr = string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])
+    pkg.giaddr = "\0\0\0\0"
+    pkg.secs = 0
+
+    pkg.opts = {} -- 复位option
+    table.insert(pkg.opts, {53, string.char(msgtype)})
+    table.insert(pkg.opts, {1, string.char(srv.opts.mark[1], srv.opts.mark[2], srv.opts.mark[3], srv.opts.mark[4])})
+    table.insert(pkg.opts, {3, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {51, "\x00\x00\x1E\x00"}) -- 7200秒, 大概
+    table.insert(pkg.opts, {54, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+    table.insert(pkg.opts, {6, string.char(223, 5, 5, 5)})
+    table.insert(pkg.opts, {6, string.char(119, 29, 29, 29)})
+    table.insert(pkg.opts, {6, string.char(srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], srv.opts.gw[4])})
+
+    dhcp_encode(pkg, buff)
+
+    local dst = "255.255.255.255"
+    if 4 == msgtype then
+        dst = string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], client.ip)
+    end
+    -- log.info(TAG, "发送", msgtype, dst, buff:query():toHex())
+    srv.udp:send(buff, dst, 68)
+end
+
+local function dhcp_send_offer(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 2)
+end
+
+local function dhcp_send_ack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 5)
+end
+
+local function dhcp_send_nack(srv, pkg, client)
+    dhcp_send_x(srv, pkg, client, 6)
+end
+
+local function dhcp_handle_discover(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "发现已经分配的mac地址, send offer")
+            dhcp_send_offer(srv, pkg, client)
+            return
+        end
+    end
+    -- TODO 清理已经过期的IP分配记录
+    -- 分配一个新的ip
+    if #srv.clients >= (srv.opts.ip_end - srv.opts.ip_start) then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    local ip = nil
+    for i = srv.opts.ip_start, srv.opts.ip_end, 1 do
+        if srv.clients[i] == nil then
+            ip = i
+            break
+        end
+    end
+    if ip == nil then
+        log.info(TAG, "没有可分配的ip了")
+        return
+    end
+    log.info(TAG, "分配ip", mac:toHex(), string.format("%d.%d.%d.%d", srv.opts.gw[1], srv.opts.gw[2], srv.opts.gw[3], ip))
+    local client = {
+        mac = mac,
+        ip = ip,
+        tm = mcu.ticks() // mcu.hz(),
+        stat = 1
+    }
+    srv.clients[ip] = client
+    log.info(TAG, "send offer")
+    dhcp_send_offer(srv, pkg, client)
+end
+
+local function dhcp_handle_request(srv, pkg)
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    -- 看看是不是已经分配了ip
+    for _, client in pairs(srv.clients) do
+        if client.mac == mac then
+            log.info(TAG, "request,发现已经分配的mac地址, send ack")
+            client.tm = mcu.ticks() // mcu.hz()
+            stat = 3
+            dhcp_send_ack(srv, pkg, client)
+            return
+        end
+    end
+    -- 没有找到, 那应该返回NACK
+    log.info(TAG, "request,没有分配的mac地址, send nack")
+    dhcp_send_nack(srv, pkg, {ip=pkg.yiaddr:byte(1)})
+end
+
+local function dhcp_pkg_handle(srv, pkg)
+    -- 进行基本的检查
+    if pkg.magic ~= 0x63825363 then
+        log.warn(TAG, "dhcp数据包的magic不对劲,忽略该数据包", pkg.magic)
+        return
+    end
+    if pkg.op ~= 1 then
+        log.info(TAG, "op不对,忽略该数据包", pkg.op)
+        return
+    end
+    if pkg.htype ~= 1 or pkg.hlen ~= 6 then
+        log.warn(TAG, "htype/hlen 不认识, 忽略该数据包")
+        return
+    end
+    -- 看看是不是能处理的类型, 当前只处理discover/request
+    if pkg.msgtype == 1 or pkg.msgtype == 3 then
+    else
+        log.warn(TAG, "msgtype不是discover/request, 忽略该数据包", pkg.msgtype)
+        return
+    end
+    -- 检查一下mac地址是否合法
+    local mac = pkg.chaddr:sub(1, pkg.hlen)
+    if mac == "\0\0\0\0\0\0" or mac == "\xFF\xFF\xFF\xFF\xFF\xFF" then
+        log.warn(TAG, "mac地址为空, 忽略该数据包")
+        return
+    end
+
+    -- 处理discover包
+    if pkg.msgtype == 1 then
+        log.info(TAG, "是discover包")
+        dhcp_handle_discover(srv, pkg)
+    elseif pkg.msgtype == 3 then
+        log.info(TAG, "是request包")
+        dhcp_handle_request(srv, pkg)
+    end
+    -- TODO 处理结束, 打印一下客户的列表?
+end
+
+local function dhcp_task(srv)
+    while 1 do
+        -- log.info("ulwip", "等待DHCP数据")
+        local result, data = sys.waitUntil(srv.udp_topic, 1000)
+        if result then
+            -- log.info("ulwip", "收到dhcp数据包", data:toHex())
+            -- 解析DHCP数据包
+            local pkg = dhcp_decode(zbuff.create(#data, data))
+            if pkg then
+                -- dhcp_print_pkg(pkg)
+                dhcp_pkg_handle(srv, pkg)
+            end
+        end
+    end
+end
+function dhcpsrv.create(opts)
+    local srv = {}
+    if not opts then
+        opts = {}
+    end
+    srv.udp_topic = "dhcpd_inc"
+    -- 补充参数
+    if not opts.mark then
+        opts.mark = {255, 255, 255, 0}
+    end
+    if not opts.gw then
+        opts.gw = {192, 168, 4, 1}
+    end
+    if not opts.dns then
+        opts.dns = opts.gw
+    end
+    if not opts.ip_start then
+        opts.ip_start = 100
+    end
+    if not opts.ip_end then
+        opts.ip_end = 200
+    end
+
+    srv.clients = {}
+    srv.opts = opts
+
+    srv.udp = udpsrv.create(67, srv.udp_topic, opts.adapter)
+    srv.task = sys.taskInit(dhcp_task, srv)
+    return srv
+end
+
+
+return dhcpsrv

+ 113 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/dnsproxy.lua

@@ -0,0 +1,113 @@
+--[[
+@module dnsproxy
+@summary DNS代理转发
+@version 1.0
+@date    2024.4.20
+@author  wendal
+@demo    socket
+@tag LUAT_USE_NETWORK
+@usage
+-- 具体用法请查阅demo
+]]
+
+local sys = require "sys"
+
+local dnsproxy = {}
+dnsproxy.map = {}
+dnsproxy.txid = 0x123
+dnsproxy.rxbuff = zbuff.create(1500)
+
+function dnsproxy.on_request(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len, remote_ip, remote_port = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                -- log.info("dnsproxy", "收到DNS查询数据", rxbuff:query():toHex())
+                if remote_ip and #remote_ip == 5 then
+                    local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_request = rxbuff[0] + rxbuff[1] * 256
+                    local txid_map = dnsproxy.txid
+                    dnsproxy.txid = dnsproxy.txid + 1
+                    if dnsproxy.txid > 65000 then
+                        dnsproxy.txid = 0x123
+                    end
+                    table.insert(dnsproxy.map, {txid_request, txid_map, remote_ip, remote_port})
+                    rxbuff[0] = txid_map % 256
+                    rxbuff[1] = txid_map // 256
+                    socket.tx(dnsproxy.main_sc, rxbuff, "223.5.5.5", 53)
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+function dnsproxy.on_response(sc, event)
+    if event == socket.EVENT then
+        local rxbuff = dnsproxy.rxbuff
+        while 1 do
+            rxbuff:seek(0)
+            local succ, data_len = socket.rx(sc, rxbuff)
+            if succ and data_len and data_len > 0 then
+                if true then
+                    -- local ip1,ip2,ip3,ip4 = remote_ip:byte(2),remote_ip:byte(3),remote_ip:byte(4),remote_ip:byte(5)
+                    -- remote_ip = string.format("%d.%d.%d.%d", ip1, ip2, ip3, ip4)
+                    local txid_resp = rxbuff[0] + rxbuff[1] * 256
+                    local index = -1
+                    for i, mapit in pairs(dnsproxy.map) do
+                        if mapit[2] == txid_resp then
+                            local txid_request = mapit[1]
+                            local remote_ip = mapit[3]
+                            local remote_port = mapit[4]
+                            rxbuff[0] = txid_request % 256
+                            rxbuff[1] = txid_request // 256
+                            socket.tx(dnsproxy.sc, rxbuff, remote_ip, remote_port)
+                            index = i
+                            break
+                        end
+                    end
+                    if index > 0 then
+                        table.remove(dnsproxy.map, index)
+                    end
+                end
+            else
+                break
+            end
+        end
+    end
+end
+
+--[[
+创建UDP服务器
+@api dnsproxy.create(adapter, main_adapter)
+@int 监听的网络适配器id
+@int 网络适配编号, 默认为nil,可选
+@return table UDP服务的实体, 若创建失败会返回nil
+]]
+function dnsproxy.setup(adapter, main_adapter)
+    log.info("dnsproxy", adapter, main_adapter)
+    dnsproxy.adapter = adapter
+    dnsproxy.main_adapter = main_adapter
+    dnsproxy.sc = socket.create(dnsproxy.adapter, dnsproxy.on_request)
+    dnsproxy.main_sc = socket.create(dnsproxy.main_adapter, dnsproxy.on_response)
+    socket.config(dnsproxy.sc, 53, true)
+    socket.config(dnsproxy.main_sc, 1053, true)
+    dnsproxy.on_ip_ready()
+    return true
+end
+
+function dnsproxy.on_ip_ready()
+    socket.close(dnsproxy.sc)
+    socket.close(dnsproxy.main_sc)
+    log.info("dnsproxy", "开启DNS代理")
+    socket.connect(dnsproxy.sc, "255.255.255.255", 0)
+    socket.connect(dnsproxy.main_sc, "223.5.5.5", 53)
+end
+
+sys.subscribe("IP_READY", dnsproxy.on_ip_ready)
+
+return dnsproxy

+ 51 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/lan.lua

@@ -0,0 +1,51 @@
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+dhcps = require "dhcpsrv"
+dnsproxy = require "dnsproxy"
+
+sys.taskInit(function ()
+    -- sys.wait(3000)
+    local result = spi.setup(
+        0,--串口id
+        nil,
+        0,--CPHA
+        0,--CPOL
+        8,--数据宽度
+        25600000--,--频率
+        -- spi.MSB,--高低位顺序    可选,默认高位在前
+        -- spi.master,--主模式     可选,默认主
+        -- spi.full--全双工       可选,默认全双工
+    )
+    log.info("main", "open",result)
+    if result ~= 0 then--返回值为0,表示打开成功
+        log.info("main", "spi open error",result)
+        return
+    end
+
+    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spiid=0,cs=8})
+    sys.wait(3000)
+    local ipv4,mark, gw = netdrv.ipv4(socket.LWIP_ETH, "192.168.4.1", "255.255.255.0", "192.168.4.1")
+    log.info("ipv4", ipv4,mark, gw)
+    while netdrv.link(socket.LWIP_ETH) ~= true do
+        sys.wait(100)
+    end
+    dhcps.create({adapter=socket.LWIP_ETH})
+    dnsproxy.setup(socket.LWIP_ETH, socket.LWIP_GP)
+    netdrv.napt(socket.LWIP_GP)
+    -- netdrv.dhcp(socket.LWIP_ETH, true)
+end)
+
+
+sys.taskInit(function()
+    -- sys.waitUntil("IP_READY")
+    while 1 do
+        sys.wait(300000)
+        -- log.info("http", http.request("GET", "http://httpbin.air32.cn/bytes/4096", nil, nil, {adapter=socket.LWIP_ETH}).wait())
+        log.info("lua", rtos.meminfo())
+        log.info("sys", rtos.meminfo("sys"))
+        -- log.info("psram", rtos.meminfo("psram"))
+    end
+end)

+ 24 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/lan/main.lua

@@ -0,0 +1,24 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ch390h"
+VERSION = "1.0.0"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "xxx" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+log.info("ch390", "打开LDO供电")
+gpio.setup(20, 1) -- 打开lan供电
+
+mcu.hardfault(0) -- 死机后停机,一般用于调试状态
+
+
+require "lan"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 22 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/broker.emqx.io-ca.crt

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----

+ 22 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/ca.crt

@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIUQ+u8vuzFnvSARWmvRtRdjrIHh5gwDQYJKoZIhvcNAQEL
+BQAwazELMAkGA1UEBhMCd3ExCzAJBgNVBAgMAndxMQswCQYDVQQHDAJ3cTELMAkG
+A1UECgwCd3ExCzAJBgNVBAsMAndxMRIwEAYDVQQDDAl6ZXRpbC5uZXQxFDASBgkq
+hkiG9w0BCQEWBW15QHdqMB4XDTIxMDEwODA5MTQ1MFoXDTIyMDEwODA5MTQ1MFow
+azELMAkGA1UEBhMCd3ExCzAJBgNVBAgMAndxMQswCQYDVQQHDAJ3cTELMAkGA1UE
+CgwCd3ExCzAJBgNVBAsMAndxMRIwEAYDVQQDDAl6ZXRpbC5uZXQxFDASBgkqhkiG
+9w0BCQEWBW15QHdqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsdvp
+N13PAcGuTlYOS4PO9WWJjTRFS91hGABHQRex3PhR/HWuxrvL8yg8+CKV8neNDT0z
+T+VJdu4p/F6v3xaW9eu7wlVX8WTS/bJhd/vXdS3rH41IVgJ1vPr80q519K+/lWwJ
+2Cs4N5qhC32ZnAXxxkvljIOz+mHrwMw/jgXtHPhhrxoamrsJ1DY4KAYOE7XBa1r7
+AgtG8Cx4FRXYTycZo3xg6wcOz747AseTjpeumJVG8j41iIiu/PhY3CjQTyVlBXpN
+T8/rZd1F6vwQRf2oXYc5ab9QKXNj0iY3Y93Doihc3fiXB0GRvWbJ+zn5Qeo2OQoP
+pzaSUYSU42QpFQ6xJQIDAQABo1MwUTAdBgNVHQ4EFgQUsODvMxpmXVn6G17hfEy0
+/+q5gW8wHwYDVR0jBBgwFoAUsODvMxpmXVn6G17hfEy0/+q5gW8wDwYDVR0TAQH/
+BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAPDR6I4g4jLJ0Jbi7ueQ3fExwUATs
+MXXsHlRhCNE4sabHjh2vmolwbej4771RpNrVVxxAFAk4GRh4bumU+yghosWqps6X
+BAuvsicGLRBGi0Bl01gxCxIH9r4TRSG19gLuw7UvfJFbTKGen6LY0wN4+AB5SYUZ
+n+vX8RgFhK21oQr/3LB8XmjYfsaoKEYWuH7hlx9pd0n0JUVPxIz1MDpsx6SgJPGR
+BkL5mTId8YnjGqBNOn557yLXe/4pHL3B0zr/YjXYgQ8kOhP8NpcdmtO2bfsMq8vZ
+xKKGrkplBitncojniz6e4eMdjx8BxRb3vpFpSn7pTQ8WVlrkMHh3bpWSmg==
+-----END CERTIFICATE-----

+ 69 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/client.crt

@@ -0,0 +1,69 @@
+Certificate:
+    Data:
+        Version: 1 (0x0)
+        Serial Number: 6 (0x6)
+        Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C=wq, ST=wq, L=wq, O=wq, OU=wq, CN=zetil.net/emailAddress=my@wj
+        Validity
+            Not Before: Jan  8 09:15:15 2021 GMT
+            Not After : Jan  6 09:15:15 2031 GMT
+        Subject: C=wq, ST=wq, L=w, O=qwq, OU=w, CN=qw/emailAddress=qw
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                RSA Public-Key: (2048 bit)
+                Modulus:
+                    00:ba:22:33:6d:db:f4:81:7a:2d:27:bc:fb:1b:7f:
+                    b9:db:1b:eb:8a:11:ab:a1:26:0b:90:3d:4c:42:3b:
+                    90:1b:98:5a:00:1a:3a:98:c3:1f:1d:32:ce:f6:26:
+                    07:31:10:3b:07:e7:92:05:5f:94:b2:30:f6:f8:cd:
+                    99:88:f2:db:35:da:40:60:fa:90:b4:e2:15:34:36:
+                    3e:43:f6:90:10:cb:bf:86:25:5e:c9:0d:d9:66:3e:
+                    5f:ef:cf:91:d1:92:b5:60:d8:26:14:3c:fa:5d:b7:
+                    8b:5c:00:e7:ef:cb:d1:4b:af:53:17:d9:a5:5f:85:
+                    19:f3:5b:fa:6e:74:f1:0b:be:b1:2d:fe:ed:e8:e4:
+                    15:19:a2:42:7c:9e:68:bb:37:10:f9:71:27:87:18:
+                    e4:5c:32:9d:9a:da:20:8d:50:d6:31:aa:56:bd:c3:
+                    2d:a6:4c:c5:72:14:6b:4e:18:81:42:af:2b:37:64:
+                    a9:44:6f:39:49:86:5e:c4:c5:98:7c:8e:72:58:5b:
+                    f9:2b:22:13:de:3f:a3:a2:b7:31:4c:48:2b:4c:29:
+                    52:5b:84:ae:85:a0:ff:6a:bb:90:ac:73:e5:f3:79:
+                    9f:fb:25:f1:91:17:6c:a6:18:c6:7e:a6:f0:b2:ef:
+                    8e:18:17:fa:0a:4b:20:1f:62:c4:05:46:92:b2:72:
+                    82:c3
+                Exponent: 65537 (0x10001)
+    Signature Algorithm: sha256WithRSAEncryption
+         70:95:e0:27:f5:66:fa:61:2a:17:89:74:de:52:5e:00:81:3b:
+         a4:5e:20:fc:c9:ba:fa:2b:b7:07:e4:4c:74:55:14:88:4d:a8:
+         94:4e:38:79:38:0d:1f:d5:d5:74:f8:db:22:e2:71:c7:25:a3:
+         3b:de:48:b8:31:a9:34:a8:11:a1:d2:3d:87:48:a1:26:70:93:
+         23:ec:fd:4a:14:1b:87:d6:af:34:a6:58:02:e5:48:b0:5a:5a:
+         98:05:1d:04:69:01:76:27:8e:dc:08:dd:81:94:08:97:9b:2d:
+         f5:c1:99:a1:a1:8b:78:af:dd:73:3b:94:01:96:cb:4c:99:bf:
+         a9:d7:95:3b:5b:f5:d8:6e:f5:d8:74:11:87:2f:b6:44:aa:6a:
+         87:c7:5f:96:a0:78:8d:47:d1:28:b1:15:ea:32:46:76:ef:b1:
+         ed:2a:39:df:35:64:d3:2c:bd:66:78:97:50:5a:4d:9b:3e:47:
+         d5:44:80:82:cb:cc:e7:1e:23:c3:4e:e4:7e:09:c9:1e:21:b2:
+         3e:7b:e7:b9:48:08:ab:af:a2:63:4f:8b:a4:b7:3e:54:62:a0:
+         75:89:25:b2:51:2c:3b:3d:74:dc:b3:5b:2e:fb:59:82:0b:e5:
+         37:b4:7f:d2:8d:bd:8f:a2:47:33:79:d0:39:ee:ac:3b:56:d7:
+         dd:e0:5d:25
+-----BEGIN CERTIFICATE-----
+MIIDPzCCAicCAQYwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCd3ExCzAJBgNV
+BAgMAndxMQswCQYDVQQHDAJ3cTELMAkGA1UECgwCd3ExCzAJBgNVBAsMAndxMRIw
+EAYDVQQDDAl6ZXRpbC5uZXQxFDASBgkqhkiG9w0BCQEWBW15QHdqMB4XDTIxMDEw
+ODA5MTUxNVoXDTMxMDEwNjA5MTUxNVowYDELMAkGA1UEBhMCd3ExCzAJBgNVBAgM
+AndxMQowCAYDVQQHDAF3MQwwCgYDVQQKDANxd3ExCjAIBgNVBAsMAXcxCzAJBgNV
+BAMMAnF3MREwDwYJKoZIhvcNAQkBFgJxdzCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALoiM23b9IF6LSe8+xt/udsb64oRq6EmC5A9TEI7kBuYWgAaOpjD
+Hx0yzvYmBzEQOwfnkgVflLIw9vjNmYjy2zXaQGD6kLTiFTQ2PkP2kBDLv4YlXskN
+2WY+X+/PkdGStWDYJhQ8+l23i1wA5+/L0UuvUxfZpV+FGfNb+m508Qu+sS3+7ejk
+FRmiQnyeaLs3EPlxJ4cY5FwynZraII1Q1jGqVr3DLaZMxXIUa04YgUKvKzdkqURv
+OUmGXsTFmHyOclhb+SsiE94/o6K3MUxIK0wpUluEroWg/2q7kKxz5fN5n/sl8ZEX
+bKYYxn6m8LLvjhgX+gpLIB9ixAVGkrJygsMCAwEAATANBgkqhkiG9w0BAQsFAAOC
+AQEAcJXgJ/Vm+mEqF4l03lJeAIE7pF4g/Mm6+iu3B+RMdFUUiE2olE44eTgNH9XV
+dPjbIuJxxyWjO95IuDGpNKgRodI9h0ihJnCTI+z9ShQbh9avNKZYAuVIsFpamAUd
+BGkBdieO3AjdgZQIl5st9cGZoaGLeK/dczuUAZbLTJm/qdeVO1v12G712HQRhy+2
+RKpqh8dflqB4jUfRKLEV6jJGdu+x7So53zVk0yy9ZniXUFpNmz5H1USAgsvM5x4j
+w07kfgnJHiGyPnvnuUgIq6+iY0+LpLc+VGKgdYklslEsOz103LNbLvtZggvlN7R/
+0o29j6JHM3nQOe6sO1bX3eBdJQ==
+-----END CERTIFICATE-----

+ 27 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/cert/client.key

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAuiIzbdv0gXotJ7z7G3+52xvrihGroSYLkD1MQjuQG5haABo6
+mMMfHTLO9iYHMRA7B+eSBV+UsjD2+M2ZiPLbNdpAYPqQtOIVNDY+Q/aQEMu/hiVe
+yQ3ZZj5f78+R0ZK1YNgmFDz6XbeLXADn78vRS69TF9mlX4UZ81v6bnTxC76xLf7t
+6OQVGaJCfJ5ouzcQ+XEnhxjkXDKdmtogjVDWMapWvcMtpkzFchRrThiBQq8rN2Sp
+RG85SYZexMWYfI5yWFv5KyIT3j+jorcxTEgrTClSW4SuhaD/aruQrHPl83mf+yXx
+kRdsphjGfqbwsu+OGBf6CksgH2LEBUaSsnKCwwIDAQABAoIBACbJo7/7+xrUM/64
+8fcMCdXwHohaIFLnk7dOHssakHA/slmdHaLh3mT+RoSi7hK6WCLQjexSu7DaZUz5
+w0n3mdjCD3JmJKudBWApAZa2FdV6MAIrXXI2UZxt2R4nOjLbCLMSt/S1tFK9Qew9
+QBgHeCj2czFgKIccPIkrHKfR9L1Gdx0dN0rT+bMXmfBXKl27PiUu+ACEAHGPHJ8r
+gWGm6IGB5H8x+Cun9KpDNX9qe5FOzyG0cSl1TWoFEDdXrkteMWZC+o2CkpiEx6xM
+ELtpFofYohbjB+JvbEU03huVWsDuuOn8chDRSWA+h9w5UQ8apDgkFwOCf/FJohCc
+89mGIDECgYEA9RFbXqYFyUW1SATosWBHUuU+nPFdWhoi54y3fdQs4G0/lkEdsLaD
+YiiLERM8AeSrHk/rEmB//UKHqp9UNNjK33TkbpJjUewolrngz4hQHikOXzT2ZZYa
+HdmGMC906oApQ1YxLSj5MgCSAwlDLDZrn6j59tUmnKb7AemO/Lhn9jkCgYEAwm/S
+qHjsfrgaPzTdAtyj5xW7fRRWBKIoCeo3sdQlg0190MGBtz2Tbw4UcdFwo6lTdu9R
+fxYMwpwyJ3n3RccuzKIda0iNRNcNgXIONDAEr8A9wqqX1JOwhOr08c89glV2h46a
++lS/eDuLTD7DeVlC/iV7MNvs+4RfX2SFsmKZ4NsCgYBFF7Cn/azR8ypJ9MBaCefx
+8hn2C4KjPY0rtRuiiShh2cs8pH0nbj2adg3HMaIQcpTgBe4jjztmftRbAXKvN5Py
+7jTdC76ewTMsU5mTST41UqPvqbHyMCCK2+IeQbL3zkxT5MAWmF+xfkGsQ3dBxtIP
+AIgA1FV/gwBvqJacn60H2QKBgQCzzrFi9yDNNveeyAYypVQ1WVWfH/VEJ6kbMiv7
+GZLvT/Qv3yNUD2+OXdjuQJ8H2ojDDiGxgvSd69A9zX6sWryepLTMB7YMmUt2D8Gu
+5VEQLplusk/iWAn/gUCvddUN+Ha6eVg8c671QytYgRpH2BIp8QNxdZA8MHf6QX2a
+L7DZzQKBgCk+QxDyXhpWzkFpGUgu+XerZFoAtvlDeTv6VYfmfGpmC8/AsdNRSuR0
+a06VxHTXlpGKDaFYgvqEV97j7ekJherS4XMs6TBjuIRCfI8wtWaN3RMCzn6V6gnW
+uUXWFwsTARvNycZSfZMute/C6E5LjdkGVvnPsGKv54+mqIDpEpIJ
+-----END RSA PRIVATE KEY-----

+ 31 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/main.lua

@@ -0,0 +1,31 @@
+-- LuaTools需要PROJECT和VERSION这两个信息
+PROJECT = "ch390h"
+VERSION = "1.0.0"
+
+-- 使用合宙iot平台时需要这个参数
+PRODUCT_KEY = "xxx" -- 到 iot.openluat.com 创建项目,获取正确的项目id
+
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+log.info("ch390", "打开LDO供电")
+gpio.setup(20, 1) -- 打开lan供电
+
+mcu.hardfault(0) -- 死机后停机,一般用于调试状态
+
+
+require "wan"
+-- require "wan_http"
+-- require "wan_tcp_udp_ssl"
+-- require "wan_single_mqtt" --mqtt单链接
+-- require"wan_ssl_mqtt" --mqtt SSL链接
+-- require"wan_multilink_mqtt" --mqtt多链接
+-- require "wan_ftp"
+require"wan_websocket"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!
+

+ 58 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan.lua

@@ -0,0 +1,58 @@
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+sys.taskInit(function()
+    sys.wait(3000)
+    local result = spi.setup(0, -- 串口id
+    nil, 0, -- CPHA
+    0, -- CPOL
+    8, -- 数据宽度
+    25600000 -- ,--频率
+    -- spi.MSB,--高低位顺序    可选,默认高位在前
+    -- spi.master,--主模式     可选,默认主
+    -- spi.full--全双工       可选,默认全双工
+    )
+    log.info("main", "open", result)
+    if result ~= 0 then -- 返回值为0,表示打开成功
+        log.info("main", "spi open error", result)
+        return
+    end
+
+    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {
+        spiid = 0,
+        cs = 8
+    })
+    netdrv.dhcp(socket.LWIP_ETH, true)
+    -- sys.wait(3000)
+    while 1 do
+        local ipv4ip, aaa, bbb = netdrv.ipv4(socket.LWIP_ETH, "", "", "")
+        log.info("ipv4地址,掩码,网关为", ipv4ip, aaa, bbb)
+        local netdrv_start = netdrv.ready(socket.LWIP_ETH)
+        if netdrv_start and ipv4ip and ipv4ip ~= "0.0.0.0" then
+            log.info("条件都满足")
+            sys.publish("CH390_IP_READY")
+            return
+        end
+        sys.wait(1000)
+    end
+
+end)
+
+-- sys.taskInit(function()
+--     sys.waitUntil("CH390_IP_READY")
+--     log.info("CH390 联网成功,开始测试")
+
+--     -- 如果自带的DNS不好用,可以用下面的公用DNS,但是一定是要在CH390联网成功后使用
+-- -- socket.setDNS(socket.LWIP_ETH,1,"223.5.5.5")	
+-- -- socket.setDNS(nil,1,"114.114.114.114")
+
+--     while 1 do
+--         sys.wait(6000)
+--         log.info("http", http.request("GET", "https://wiki.luatos.com/api/index.html", nil, nil, {
+--             adapter = socket.LWIP_ETH
+--         }).wait())
+--         log.info("lua", rtos.meminfo())
+--         log.info("sys", rtos.meminfo("sys"))
+--     end
+-- end)

+ 53 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_ftp.lua

@@ -0,0 +1,53 @@
+
+
+
+sys.taskInit(function()
+
+    sys.waitUntil("CH390_IP_READY")
+    log.info("CH390 联网成功,开始测试")
+    socket.dft(socket.LWIP_ETH)
+    -- 如果自带的DNS不好用,可以用下面的公用DNS,但是一定是要在CH390联网成功后使用
+    -- socket.setDNS(socket.LWIP_ETH,1,"223.5.5.5")	
+    -- socket.setDNS(nil,1,"114.114.114.114")
+
+    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)

+ 268 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_http.lua

@@ -0,0 +1,268 @@
+-- 引入必要的库文件(lua编写), 内部库不需要require
+sys = require("sys")
+sysplus = require("sysplus")
+
+sys.taskInit(function()
+    sys.wait(3000)
+    local result = spi.setup(0, -- 串口id
+    nil, 0, -- CPHA
+    0, -- CPOL
+    8, -- 数据宽度
+    25600000 -- ,--频率
+    -- spi.MSB,--高低位顺序    可选,默认高位在前
+    -- spi.master,--主模式     可选,默认主
+    -- spi.full--全双工       可选,默认全双工
+    )
+    log.info("main", "open", result)
+    if result ~= 0 then -- 返回值为0,表示打开成功
+        log.info("main", "spi open error", result)
+        return
+    end
+
+    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {
+        spiid = 0,
+        cs = 8
+    })
+    netdrv.dhcp(socket.LWIP_ETH, true)
+    -- sys.wait(3000)
+    while 1 do
+        local ipv4ip, aaa, bbb = netdrv.ipv4(socket.LWIP_ETH, "", "", "")
+        log.info("ipv4地址,掩码,网关为", ipv4ip, aaa, bbb)
+        local netdrv_start = netdrv.ready(socket.LWIP_ETH)
+        if netdrv_start and ipv4ip and ipv4ip ~= "0.0.0.0" then
+            log.info("条件都满足")
+            sys.publish("CH390_IP_READY")
+            return
+        end
+        sys.wait(1000)
+    end
+
+end)
+
+local url = "http://httpbin.air32.cn"
+
+-- 读取证书和私钥的函数
+local function read_file(file_path)
+    local file, err = io.open(file_path, "r")
+    if not file then
+        error("Failed to open file: " .. err)
+    end
+    local data = file:read("*a")
+    file:close()
+    return data
+end
+
+-- 读取证书和私钥
+local ca_server = read_file("/luadb/ca.crt") -- 服务器 CA 证书数据
+local ca_client = read_file("/luadb/client.crt") -- 客户端 CA 证书数据
+local client_private_key_encrypts_data = read_file("/luadb/client.key") -- 客户端私钥
+local client_private_key_password = "123456789" -- 客户端私钥口令
+
+-- 测试用例函数
+local function run_tests()
+    log.info("启动HTTP多项测试")
+    local tests = { -- GET 方法测试
+    {
+        method = "GET",
+        url = url .. "/get",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH
+
+        },
+        expected_code = 200,
+        description = "GET方法,无请求头、body以及额外的附加数据"
+    }, {
+        method = "GET",
+        url = url .. "/get",
+        headers = {
+            ["Content-Type"] = "application/json"
+        },
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH
+
+        },
+        expected_code = 200,
+        description = "GET方法,有请求头,无body和额外的附加数据"
+    }, {
+        method = "GET",
+        url = url .. "/get",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+            timeout = 5000,
+            debug = true
+        },
+        expected_code = 200,
+        description = "GET方法,无请求头,无body,超时时间5S,debug日志打开"
+    }, -- GET 方法测试(下载 2K 小文件)
+    {
+        method = "GET",
+        url = "http://airtest.openluat.com:2900/download/2K", -- 返回 2K 字节的文件
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = 200,
+        description = "GET 2K小文件下载"
+    }, {
+        method = "GET",
+        url = "http://invalid-url",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = -4,
+        description = "GET方法,无效的url,域名"
+    }, {
+        method = "GET",
+        -- url = "http://invalid-url",
+        url = "192.168.1",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = -4,
+        description = "GET方法,无效的url,IP地址"
+    }, -- POST 方法测试
+    {
+        method = "POST",
+        url = url .. "/post",
+        headers = {
+            ["Content-Type"] = "application/json"
+        },
+        body = '{"key": "value"}',
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = 200,
+        description = "POST方法,有请求头,body为json"
+    }, {
+        method = "POST",
+        url = url .. "/post",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = 200,
+        description = "POST方法,无请求头,无body,无额外的数据"
+    }, {
+        method = "POST",
+        url = "clahflkjfpsjvlsvnlohvioehoi",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = -4,
+        description = "POST方法,无效的url,域名"
+    }, {
+        method = "POST",
+        -- url = "http://invalid-url",
+        url = "192.168.1",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = -4,
+        description = "POST方法,无效的url,IP地址"
+    }, -- POST 方法测试(上传 30K 大文件)
+    {
+        method = "POST",
+        url = url .. "/post",
+        headers = {
+            ["Content-Type"] = "application/octet-stream"
+        },
+        body = string.rep("A", 30 * 1024), -- 生成 30K 的数据
+        opts = {
+            adapter = socket.LWIP_ETH,
+        },
+        expected_code = 200,
+        description = "POST 30K大数据上传"
+    }, {
+        method = "POST",
+        url = url .. "/post",
+        headers = {
+            ["Content-Type"] = "application/x-www-form-urlencoded"
+        },
+        body = "key=value",
+        opts = {
+            adapter = socket.LWIP_ETH,
+            timeout = 5000
+        },
+        expected_code = 200,
+        description = "POST方法,有请求头,body为json,超时时间5S"
+    }, -- HTTPS GET 方法测试(双向认证)
+    {
+        method = "GET",
+        url = url .. "/get",
+        headers = nil,
+        body = nil,
+        opts = {
+            adapter = socket.LWIP_ETH,
+            ca = ca_server,
+            client_cert = ca_client,
+            client_key = client_private_key_encrypts_data,
+            client_key_password = client_private_key_password
+        },
+        expected_code = 200,
+        description = "HTTPS GET方法,无请求头,无body,带双向认证的服务器证书、客户端证书、客户端key,客户端password"
+    }, -- HTTPS POST 方法测试(双向认证)
+    {
+        method = "POST",
+        url = url .. "/post",
+        headers = {
+            ["Content-Type"] = "application/json"
+        },
+        body = '{"key": "value"}',
+        opts = {
+            adapter = socket.LWIP_ETH,
+            ca = ca_server,
+            client_cert = ca_client,
+            client_key = client_private_key_encrypts_data,
+            client_key_password = client_private_key_password
+        },
+        expected_code = 200,
+        description = "HTTPS POST方法,有请求头,body为json,带双向认证的服务器证书、客户端证书、客户端key,客户端password"
+    }}
+
+    for i, test in ipairs(tests) do
+        log.info("HTTP第" .. i .. "次测试")
+        -- sys.wait(5000)
+        local code, headers, body = http.request(test.method, test.url, test.headers, test.body, test.opts).wait()
+
+        -- 调试输出
+        print(string.format("Test %d: %s", i, test.description))
+        print("Returned values: code =", code, ", headers =", headers, ", body =", body)
+
+        -- 验证返回值
+        if code == test.expected_code then
+            log.info("本次测试的是", test.description, "code 符合预期结果 code = ", code)
+        else
+            log.info("本次测试的是", test.description, "预期结果为", test.expected_code,
+                "code 不符合预期结果 code =", code)
+
+        end
+    end
+end
+
+-- 运行测试用例
+sys.taskInit(function()
+
+    sys.waitUntil("CH390_IP_READY")
+    log.info("CH390 联网成功,开始测试")
+    socket.dft(socket.LWIP_ETH)
+    -- 如果自带的DNS不好用,可以用下面的公用DNS,但是一定是要在CH390联网成功后使用
+    -- socket.setDNS(socket.LWIP_ETH,1,"223.5.5.5")	
+    -- socket.setDNS(nil,1,"114.114.114.114")
+    run_tests()
+
+end)

+ 221 - 0
module/Air780EPM/demo/780EPM_1.3版本开发板 ch390h联网测试/wan/wan_multilink_mqtt.lua

@@ -0,0 +1,221 @@
+-- 自动低功耗, 轻休眠模式
+-- Air780E、Air780EP支持uart唤醒和网络数据下发唤醒, 但需要断开USB,或者pm.power(pm.USB, false) 但这样也看不到日志了
+-- pm.request(pm.LIGHT)
+-- 根据自己的服务器修改以下参数
+local mqtt_host = "lbsmqtt.airm2m.com"
+local mqtt_port = 1884
+local mqtt_isssl = false
+local client1_id = "abc"
+local client2_id = "abc2"
+local user_name = "user"
+local password = "password"
+
+--第一个mqtt链接
+local mqttc1 = nil
+local pub_topic_client = "/luatos/pub/client1/"
+local sub_topic_client = "/luatos/sub/client1/"
+
+--第二个mqtt链接
+local mqttc2 = nil
+local pub_topic_client2 = "/luatos/pub/client2/"
+local sub_topic_client2 = "/luatos/sub/client2/"
+
+local device_id = mobile.imei()
+
+sys.taskInit(function()
+    -- 等待联网
+
+    sys.waitUntil("CH390_IP_READY")
+    log.info("CH390 联网成功,开始测试")
+    socket.dft(socket.LWIP_ETH) -- 配置默认网卡为CH390
+
+    -- 如果自带的DNS不好用,可以用下面的公用DNS,但是一定是要在CH390联网成功后使用
+    -- socket.setDNS(socket.LWIP_ETH,1,"223.5.5.5")	
+    -- socket.setDNS(nil,1,"114.114.114.114")
+    -- local ret, device_id = sys.waitUntil("net_ready")
+    -- 下面的是mqtt的参数均可自行修改
+    -- client1_id = device_id
+    pub_topic_client = pub_topic_client .. device_id
+    sub_topic_client = sub_topic_client .. device_id
+
+    -- 打印一下上报(pub)和下发(sub)的topic名称
+    -- 上报: 设备 ---> 服务器
+    -- 下发: 设备 <--- 服务器
+    -- 可使用mqtt.x等客户端进行调试
+    log.info("mqtt", "pub", pub_topic_client)
+    log.info("mqtt", "sub", sub_topic_client)
+
+    if mqtt == nil then
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp未适配mqtt库, 请查证")
+        end
+    end
+
+    -------------------------------------
+    -------- MQTT 演示代码 --------------
+    -------------------------------------
+
+    mqttc1 = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
+
+    mqttc1:auth(client1_id, user_name, password) -- client_id必填,其余选填
+    -- mqttc1:keepalive(240) -- 默认值240s
+    mqttc1:autoreconn(true, 3000) -- 自动重连机制
+
+    mqttc1:on(function(mqtt_client, event, data, payload)
+        -- 用户自定义代码
+        log.info("mqtt", "event", event, mqtt_client, data, payload)
+        if event == "conack" then
+            -- 联上了
+            sys.publish("mqtt_conack")
+            mqtt_client:subscribe(sub_topic_client) -- 单主题订阅
+            -- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
+        elseif event == "recv" then
+            log.info("mqtt", "downlink", "topic", data, "payload", payload)
+            sys.publish("mqtt_payload", data, payload)
+        elseif event == "sent" then
+            -- log.info("mqtt", "sent", "pkgid", data)
+            -- elseif event == "disconnect" then
+            -- 非自动重连时,按需重启mqttc
+            -- mqtt_client:connect()
+        end
+    end)
+
+    -- mqttc自动处理重连, 除非自行关闭
+    mqttc1:connect()
+    sys.waitUntil("mqtt_conack")
+    while true do
+        -- 演示等待其他task发送过来的上报信息
+        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
+        if ret then
+            -- 提供关闭本while循环的途径, 不需要可以注释掉
+            if topic == "close" then
+                break
+            end
+            mqttc1:publish(topic, data, qos)
+        end
+        -- 如果没有其他task上报, 可以写个空等待
+        -- sys.wait(60000000)
+    end
+    mqttc1:close()
+    mqttc1 = nil
+end)
+
+-- 这里演示在另一个task里上报数据, 会定时上报数据,不需要就注释掉
+sys.taskInit(function()
+    sys.wait(3000)
+    local data = "123,"
+    local qos = 1 -- QOS0不带puback, QOS1是带puback的
+    while true do
+        sys.wait(3000)
+        if mqttc1 and mqttc1:ready() then
+            local pkgid = mqttc1:publish(pub_topic_client, data .. os.date(), qos)
+            -- local pkgid = mqttc1:publish(topic2, data, qos)
+            -- local pkgid = mqttc1:publish(topic3, data, qos)
+        end
+    end
+end)
+
+-- mqtt多链接示例
+sys.taskInit(function()
+    -- 等待联网
+    local ret, device_id = sys.waitUntil("net_ready")
+    -- 下面的是mqtt的参数均可自行修改
+    client2_id = device_id .. "2"
+    pub_topic_client2 = pub_topic_client2 .. device_id
+    sub_topic_client2 = sub_topic_client2 .. device_id
+
+    -- 打印一下上报(pub)和下发(sub)的topic名称
+    -- 上报: 设备 ---> 服务器
+    -- 下发: 设备 <--- 服务器
+    -- 可使用mqtt.x等客户端进行调试
+    log.info("mqtt", "pub", pub_topic_client2)
+    log.info("mqtt", "sub", sub_topic_client2)
+
+    -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
+    -- if crypto.cipher_suites then
+    --     log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
+    -- end
+    if mqtt == nil then
+        while 1 do
+            sys.wait(1000)
+            log.info("bsp", "本bsp未适配mqtt库, 请查证")
+        end
+    end
+
+    -------------------------------------
+    -------- MQTT 演示代码 --------------
+    -------------------------------------
+
+    mqttc2 = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl)
+
+    mqttc2:auth(client2_id, user_name, password) -- client_id必填,其余选填
+    -- mqttc2:keepalive(240) -- 默认值240s
+    mqttc2:autoreconn(true, 3000) -- 自动重连机制
+
+    mqttc2:on(function(mqtt_client, event, data, payload)
+        -- 用户自定义代码
+        log.info("mqtt", "event", event, mqtt_client, data, payload)
+        if event == "conack" then
+            -- 联上了
+            sys.publish("mqtt_conack")
+            mqtt_client:subscribe(sub_topic_client2) -- 单主题订阅
+            -- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
+        elseif event == "recv" then
+            log.info("mqtt", "downlink", "topic", data, "payload", payload)
+            sys.publish("mqtt_payload", data, payload)
+        elseif event == "sent" then
+            -- log.info("mqtt", "sent", "pkgid", data)
+            -- elseif event == "disconnect" then
+            -- 非自动重连时,按需重启mqttc
+            -- mqtt_client:connect()
+        end
+    end)
+
+    -- mqttc自动处理重连, 除非自行关闭
+    mqttc2:connect()
+    sys.waitUntil("mqtt_conack")
+    while true do
+        -- 演示等待其他task发送过来的上报信息
+        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
+        if ret then
+            -- 提供关闭本while循环的途径, 不需要可以注释掉
+            if topic == "close" then
+                break
+            end
+            mqttc2:publish(topic, data, qos)
+        end
+        -- 如果没有其他task上报, 可以写个空等待
+        -- sys.wait(60000000)
+    end
+    mqttc2:close()
+    mqttc2 = nil
+end)
+
+-- 这里演示在另一个task里上报数据, 会定时上报数据,不需要就注释掉
+sys.taskInit(function()
+    sys.wait(3000)
+    local data = "123,"
+    local qos = 1 -- QOS0不带puback, QOS1是带puback的
+    while true do
+        sys.wait(3000)
+        if mqttc2 and mqttc2:ready() then
+            local pkgid = mqttc2:publish(pub_topic_client2, data .. os.date(), qos)
+            -- local pkgid = mqttc2:publish(topic2, data, qos)
+            -- local pkgid = mqttc2:publish(topic3, data, qos)
+        end
+    end
+end)
+
+sys.taskInit(function()
+    while true do
+        sys.wait(3000)
+        log.info("lua", rtos.meminfo())
+        log.info("sys", rtos.meminfo("sys"))
+    end
+end)
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后后面不要加任何语句!!!!!

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff