-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = "fotademo"
VERSION = "1.0.0"

--[[
演示用uart进行固件升级

1. 需要 V1107及以上的固件
2. 需要 LuaTools 2.1.89 及以上的升级文件生成

目录内文件的说明
1. main.lua 本文件, 是下载到模块的唯一文件
2. fota_uart.bin 演示用的脚本升级文件,不需要下载到模块
3. main.py 上位机发送升级包的程序, 不需要下载到模块

fota_uart.bin 使用 LuaTools 的 "量产文件" 按钮进行生成, .bin后缀的就是脚本OTA文件

用法:
1. 先把脚本和固件烧录到模块里, 并确认开机
2. 进入命令行程序, 执行 python main.py 升级
3. 观察luatools的输出和main.py的输出
4. 模块接收正确的升级数据后,会提示1秒后重启
5. 本demo自带的脚本升级包,升级后是GPIO闪灯的demo

注意: 本demo默认是走虚拟串口进行交互, 如需改成物理串口, 修改uart_id和main.py
]]

_G.sys = require "sys"

-- 定义所需要的UART编号
-- uart_id = 1    -- 物理UART1, 通常也是MAIN_UART
uart_id = uart.VUART_0 -- 虚拟USB串口

-- 循环打印当前版本, 从而直观表示是否升级成功
-- sys.taskInit(function()
--     while 1 do
--         sys.wait(3000)
--         log.info("fota", "version", VERSION)
--     end
-- end)

-- 开始初始化uart
uart_zbuff = zbuff.create(1024)
uart.setup(uart_id, 115200)

-- 几个状态变量, 调试用
local uart_fota_state = 0
local uart_rx_counter = 0
local uart_fota_writed = 0
uart.on(uart_id, "receive", function(id, len)
    -- 防御缓冲区超标的情况
    if uart_zbuff:used() > 8192 then
        log.warn("fota", "uart_zbuff待处理的数据太多了,强制清空")
        uart_zbuff:del()
    end
    while 1 do
        local len = uart.rx(id, uart_zbuff)
        if len <= 0 then
            break
        end
        -- if #s > 0 then -- #s 是取字符串的长度
        uart_rx_counter = uart_rx_counter + len
        log.info("uart", "收到数据", len, "累计", uart_rx_counter)
        if uart_fota_state == 0 then
            sys.publish("UART_FOTA")
        end
    end
end)

sys.taskInit(function()
    local fota_state = 0 -- 0还没开始, 1进行中
    while 1 do
        -- 等待升级数据到来
        sys.waitUntil("UART_FOTA", 1000)
        local used = uart_zbuff:used()
        if used > 0 then
            if fota_state == 0 then
                -- 等待FOTA的状态
                if used > 5 then
                    local data = uart_zbuff:query()
                    uart_zbuff:del()
                    -- 如果接受到 #FOTA\n 代表数据要来了
                    if data:startsWith("#FOTA") and data:endsWith("\n") then
                        fota_state = 1
                        log.info("fota", "检测到fota起始标记,进入FOTA状态", data)
                        fota.init()
                        -- 固件数据发送端应该在收到#FOTA RDY\n之后才开始发送数据
                        uart.write(uart_id, "#FOTA RDY\n")
                    end
                end
            else
                uart_fota_writed = uart_fota_writed + used
                log.info("准备写入fota包", used, "累计写入", uart_fota_writed)
                local result, isDone, cache = fota.run(uart_zbuff)
                log.debug("fota.run", result, isDone, cache)
                uart_zbuff:del() -- 清空缓冲区
                if not result then
                    fota_state = 0
                    fota.isDone()
                    uart.write(uart_id, "#FOTA ERR\n")
                    log.info("fota", "出错了", result, isDone, cache)
                elseif isDone then
                    while true do
                        sys.wait(100)
                        local succ, fotaDone = fota.isDone()
                        if not succ then
                            fota_state = 0
                            uart.write(uart_id, "#FOTA ERR\n")
                            log.info("fota", "出错了")
                            break
                        end
                        if fotaDone then
                            uart_fota_state = 1
                            log.info("fota", "已完成,1s后重启")
                            -- 反馈给上位机
                            uart.write(uart_id, "#FOTA OK\n")
                            sys.wait(1000)
                            rtos.reboot()
                        end
                        sys.wait(100)
                    end
                else
                    log.info("fota", "单包写入完成", used, "等待下一个包")
                    uart.write(uart_id, "#FOTA NEXT\n")
                end
            end
        end
    end
end)

-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后后面不要加任何语句!!!!!
