--[[**e180_uart_data.lua***********Copyright(c)*****************************
**                Guangzhou DACAIGAUNGDIAN Technology Co. Ltd
**
**                             http://www.gz-dc.com
**
**------File Info-----------------------------------------------------------
** File Name:               e180_uart_data.lua
** Latest modified Date:    2022/08/19
** Latest Version:          
** Description:             zigbee模块串口数据处理。
**
**--------------------------------------------------------------------------
** Created By:              lsj
** Created date:            2022/08/19
** Version:                 V0.1
** Descriptions:            
**
***************************************************************************--]]
--[[
ZGB握手
1、

--]]

eud={}                      --本文件所有数据的表

--接收数据的存储变量
eud.dataversion = 0         --传输模式下的数据版本
eud.datatype = 0            --传输模式下的数据命令字
eud.datalen = 0             --传输模式下的数据长度
eud.datavalue = {}          --传输模式下的数据，从0开始

eud.uart_recv_data2 = {}    --传输模式下，串口接收的所有数据

eud.en_debug = 0    --0-不显示调试信息;1-虚拟屏; 2-实体屏，串口1输出
--[[***************************************************************************
** Function name:  eud.my_uart_log
** Descriptions:   打印虚拟屏调试信息，设置 eud.en_debug = 1
                   注意：实体屏运行时， eud.en_debug 不能等于 1
                   打印实体屏调试信息，设置 eud.en_debug = 2
                   注意：虚拟屏运行时，eud.en_debug 不能等于 2
***************************************************************************--]]
function eud.my_uart_log(debug_msg)
    if eud.en_debug == 1
    then
        print(debug_msg)
    elseif eud.en_debug == 2
    then
        uart_send_string(debug_msg)
    end
end

eudsc = {}                          --传输模式下的当前指令的存储表
eudsc.senddata = {}                 --传输模式下的当前发送的命令
eudsc.ack = {}                      --传输模式下的当前发送的命令的应答
eudsc.acktimeout = 0                --传输模式下的当前命令的超时时间
eudsc.timerid_acktimeout = 12       --传输模式下的当前命令超时定时器id
eudsc.callback = nil                --传输模式下的当前命令的应答回调函数

--启动超时定时器
function eudsc.start_timeout(acktimeout)
    stop_timer(eudsc.timerid_acktimeout)
    start_timer(eudsc.timerid_acktimeout,acktimeout,0,0)
end

--暂停超时定时器
function eudsc.stop_timeout()
    stop_timer(eudsc.timerid_acktimeout)
end

--传输模式下的命令发送
function eudsc.sendcmd(senddata,ack,timeout,callback)
    if senddata ~= nil
    then
        eudsc.senddata = senddata
        e180.send_callback( eudsc.senddata )
    end
    
    if ack ~= nil
    then
        eudsc.ack = ack
    end
    
    if timeout ~= nil
    then
        eudsc.acktimeout = timeout
        eudsc.start_timeout(eudsc.acktimeout)
    end
    
    if callback ~= nil
    then
        eudsc.callback = callback
    end
end

--超时处理
function eudsc.cmd_acktimeout()
    if eudsc.callback~=nil
    then
        eudsc.callback(eudsc.senddata,'timeout')
    end
    user_acktimeout()
    eudsc.senddata = {}
    eudsc.ack = {}
    eudsc.acktimeout = 0
    eudsc.callback = nil
end

