package.path = package.path..";.\\LuaSocket\\?.lua;" package.cpath = package.cpath..";.\\LuaSocket\\?.dll;" package.path = package.path..";.\\LuaSocket\\?.lua" package.cpath = package.cpath..";.\\LuaSocket\\?.dll" local MATRIC = {} local mtrxlog = nil null = nil MATRIC.ipaddr = "127.0.0.1" MATRIC.port = 50300 MATRIC.PIN = "9087" MATRIC.appName = "MATRIC4DCS" MATRIC.clientId = nil MATRIC.updatePeriod = 0.2 local socket = require("socket") MATRIC.conn = socket.udp() MATRIC.conn:settimeout(0) MATRIC.conn:setpeername(MATRIC.ipaddr, MATRIC.port) JSON = loadfile("Scripts\\JSON.lua")() --#region ***** MATRIC structures and helper functions ***** function defineMatricButton(matricButtonName, dcsValueId, reverse) return { DCSValueId = dcsValueId, ButtonName = matricButtonName, Reverse = reverse } end --returns the data structure that MATRIC expects for SETDECK command MATRIC.cmdSETDECK = function() return { command = "SETDECK", appName = MATRIC.appName, appPin = MATRIC.PIN, clientId = MATRIC.clientId, deckId = "", pageId = "" } end --returns the data structure that MATRIC expects for SETACTIVEPAGE command MATRIC.cmdSETACTIVEPAGE = function() return { command = "SETACTIVEPAGE", appName = MATRIC.appName, appPin = MATRIC.PIN, clientId = MATRIC.clientId, pageId = "" } end --returns the data structure that MATRIC expects for SETBUTTONPROPS command MATRIC.cmdSETBUTTONPROPS = function() return { command = "SETBUTTONPROPS", appName = MATRIC.appName, appPin = MATRIC.PIN, clientId = MATRIC.clientId, buttonId = "", buttonName = nil, data = { imageOff = nil, imageOn = nil, textcolorOn = nil, textcolorOff = nil, backgroundcolorOn = nil, backgroundcolorOff = nil, fontSize = nil, text = nil, halign = nil, valign = nil, padding = nil, } } end --returns the data structure that MATRIC expects for SETBUTTONPROPSEX command MATRIC.cmdSETBUTTONPROPSEX = function() return { command = "SETBUTTONPROPSEX", appName = MATRIC.appName, appPin = MATRIC.PIN, clientId = MATRIC.clientId, data = {} } end MATRIC.cmdSETBUTTONSVISUALSTATE = function() return { command = "SETBUTTONSVISUALSTATE", appName = MATRIC.appName, appPin = MATRIC.PIN, clientId = nil, data = {} } end MATRIC.buttonVisualState = function(buttonDef, dcsValue) local _state = "off" if(dcsValue == 1) then if(buttonDef.Reverse) then _state = "off" else _state = "on" end else if(buttonDef.Reverse) then _state = "on" else _state = "off" end end return { buttonName = buttonDef.ButtonName, state = _state } end ----returns the data structure containing button props we can modify MATRIC.buttonProps = function() return { buttonName = nil, buttonId = nil, imageOff = nil, imageOn = nil, textcolorOn = nil, textcolorOff = nil, backgroundcolorOn = nil, backgroundcolorOff = nil, fontSize = nil, text = nil, halign = nil, valign = nil, padding = nil, } end function SendMATRICCommand(data) mtrxlog:write("sending UDP update") mtrxlog:write(JSON:encode_pretty(data)) socket.try(MATRIC.conn:send(JSON:encode_pretty(data))) end --#endregion --#region UTILS function coerce_nil_to_string(value) if value == nil then return "" else return value end end function parse_indication(indicator_id) local ret = {} local li = list_indication(indicator_id) if li == "" then return nil end local m = li:gmatch("-----------------------------------------\n([^\n]+)\n([^\n]*)\n") while true do local name, value = m() if not name then break end ret[name] = value end return ret end function GetUFCPLine(ufcpLine, lineNum) local status, result = pcall(processUFCPLine, ufcpLine, lineNum) if(status) then return result else return " " end end function processUFCPLine(ufcpLine, lineNum) local temp_txt_win = ufcpLine["txt_win"..lineNum] local txt_win_fill = ufcpLine["txt_win"..lineNum.."_fill"] local cur_win = ufcpLine["cur_win"..lineNum] local txt_winr = ufcpLine["txt_win"..lineNum.."r"] local cur_winr = ufcpLine["cur_win"..lineNum.."r"] local UFCPLineLength = 8 local txt_win if temp_txt_win ~= null then txt_win = temp_txt_win:gsub(string.char(127),"^") else txt_win = "" end if txt_win_fill ~= null then local full_txt_win_fill = txt_win_fill..string.rep(" ",UFCPLineLength - string.len(txt_win_fill)) if temp_txt_win ~= null then if cur_win ~= null then if txt_win:find("-") then processedUFCPLine = txt_win:sub(1,txt_win:find("-") - cur_win:len()) .. cur_win .. txt_win:sub(txt_win:find("-") + cur_win:len()) .. full_txt_win_fill:sub(txt_win:len()+1) else processedUFCPLine = txt_win:sub(1,txt_win:len() - cur_win:len()) .. cur_win .. full_txt_win_fill:sub(txt_win:len()+1) end else processedUFCPLine = txt_win .. full_txt_win_fill:sub(txt_win:len() + 1) end else if cur_winr ~= null then processedUFCPLine = full_txt_win_fill:sub(1,UFCPLineLength - txt_winr:len()) .. txt_winr:sub(1,txt_winr:len() - cur_winr:len())..cur_winr else processedUFCPLine = full_txt_win_fill:sub(1,UFCPLineLength - txt_winr:len())..txt_winr end end elseif txt_win ~= null then processedUFCPLine = txt_win else processedUFCPLine = txt_winr end return processedUFCPLine end --#endregion --Set up buttons that we shall control with our script --first argument: button name in matric decks --second argument: DCS value Id --third argument if true button will be off if DCS value equals 1, else button will be on if DCS value equals 1 local JF17_BUTTONS = { UFCP_BTN_OAP = defineMatricButton("UFCP_BTN_OAP", 150, false), UFCP_BTN_MRK = defineMatricButton("UFCP_BTN_MRK", 151, false), UFCP_BTN_PU = defineMatricButton("UFCP_BTN_PU", 152, false), UFCP_BTN_HNS = defineMatricButton("UFCP_BTN_HNS", 153, false), UFCP_BTN_AP = defineMatricButton("UFCP_BTN_AP", 154, false), UFCP_BTN_FPM = defineMatricButton("UFCP_BTN_FPM", 155, false) } --Get all the data we need for UFCP and send integration commands --We will use SETBUTTONSVISUALSTATE to toggle UFCP buttons on/off --We will use SETBUTTONPROPSEX to set UFCP displays function UpdateMATRICJF17() local cmd = MATRIC:cmdSETBUTTONSVISUALSTATE() local i = 1; mtrxlog:write(JSON:encode_pretty(JF17_BUTTONS)) local device = GetDevice(0); --46 is UFCP device id? Or 0? for k, v in pairs(JF17_BUTTONS) do cmd.data[i] = MATRIC.buttonVisualState(v, device:get_argument_value(v.DCSValueId)) i = i+1 end SendMATRICCommand(cmd) local UFCP_LINE_1 = coerce_nil_to_string(GetUFCPLine(parse_indication(3), 1)) local UFCP_LINE_2 = coerce_nil_to_string(GetUFCPLine(parse_indication(4), 2)) local UFCP_LINE_3 = coerce_nil_to_string(GetUFCPLine(parse_indication(5), 3)) local UFCP_LINE_4 = coerce_nil_to_string(GetUFCPLine(parse_indication(6), 4)) local cmdDisplays = MATRIC.cmdSETBUTTONPROPSEX(); cmdDisplays.data[1] = { buttonName="UFCP_DISPLAY_1", text=UFCP_LINE_1} cmdDisplays.data[2] = { buttonName="UFCP_DISPLAY_2", text=UFCP_LINE_2} cmdDisplays.data[3] = { buttonName="UFCP_DISPLAY_3", text=UFCP_LINE_3} cmdDisplays.data[4] = { buttonName="UFCP_DISPLAY_4", text=UFCP_LINE_4} SendMATRICCommand(cmdDisplays) end -- #region **************** DCS hooks **************** local _prevExport = {} _prevExport.LuaExportActivityNextEvent = LuaExportActivityNextEvent _prevExport.LuaExportBeforeNextFrame = LuaExportBeforeNextFrame _prevExport.LuaExportStart = LuaExportStart _prevExport.LuaExportStop = LuaExportStop function LuaExportStart() --initialize mtrxlog = io.open(lfs.writedir().."/Logs/matric_connector_log.txt", "w") mtrxlog:write("-- LOG start --") --ToDo: set deck, page local _status,_result = pcall(function() -- Call original function if it exists if _prevExport.LuaExportStart then _prevExport.LuaExportStart() end end) end function LuaExportStop() if mtrxlog then mtrxlog:write("-- LOG end --") mtrxlog:close() mtrxlog = nil end local _status,_result = pcall(function() -- Call original function if it exists if _prevExport.LuaExportStop then _prevExport.LuaExportStop() end end) end LuaExportActivityNextEvent = function(tCurrent) local tNext = tCurrent + MATRIC.updatePeriod if (LoGetSelfData() ~= nil) then if (LoGetSelfData().Name == "JF-17") then UpdateMATRICJF17() end end -- call original local _status,_result = pcall(function() -- Call original function if it exists if _prevExport.LuaExportActivityNextEvent then _prevExport.LuaExportActivityNextEvent(tCurrent) end end) return tNext end LuaExportBeforeNextFrame = function() -- call original _status,_result = pcall(function() -- Call original function if it exists if _prevExport.LuaExportBeforeNextFrame then _prevExport.LuaExportBeforeNextFrame() end end) end -- #endregion