/
Sangak
/
ardupilot
Обзор
Документация
Войти
/
Sangak
/
ardupilot
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
libraries/AP_Scripting/drivers/Generator_SVFFI.lua
249 строк
9 KB
Iampete1
AP_Scripting: ignore lua-language-server-errors
21 май 2024, 02:42
21 май 2024, 02:42
5bb5f44
Код
Авторство
О чём код?
--[[ SVFFI serial protocol for generator support See http://www.svffi.com/en/ --]] ---@diagnostic disable: param-type-mismatch ---@diagnostic disable: missing-parameter local PARAM_TABLE_KEY = 42 local PARAM_TABLE_PREFIX = "EFI_SVF_" local MAV_SEVERITY = {EMERGENCY=0, ALERT=1, CRITICAL=2, ERROR=3, WARNING=4, NOTICE=5, INFO=6, DEBUG=7} -- bind a parameter to a variable given local function bind_param(name) local p = Parameter() assert(p:init(name), string.format('could not find %s parameter', name)) return p end -- add a parameter and bind it to a variable local function bind_add_param(name, idx, default_value) assert(param:add_param(PARAM_TABLE_KEY, idx, name, default_value), string.format('could not add param %s', name)) return bind_param(PARAM_TABLE_PREFIX .. name) end -- setup script specific parameters assert(param:add_table(PARAM_TABLE_KEY, PARAM_TABLE_PREFIX, 8), 'could not add param table') --[[ // @Param: EFI_SVF_ENABLE // @DisplayName: Generator SVFFI enable // @Description: Enable SVFFI generator support // @Values: 0:Disabled,1:Enabled // @User: Standard --]] EFI_SVF_ENABLE = bind_add_param("ENABLE", 1, 0) --[[ // @Param: EFI_SVF_ARMCHECK // @DisplayName: Generator SVFFI arming check // @Description: Check for Generator ARM state before arming // @Values: 0:Disabled,1:Enabled // @User: Standard --]] EFI_SVF_ARMCHECK = bind_add_param("ARMCHECK", 2, 1) if EFI_SVF_ENABLE:get() ~= 1 then return end local auth_id = arming:get_aux_auth_id() arming:set_aux_auth_failed(auth_id, "GEN: not in ARM state") local uart = serial:find_serial(0) -- first scripting serial if not uart then gcs:send_text(MAV_SEVERITY.ERROR, "GEN_SVF: unable to find serial port") return end uart:begin(115200) local efi_backend = efi:get_backend(0) if not efi_backend then gcs:send_text(MAV_SEVERITY.ERROR, "GEN_SVF: unable to find EFI backend") return end local function read_bytes(n) local ret = "" for _ = 1, n do ret = ret .. string.char(uart:read()) end return ret end local auchCRCHi = { 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 } local auchCRCLo = { 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 } --[[ calculate crc16 --]] local function get_crc16(s) local uchCRCHi = 0xFF local uchCRCLo = 0xFF for i = 1, #s do local b = string.byte(string.sub(s, i, i)) local uIndex = uchCRCLo ~ b --gcs:send_text(MAV_SEVERITY.INFO, string.format("uIndex=%u", uIndex)) uchCRCLo = uchCRCHi ~ auchCRCHi[uIndex+1] uchCRCHi = auchCRCLo[uIndex+1] end return (uchCRCHi << 8 | uchCRCLo) end local state = {} state.last_read_us = uint32_t(0) state.last_status = -1 --[[ check for input and parse data --]] local function check_input() local n_bytes = uart:available():toint() --gcs:send_text(MAV_SEVERITY.INFO, string.format("n_bytes=%u %.2f", n_bytes, millis():tofloat()*0.001)) if n_bytes < 31 then return end local s = read_bytes(n_bytes) local prefix, len = string.unpack("<HB", s, 1) if prefix ~= 0xa55a then gcs:send_text(MAV_SEVERITY.INFO, string.format("bad prefix 0x%x", prefix)) return end if len+5 ~= n_bytes then gcs:send_text(MAV_SEVERITY.INFO, string.format("bad len %u %u", n_bytes, len)) return end local crc = string.unpack("<H", s, 4+len) local s2 = string.sub(s,1,n_bytes-2) --gcs:send_text(MAV_SEVERITY.INFO, string.format("s2 n_bytes=%u len1=%u len2=%u", n_bytes, #s, #s2)) local crc2 = get_crc16(s2) if crc ~= crc2 then gcs:send_text(MAV_SEVERITY.INFO, string.format("bad crc %x %x", crc, crc2)) return end state.version, state.rpm, state.throttle = string.unpack("<BHH", string.sub(s,4,8)) state.voltage, state.current, state.runtime = string.unpack("<HHI", string.sub(s,9,16)) state.maint_time, state.lock_time, state.status = string.unpack("<HHB", string.sub(s,17,21)) state.alarm, state.fuellevel, state.cht1 = string.unpack("<HBH", string.sub(s,22,26)) state.cht2, state.pcb_temp = string.unpack("<HB", string.sub(s,27,29)) if state.status ~= state.last_status then state.last_status = state.status local states = {"STOP", "IDLE", "RUN", "3", "CHARGE" } local name = states[state.status+1] if not name then name = string.format("Unknown%u", state.status) end gcs:send_text(MAV_SEVERITY.WARNING, string.format("Generator state: %s", name)) if name ~= "RUN" and EFI_SVF_ARMCHECK:get() == 1 then arming:set_aux_auth_failed(auth_id, string.format("GEN: not in ARM state (%s)", name)) else arming:set_aux_auth_passed(auth_id) end end state.last_read_us = micros() end --[[ update EFI state --]] local function update_EFI() if state.last_read_us == uint32_t(0) then return end local cylinder_state = Cylinder_Status() local efi_state = EFI_State() local C_TO_KELVIN = 273.2 cylinder_state:cylinder_head_temperature(state.cht1+C_TO_KELVIN) efi_state:engine_speed_rpm(state.rpm) efi_state:throttle_position_percent(state.throttle) efi_state:ignition_voltage(state.voltage*0.1) efi_state:cylinder_status(cylinder_state) efi_state:last_updated_ms(millis()) -- Set the EFI_State into the EFI scripting driver efi_backend:handle_scripting(efi_state) gcs:send_named_float('GEN_VOLT', state.voltage*0.1) gcs:send_named_float('GEN_AMPS', state.current*0.1) gcs:send_named_float('GEN_STAT', state.status) logger.write('SVF','Curr,Volt,Status', 'ffB', state.current*0.1, state.voltage*0.1, state.status) end --[[ main update function --]] local function update() check_input() update_EFI() return update, 100 end gcs:send_text(MAV_SEVERITY.INFO, "GEN_SVF: loaded") return update()