-- combination_data 组合要发送的数据
-- dvalue从下标0开始
--[[***************************************************************************
** Function name:  eudsc.c_d
** Descriptions :  组合完整的发送指令
** @dversion    ： 发送版本号
** @dtype       ： 发送类型
** @dvalue      ： 发送数据
** return       ： 发送组合后的指令
***************************************************************************--]]
function eudsc.c_d(dversion,dtype,dvalue)
    local c_sdata = {}
    c_sdata[0] = 0x55
    c_sdata[1] = 0xAA
    c_sdata[2] = dversion
    c_sdata[3] = dtype
    local ddatalen = 0
    if dvalue == nil
    then
        c_sdata[4] = 0
        c_sdata[5] = 0
    elseif dvalue ~= nil
    then
        if type(dvalue) == 'number'
        then
            ddatalen = 1
            c_sdata[4] = 0x00
            c_sdata[5] = 0x01
            c_sdata[6] = dvalue
        elseif type(dvalue) == 'table'
        then
            ddatalen = #dvalue + 1
            c_sdata[4] = (ddatalen>>8) & 0xFF
            c_sdata[5] = ddatalen & 0xFF
            for i=0,ddatalen-1
            do
                c_sdata[6+i] = dvalue[i]
            end
        end
    end
    local dsum = 0
    for i=0,#c_sdata
    do
        dsum = dsum + c_sdata[i]
    end
    c_sdata[5+ddatalen+1] = dsum&0xFF
    return c_sdata
end

eud.e180_local_shaddr = -1      --本地短地址
eud.e180_parent_shaddr = -1     --父节点短地址

eud.timerid_sh = 11             --握手定时器
eud.timerout_sh = 2000          --握手超时

eud.timerid_getaddr = 13        --定时一段时间后获取短地址
eud.timerout_getaddr = 2000

--[[***************************************************************************
** Function name:  wbr3.table2str16
** Descriptions :  把表转换成十六进制形式的字符串
***************************************************************************--]]
function eud.table2str16(tbl)
    if tbl==nil
    then return '' end
    
    local str = ''
    local count = #(tbl)
    for i=0,count do
        ch = string.format('%02X',tbl[i])
        str = str..' '..ch
    end
    return str
end

--初始化为终端
function eud.init_end_device()
    function on_eud_ieden_cb(key,value)
        if value=='timeout'
        then
            e180.enter_confg_mode('config')
        end
    end
    
    function on_eud_ientercn_cb(key,value)
        if value=='timeout'
        then
            -- e180.log('eud_ientercn_cb -1 -1')
            -- e180.cmd_list_clear()
            -- e180.my_uart_log('timeout')
            -- e180.log('timeout')
            -- set_text(screen_zgbtest,15,'timeout')
        end
        
    end
    
    function on_eud_irestart_cb(key,value)
        local value_ack = {[0]=0xFA,0x12}
        if _ex.contrast_table(value,value_ack)
        then
            e180.enter_confg_mode('transfer')
            stop_timer( eud.timerid_getaddr )
            start_timer( eud.timerid_getaddr, eud.timerout_getaddr, 0, 1 )
        end
    end
    
    e180.cmd_add( '', 0x17283955, 1000, 0, on_eud_ieden_cb )  --延时
    local send_data = {0x2D,0x2E}
    send_data[0] = 0x2A
    local re_ack = {0x7D,0x7E}
    re_ack[0] = 0x7A
    e180.cmd_add( send_data, re_ack, 1500, 999, on_eud_ientercn_cb ) --进入配置模式Enter configuration mode
    
    local send_data = {0x01,0x01,0X03,0XFF}
    send_data[0] = 0xFD
    local re_ack = {0x01}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 5000, 0 )  --配置终端
    
    local send_data = {0x01,0x0A,0X19,0XFF}
    send_data[0] = 0xFD
    local re_ack = {0x0A}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置信道
    
    local send_data = {0x01,0x0B,0X0A,0XFF}
    send_data[0] = 0xFD
    local re_ack = {0x0B}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置发送功率
    
    local send_data = {0x02,0x03,0XFF,0XFF,0XFF}
    send_data[0] = 0xFD
    local re_ack = {0x03}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置PANID
    
    local send_data = {0x01,0x26,0X02,0XFF}
    send_data[0] = 0xFD
    local re_ack = {0x26}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置系统发送模式 透传点播+短地址
    
    local send_data = {0x00,0x12,0xFF}
    send_data[0] = 0xFD
    local re_ack = {[0]=0xFA,0x12}
    e180.cmd_add( send_data, re_ack, 1500, 3, on_eud_irestart_cb)  --重启设备
    
    -- local send_data = {0x2C,0x2B}
    -- send_data[0] = 0x2F
    -- local re_ack = {0x7C,0x7B}
    -- re_ack[0] = 0x7F
    -- e180.cmd_add( send_data, re_ack, 1000, 0, on_eud_irecn_cb )  --退出配置模式
    
    e180.cmd_add( '', 0x17283955, 1000, 0 )  --延时
    
