#!/usr/bin/lua -- created by jiaqiang.ye@lnxall.com -- Monitor hci status -- 2022/06/11 local cjson = require "cjson" local invoker = require "invoker" local dmesg_clear = nil local CHECK_INTERVAL = 60 local function load_json(jcfg) local jfil = io.open(jcfg, "rb") if not jfil then return nil end local jdat = jfil:read("*a") jfil:close(); jfil = nil local okay, jval = pcall(cjson.decode, jdat) if not okay then return nil end return jval end local function load_last_check(filp) local fild = load_json(filp) local upt = invoker.uptime() local rval = { ["hci0"] = upt, ["hci1"] = upt, ["hci2"] = upt, ["hci3"] = upt } if not fild then return rval, true end if fild["hci0"] then rval["hci0"] = fild["hci0"] end if fild["hci1"] then rval["hci1"] = fild["hci1"] end if fild["hci2"] then rval["hci2"] = fild["hci2"] end if fild["hci3"] then rval["hci3"] = fild["hci3"] end return rval, false end local function hci_isok(hdev) local eval, pbuf = invoker.invoke(invoker.OUTPUT + invoker.NOSTDIO, "hciconfig", hdev, "-a") if eval ~= 0 then -- hci device not found return true end if string.find(pbuf, "DOWN", 1, true) then return false end if string.find(pbuf, "Operation timed out", 1, true) then return false end -- print(string.format("HCI deivce is ok: %s", hdev)) return true end local function check_hci_devs() local cfile = "/tmp/hci_check.log" local last, update = load_last_check(cfile) local upt, err = invoker.uptime(), false for hdev, when in pairs(last) do if (upt - when) > CHECK_INTERVAL then if not hci_isok(hdev) then err = true break end update = true last[hdev] = upt end end if err or update then if err then last = { ["hci0"] = upt, ["hci1"] = upt, ["hci2"] = upt, ["hci3"] = upt } end local lastd = cjson.encode(last) local pfile = io.open(cfile, "wb") if pfile then pfile:write(lastd) pfile:close(); pfile = nil end end if not err then local iflags = invoker.OUTPUT + invoker.BUFSIZ + 0x3F0000 local _, klog = invoker.invoke(iflags, "dmesg", dmesg_clear) if type(klog) == "string" and string.find(klog, "Bluetooth: hci. hardware error") then local filp = io.open("/tmp/hci_hardware_error.log", "wb") if filp then filp:write(string.format("%s: Bluetooth hardware error, resetting...\n", os.date())) filp:close() end invoker.invoke(invoker.NOSTDIO, "dmesg", "-c") else return true end end local bledaemon = "/etc/init.d/bluetoothd" io.stdout:write("WTF: reload all BLE services\n") invoker.invoke(0, "logger", "-t", "BLE-SUP", "reload all BLE services") for idx = 1, 4 do local initd = string.format("/etc/init.d/ble_%d", idx) inovker.invoke(invoker.NOSTDIO, initd, "stop") inovker.invoke(invoker.NOSTDIO, initd, "stop") end inovker.invoke(invoker.NOSTDIO, bledaemon, "stop") inovker.invoke(invoker.NOSTDIO, bledaemon, "stop") invoker.waitsec(0x2) -- bring all hci devices up inovker.invoke(invoker.NOSTDIO, "hciconfig", "hci0", "up") inovker.invoke(invoker.NOSTDIO, "hciconfig", "hci1", "up") inovker.invoke(invoker.NOSTDIO, "hciconfig", "hci2", "up") inovker.invoke(invoker.NOSTDIO, "hciconfig", "hci3", "up") invoker.waitsec(0x1) inovker.invoke(invoker.NOSTDIO, bledaemon, "start") invoker.waitsec(0x2) for idx = 1, 4 do local initd = string.format("/etc/init.d/ble_%d", idx) inovker.invoke(invoker.NOSTDIO, initd, "start") end return true end if type(arg[1]) ~= "nil" then dmesg_clear = "-c" end check_hci_devs()