| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- module(..., package.seeall)
- require"radio"
- require "sx126x_driver"
- -- --------------------- 常量定义 ---------------------
- local MASTER_ADDR = 0x00
- local MIN_SLAVE_ADDR = 0x01
- local MAX_SLAVE_ADDR = 0x05
- local QUERY_TIMEOUT_MS = 6
- local FRAME_HEADER1 = 0x5A
- local FRAME_HEADER2 = 0xA5
- local FRAME_TYPE_QUERY = 0x03
- local FRAME_TYPE_DATA = 0x02
- -- --------------------- 工具函数 ---------------------
- -- CRC16 (Modbus)
- local function Modbus_CRC16(data, len)
- local crc = 0xFFFF
- for i = 1, len do
- crc = bit.bxor(crc, data[i])
- for _ = 1, 8 do
- if bit.band(crc, 0x0001) ~= 0 then
- crc = bit.rshift(crc,1)
- crc = bit.bxor(crc,0xA001)
- else
- crc = bit.rshift(crc,1)
- end
- end
- end
- return bit.rshift(crc,8) + bit.lshift(bit.band(crc,0xFF),8)
- end
- -- 工具函数:将“十进制字节表”转为“十六进制字符串”(如 {0x5A, 0xA5} → "5AA5")
- local function byte_table_to_hex_str(byte_table)
- local hex_str = ""
- for _, byte_val in ipairs(byte_table) do
- -- 确保每个字节转为两位十六进制(不足两位补0,如0x5 → "05")
- hex_str = hex_str .. string.format("%02X", byte_val)
- end
- return hex_str
- end
- -- 将 {0x5A,0xA5} 转成 "\x5A\xA5" 这种二进制字符串
- local function byte_table_to_bin_str(byte_table)
- local chars = {}
- for i = 1, #byte_table do
- chars[i] = string.char(byte_table[i])
- end
- return table.concat(chars)
- end
- -- --------------------- 发送查询帧 ---------------------
- local function send_query_frame(slave_addr)
- log.info("Frame","发送查询帧",slave_addr)
- local buf = {
- FRAME_HEADER1, FRAME_HEADER2,
- MASTER_ADDR, slave_addr,
- FRAME_TYPE_QUERY,
- 0x00, 0x00 -- reserved
- }
- local crc = Modbus_CRC16(buf, #buf)
- table.insert(buf, bit.band(crc,0xFF)) -- CRC低字节
- table.insert(buf, bit.rshift(crc,8)) -- CRC高字节
- log.info("查询帧构建完毕,长度="..#buf.."字节")
- -- ✅ 转换成二进制字符串
- local hex_buf = byte_table_to_hex_str(buf)
- local lenHex = string.format("%02X", #buf)
- sx126x_driver.RadioSend(hex_buf, lenHex, "00")
- -- sys.wait(200)
- log.info("查询帧发送完毕,配置的PayloadLength="..#buf)
- end
- -- -- --------------------- 解析传感器数据 ---------------------
- local function bytes_to_float(b1,b2,b3,b4)
- local sign = bit.rshift(b4,7)
- local expo = bit.band(bit.rshift(b4,0),0x7F) * 2 + bit.rshift(b3,7)
- local mant = bit.lshift(bit.band(b3,0x7F),16) + bit.lshift(b2,8) + b1
- if expo == 0 then
- return 0.0
- elseif expo == 255 then
- return (mant == 0) and (sign==0 and math.huge or -math.huge) or 0/0
- end
- return (sign==1 and -1 or 1) * (1 + mant/0x800000) * 2^(expo-127)
- end
- -- 解码传感器数据,返回 (value, unit, type)
- local function decode_sensor(sensor)
- if sensor.data_type == 0x01 then
- local t = bit.lshift(sensor.data[1],8) + sensor.data[2]
- return t / 100.0, "°C", "temperature"
- elseif sensor.data_type == 0x02 then
- local h = bit.lshift(sensor.data[1],8) + sensor.data[2]
- return h / 100.0, "%", "humidity"
- elseif sensor.data_type == 0x03 then
- return sensor.data[1], "lux", "light"
- elseif sensor.data_type == 0x04 then
- return sensor.data[1], "ppm", "smoke"
- elseif sensor.data_type == 0x10 then
- if #sensor.data == 4 then
- local val = bytes_to_float(sensor.data[1],sensor.data[2],sensor.data[3],sensor.data[4])
- return val, "L", "liquid"
- end
- end
- return sensor.data, "raw", "unknown"
- end
- -- 解析接收到的帧,返回符合 JSON 格式的表
- local function parse_received_frame(hex_str)
- local buf = {}
- for i = 1, #hex_str, 2 do
- local hex_byte = hex_str:sub(i, i+1)
- table.insert(buf, tonumber(hex_byte, 16))
- end
- if #buf < 9 then return nil end
- if buf[1] ~= FRAME_HEADER1 or buf[2] ~= FRAME_HEADER2 then return nil end
- local src_addr = buf[3]
- local dst_addr = buf[4]
- local frame_type = buf[5]
- if dst_addr ~= MASTER_ADDR or frame_type ~= FRAME_TYPE_DATA then return nil end
- local sensor_count = buf[6]
- local data_total_len = buf[7]
- -- CRC 校验
- local crc_low, crc_high = buf[#buf-1], buf[#buf]
- local crc_recv = crc_low + bit.lshift(crc_high,8)
- local crc_calc = Modbus_CRC16(buf, #buf-2)
- if crc_recv ~= crc_calc then return nil end
- -- ✅ 返回简洁 JSON
- local result = {
- ts = os.time(),
- addr = src_addr,
- sensors = {}
- }
- local offset = 8
- local data_end = 8 + data_total_len - 1
- for i = 1, sensor_count do
- if offset + 2 > data_end then break end
- local sensor = {
- id = buf[offset],
- data_type = buf[offset+1],
- data_len = buf[offset+2],
- data = {}
- }
- for j = 1, sensor.data_len do
- table.insert(sensor.data, buf[offset+2+j])
- end
- local value, unit, type = decode_sensor(sensor)
- table.insert(result.sensors, {
- id = sensor.id,
- type = type,
- value = value,
- unit = unit
- })
- offset = offset + 3 + sensor.data_len
- end
- return result
- end
- -- --------------------- 主机轮询 ---------------------
- function master_query_loop()
-
- for addr=MIN_SLAVE_ADDR, MAX_SLAVE_ADDR do
- sx126x_driver.ReceiveData = ""
- log.info("Host","查询从机地址",string.format("0x%02X",addr))
- send_query_frame(addr)
- local start = os.time()
- local response = false
- while (os.time()-start) < QUERY_TIMEOUT_MS do
- if sx126x_driver.dataReady() then
- local rx_buf = sx126x_driver.RadioGetBuffer()
- log.info("Host","收到从机数据", "十六进制字符串="..rx_buf)
- if rx_buf == "" then
- log.info("返回空")
- break
- end
- local slave_addr_hex = string.format("%02X", addr) -- 把当前查询的从机地址转成两位十六进制字符串
- log.info("slave_addr_hex",slave_addr_hex)
- -- log.info("rx_buf:sub(7,8)",rx_buf:sub(7,8))
- -- log.info("rx_buf:sub(5,6)",rx_buf:sub(5,6))
- if rx_buf:sub(1,2) ~= "5A" then
- log.info("帧头错误")
- break
- end
- if rx_buf:sub(5,6) ~= slave_addr_hex then
- log.info("从机地址不匹配")
- break
- end
- if rx_buf:sub(7,8) ~= "00" then
- log.info("主机地址不匹配")
- break
- end
- local result = parse_received_frame(rx_buf)
- if result then
- -- 发布事件,外部来处理
- sys.publish("SENSOR_UPDATE",result)
- break
- end
- end
- sys.wait(50)
- end
- if not response then
- -- log.warn("Host",string.format("从机0x%02X无响应",addr))
- end
- sys.wait(5000)
- end
- end
- sys.taskInit(function()
- sys.wait(10000)
- radio.RadioInit()
- radio.RadioStandby()
- sx126x_driver.RadioSetTxConfig(sx126x_reg.RadioModems_t.MODEM_LORA,"16",0,1,7,"01","0c","00","01","00","00","00",3000)
- sx126x_driver.RadioSetChannel(433000000)
- sys.wait(2000)
- sx126x_driver.RadioRx(0)
- local payload = "Hehehe123456"
- local num = 1
- while true do
- master_query_loop()
- -- send_query_frame(0x01)
- -- RadioStandby()
- -- sx126x_driver.sentString("hello,My_name_is_XuXinyi\n")
- sys.wait(1500)
- log.info("Radio", "测试接收数据中。。。")
-
- -- sx126x_driver.sentString("5AA50005030000093C")
- -- sx126x_driver.sentString(payload)
- -- sx126x_driver.RadioRx(0)
- -- -- -- sx126x_driver.RadioRx(0)
- -- sx126x_driver.SX126xWakeup()
-
- -- payload = payload .. num
- -- num = num + 1
- end
- end)
|