end

--查询地址，Querying a Short Address
function eud.query_short_addr(on_qget_addr_cb)
    function on_eud_qsaen_cb(key,value)
        if value=='timeout'
        then
            e180.enter_confg_mode('config')
        end
    end
    
    function on_eud_qsacn_cb(key,value)
        local value_ack1 = {[0]=0x7F,0x7C,0x7B}    --退出配置模式
        local value_ack2 = {[0]=0xFA,0x12}           --重启zgb设备
        if _ex.contrast_table(value,value_ack1)
        or _ex.contrast_table(value,value_ack2)
        then
            e180.enter_confg_mode('transfer')
        end
    end
    
    e180.cmd_add( '', 0x17283955, 1000, 0, on_eud_qsaen_cb )  --延时
    local send_data = {0x2D,0x2E}
    send_data[0] = 0x2A
    local re_ack = {0x7D,0x7E}
    re_ack[0] = 0x7A
    --e180.cmd_add( send_data, 0, 1000, 0, eud_qentercn_cb ) --进入配置模式Enter configuration mode
    e180.cmd_add( send_data, re_ack, 1500, 10, eud_qentercn_cb ) --进入配置模式Enter configuration mode
    
    local send_data = {0x02,0x05,0XFF}
    send_data[0] = 0xFE
    local re_ack = {0x05}
    re_ack[0] = 0xFB
    e180.cmd_add( send_data, re_ack, 3000, 0, on_qget_addr_cb )  --读取本地网络短地址
    
    local send_data = {0x02,0x07,0XFF}
    send_data[0] = 0xFE
    local re_ack = {0x07}
    re_ack[0] = 0xFB
    e180.cmd_add( send_data, re_ack, 3000, 0, on_qget_addr_cb )  --读取父节点网络短地址
    
    local send_data = {0x2C,0x2B}
    send_data[0] = 0x2F
    local re_ack = {[0]=0x7F,0x7C,0x7B}
    e180.cmd_add( send_data, re_ack, 1500, 3, on_eud_qsacn_cb )  --退出配置模式
    
    -- local send_data = {0x00,0x12,0xFF}
    -- send_data[0] = 0xFD
    -- local re_ack = {[0]=0xFA,0x12}
    -- e180.cmd_add( send_data, re_ack, 1500, 3, on_eud_qsacn_cb)  --重启设备
    
    e180.cmd_add( '', 0x17283955, 1000, 0 )  --延时
end

--获取网络短地址的回调数据处理
function on_e180_get_addr_cb(key,value)
    
    key_ack = { [0]=0xFE,0x02,0x05 }
    value_ack = { [0]=0xFB,0x05 }
    if _ex.contrast_table(key,key_ack)
    then
        local res=_ex.contrast_table(value,value_ack)
        if res~=false
        then            --本地网络短地址
            
            eud.e180_local_shaddr = value[res+2]<<8 | value[res+3]
            on_e180_log_cb('local 0x'..string.format('%04X',eud.e180_local_shaddr))
            set_text(screen_zgbtest,2,'0x'..string.format('%04X',eud.e180_local_shaddr))
        elseif type(value)=='string'
        then
            if value == 'timeout'
            then
                set_text( screen_zgbtest, 2, 'error' )
            end
        end
    end
    
    key_ack = { [0]=0xFE,0x02,0x07 }
    value_ack = { [0]=0xFB,0x07 }
    if _ex.contrast_table(key,key_ack)
    then
        local res=_ex.contrast_table(value,value_ack)
        if res~=false
        then            --父节点网络短地址
            eud.e180_parent_shaddr = value[res+2]<<8 | value[res+3]
            on_e180_log_cb('parent 0x'..string.format('%04X',eud.e180_parent_shaddr))
            set_text(screen_zgbtest,10,'0x'..string.format('%04X',eud.e180_parent_shaddr))
            eud.set_target_shaddr(eud.e180_parent_shaddr)
        elseif type(value)=='string'
        then
            if value == 'timeout'
            then
                set_text( screen_zgbtest, 10, 'error' )
            end
        end
    end
    
    if eud.e180_local_shaddr == -1 and eud.e180_parent_shaddr == -1
    then
        eud.init_end_device()       --获取不成功，重新获取
    elseif eud.e180_local_shaddr == 0xFFFE or eud.e180_parent_shaddr == 0xFFFF
    then
        eud.init_end_device()       --地址返回错误，重新获取
    elseif eud.e180_parent_shaddr == -1
    then
        eud.init_end_device()       --获取不成功，重新获取
    end
end

--设置目标短地址
function eud.set_target_shaddr(target_shaddr)
    
    function on_eud_stsen_cb(key,value)
        if value=='timeout'
        then
            e180.enter_confg_mode('config')
        end
    end
    
    function on_eud_stsrestart_cb(key,value)
        local value_ack = {[0] = 0xFA,0x12}
        if _ex.contrast_table(value,value_ack)
        then
            e180.enter_confg_mode('transfer')
            stop_timer(eud.timerid_sh)
            start_timer(eud.timerid_sh,eud.timerout_sh,0,0)
        end
    end
    
    e180.cmd_add( '', 0x17283955, 1000, 0, on_eud_stsen_cb )  --延时
    local send_data = {[0] = 0x2A,0x2D,0x2E}
    send_data[0] = 0x2A
    local re_ack = {[0] = 0x7A,0x7D,0x7E}
    re_ack[0] = 0x7A
    e180.cmd_add( send_data, re_ack, 1500, 10 ) --进入配置模式Enter configuration mode
    
    local send_data = {[0] = 0xFD,0x01,0x26,0X02,0XFF}
    send_data[0] = 0xFD
    local re_ack = {[0] = 0xFA,0x26}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置系统发送模式 透传点播+短地址
    
    local send_data = {[0] = 0xFD,0x02,0x23,[5]=0XFF}
    send_data[0] = 0xFD
    send_data[3] = target_shaddr>>8 & 0xFF
    send_data[4] = target_shaddr& 0xFF
    local re_ack = {[0] = 0xFA,0x26}
    re_ack[0] = 0xFA
    e180.cmd_add( send_data, re_ack, 1000, 0 )  --配置目标短地址
    
    local send_data = {[0] = 0xFD,0x00,0x12,0xFF}
    local re_ack = {[0] = 0xFA,0x12}
    e180.cmd_add( send_data, re_ack, 1500, 3, on_eud_stsrestart_cb)  --重启设备
    
    -- local send_data = {0x2C,0x2B}
    -- send_data[0] = 0x2F
    -- local re_ack = {0x7C,0x7B}
    -- re_ack[0] = 0x7F
    -- e180.cmd_add( send_data, re_ack, 1000, 0, eud_recn_cb )  --退出配置模式
    
    e180.cmd_add( '', 0x17283955, 1000, 0 )  --延时
    
end

--e180传输模式下的串口数据接收函数
--这里给出一种串口命令的参考例子
-- 帧头      2     0x55AA
-- 版本      1     0x00
-- 命令字    1     0x06
-- 数据长度  2     取决于命令数据单元类型以及个数
-- 数据      N     状态数据单元组
-- 校验和    1     从帧头开始，按字节求和，得出的结果对256 求余
-- 55 AA 00 06 00 05 03 01 00 01 01 10  
function eud.usrt_recv_response( packet )
    
    local rem_num = 0
    
    local cur_num = 0
    if #eud.uart_recv_data2 == 0
    then
        if eud.uart_recv_data2[0] == nil
        then
            cur_num = 0
        else
            cur_num = 1
        end
        
    elseif #eud.uart_recv_data2 ~= 0
    then
        cur_num = #eud.uart_recv_data2 + 1
    end
    
    for i=0,#(packet)
    do
        
        eud.uart_recv_data2[cur_num] = packet[i]        --从 eud.uart_recv_data2[0] 开始存     
        cur_num = cur_num + 1
        
    end
    
    eud.my_uart_log('WBR3IN:'..eud.table2str16(eud.uart_recv_data2))
    ----串口命令例子解析 55 AA 00 06 00 05 03 01 00 01 01 10    检验和（从帧头开始，按字节求和，得出的结果对256 求余）
    local dlength = 0
    local dsum = 0
    for i=0,#(eud.uart_recv_data2)
    do
        if eud.uart_recv_data2[i] == 0x55 and eud.uart_recv_data2[i+1] == 0xAA
        then                                                --帧头正确，55 AA
            dlength = (eud.uart_recv_data2[i+4]<<8) | eud.uart_recv_data2[i+5]  --长度，00 05
            
            if dlength < 20 and ( ( dlength+i+5+1 ) <= #eud.uart_recv_data2 )
            then                                            --确认缓存变量中的数据长度比指令长
                for j=0,(dlength+5)
                do
                    dsum = dsum + eud.uart_recv_data2[i+j]      --计算校验和，10
                end
                if (dsum&0xFF) == eud.uart_recv_data2[i+6+dlength]
                then                                    --对比校验，接收到完整指令
                    eud.dataversion = eud.uart_recv_data2[i+2]      --版本，00
                    eud.datatype = eud.uart_recv_data2[i+3]         --命令字，06
                    eud.datalen = dlength               --数据长度
                    if eud.datalen > 0
                    then                                --数据，03 01 00 01 01
                        for k=0,eud.datalen-1
                        do
                            eud.datavalue[k] = eud.uart_recv_data2[i+6+k]
                        end                            
                        
                    end
                    local _data_complete = {}
                    for k=0,(dlength+6)
                    do
                        _data_complete[k] = eud.uart_recv_data2[i+k]    --把完整指令获取出来
                    end     --完整指令接收完成
                    
                    eud.my_uart_log('WBR3IN complete:'..eud.table2str16(_data_complete))        --打印完整指令
                    eud.user_uart_check_ack(_data_complete)     --透传命令处理
                    eud.uart_recv_data2={}
                    eud.dataversion = 0        --版本
                    eud.datatype = 0           --命令字
                    eud.datalen = 0            --数据长度
                    eud.datavalue = {}         --数据，从0开始
                end
            end
        end
    end
    
    if #(eud.uart_recv_data2)>50          --接收数组大于1024字节时，数组清空
    then
        eud.uart_recv_data2={}
    end
end

local uartsh_totsucnum = 0  --成功总次数
local uartsh_cursucnum = 0  --本次成功次数
local uartsh_totfalnum = 0  --失败总次数
local uartsh_curfalnum = 0  --本次失败次数

--握手命令，数据代表次数，XX XX是终端短地址
--屏发送   55 AA 00 04 00 04 XX XX 00 01 和
--工装返回 55 AA 01 04 00 04 XX XX 00 01 和
function eud.user_uart_check_ack(pdata)
    -- if eud.dataversion == 0x01
    -- and eud.datatype == 0x04
    -- and eud.datalen == 0x04
    -- then                            --收到握手返回的命令
        
        -- if eud.datavalue[0]==eud.e180_local_shaddr>>8&0xFF
        -- and eud.datavalue[1]==eud.e180_local_shaddr&0xFF
        -- then
            -- uartsh_totsucnum = uartsh_totsucnum + 1
            -- uartsh_cursucnum = uartsh_cursucnum + 1
            -- uartsh_curfalnum = 0
            -- on_e180_log_cb('SH SUC ='..uartsh_totsucnum)
            -- set_text(screen_zgbsh,12,'con suc:'..uartsh_cursucnum)
            -- set_value(screen_zgbsh,1,0)        --设置通信图标显示通信成功
-- on_e180_log_cb('ack ok')
-- eudsc.stop_timeout()
        -- end
    -- end
    
    if eudsc.senddata == nil
    then
        eud.on_e180_resp_callback(nil,pdata)
    else
        eud.on_e180_resp_callback(eudsc.senddata,pdata)
    end
    
    if eudsc.callback~=nil
    then
        if eudsc.senddata == nil
        then
            eudsc.callback(nil,pdata)
        else
            eudsc.callback(eudsc.senddata,pdata)
        end
    end
    
    if _ex.contrast_table(pdata,eudsc.ack)
    then    
        on_e180_log_cb('ack ok')
        eudsc.stop_timeout()
    end
end

--通用数据处理回调函数
function eud.on_e180_resp_callback(key,value)
    
end

--通用的，传输模式下，超时回调
function user_acktimeout()
    
end

local test_se_en = 1    --测试，握手开关
--发送握手指令
function eud.send_shake_hands(local_addr,snum)
    if test_se_en == 1
    then
        local data={}
        data[0] = local_addr>>8 & 0xFF
        data[1] = local_addr & 0xFF
        data[2] = snum>>8 & 0xFF
        data[3] = snum & 0xFF
        local data_ack={[0]=0x55,0xAA,0x01}
        eudsc.sendcmd(eudsc.c_d(0x00,0x04,data),data_ack,1500,on_eud_ssh_cb)
    end
end

--握手指令处理回调函数
function on_eud_ssh_cb(key,value)
    if type(value) == 'table'
    then
        if eud.dataversion == 0x01
        and eud.datatype == 0x04
        and eud.datalen == 0x04
        then                        --收到握手返回的命令
            if eud.datavalue[0]==eud.e180_local_shaddr>>8&0xFF
            and eud.datavalue[1]==eud.e180_local_shaddr&0xFF
            then
                uartsh_totsucnum = uartsh_totsucnum + 1
                uartsh_cursucnum = uartsh_cursucnum + 1
                uartsh_curfalnum = 0
                on_e180_log_cb('SH SUC ='..uartsh_totsucnum)
                set_text(screen_zgbsh,12,'con suc:'..uartsh_cursucnum)
                set_value(screen_zgbsh,1,0)        --设置通信图标显示通信失败
            end
        end
    elseif type(value) == 'string'
    then
        uartsh_totfalnum = uartsh_totfalnum + 1
        uartsh_curfalnum = uartsh_curfalnum + 1
        set_text(screen_zgbsh,12,'con false:'..uartsh_curfalnum)
        set_value(screen_zgbsh,1,1)        --设置通信图标显示通信失败
        uartsh_cursucnum = 0
        if uartsh_curfalnum >= 3
        then
            uartsh_curfalnum = 0
            stop_timer(eud.timerid_sh)
            eud.init_end_device()
        end
    end
end

--本文件中的定时器回调
function eud.on_init()
    set_enable(screen_zgbsh,1,0)        --设置通信成功图标禁止触摸
    set_value(screen_zgbsh,1,1)        --设置通信图标先显示通信失败
end

--本文件中的定时器回调
function eud.on_timer(timer_id)
    if timer_id == eud.timerid_sh
    then                                --握手
        eud.send_shake_hands( eud.e180_local_shaddr, 0x01 )
    elseif timer_id == eudsc.timerid_acktimeout
    then                                --传输模式下指令应答超时
        eudsc.cmd_acktimeout()
    elseif timer_id == eud.timerid_getaddr
    then                                --查询短地址
        eud.query_short_addr(on_e180_get_addr_cb)
    end
end

--本文件中的按钮回调
function eud.on_control_notify(screen,control,value)
    if screen == screen_zgbsh
    then
        
    elseif screen == screen_zgbtest
    then
        if control == 13
        then                    --测试，数据记录开关
            if value == 0
            then
                test_re_en = 1
            else
                test_re_en = 0
            end 
        end
        if control == 14
        then                    --测试，握手开关
            if value == 0
            then
                test_se_en = 1
            else
                test_se_en = 0
            end
        end
    end
end


