cctweaked_drone/lib/ihm.lua
2026-07-17 13:54:31 +02:00

176 lines
6.1 KiB
Lua

--------------------------------------------------------------------
-- lib/ihm.lua : interfaces homme-machine.
-- Display Link "conduite" : altitudes, vitesse, invites, alertes
-- Display Link "carburant" : reserve + autonomie estimee (minutes)
-- Advanced monitor tactile : modes (verrouilles si calibration
-- manquante), consigne, calibrations, informations
-- Typewriter : la saisie est geree dans drone.lua (scrutation)
--------------------------------------------------------------------
local Ihm = {}
function Ihm.nouveau(conf, materiel, journal)
local ihm = {}
local moniteur = materiel.moniteur
moniteur.setTextScale(0.5)
local zones = {}
local messageConduite, messageFin = nil, 0
-- message temporaire sur la ligne 1 de la conduite (invites,
-- alertes); duree en secondes (nil = 5)
function ihm.message(texte, duree)
messageConduite = texte
messageFin = os.clock() + (duree or 5)
end
------------------------------------------------------------------
-- ECRAN DE CONDUITE
------------------------------------------------------------------
-- ctx: { mode, consigneY, saisie }
function ihm.rafraichirConduite(ctx)
local e = materiel.ecranConduite
e.clear()
e.setCursorPos(1, 1)
if messageConduite and os.clock() < messageFin then
e.write(messageConduite:sub(1, 22))
elseif ctx.saisie and #ctx.saisie > 0 then
e.write("SAISIE: " .. ctx.saisie)
elseif ctx.mode == "vol" or ctx.mode == "drone"
or ctx.mode == "atterrissage" or ctx.mode == "auto"
or ctx.mode == "position" then
e.write(("ALT %.1f / %.0f"):format(
materiel.lireAltitude(), ctx.consigneY or 0))
else
e.write("MODE " .. ctx.mode:upper())
end
e.setCursorPos(1, 2)
e.write(("VIT %.2f b/s"):format(materiel.vitesseHorizontale()))
e.update()
end
------------------------------------------------------------------
-- ECRAN CARBURANT (peut etre tres etroit: format compact)
------------------------------------------------------------------
-- pct 0..1 ou nil ; minutes ou nil
function ihm.rafraichirCarburant(pct, minutes)
local e = materiel.ecranCarburant
local largeur = e.getSize()
e.clear()
e.setCursorPos(1, 1)
if pct == nil then
e.write(("n/a"):sub(1, largeur))
else
e.write(("%d%%"):format(math.floor(pct * 100 + 0.5)):sub(1, largeur))
e.setCursorPos(1, 2)
if minutes then
e.write(("%dm"):format(math.floor(minutes)):sub(1, largeur))
else
e.write(("--m"):sub(1, largeur))
end
end
e.update()
end
------------------------------------------------------------------
-- MONITEUR TACTILE
------------------------------------------------------------------
local function bouton(x, y, texte, action, couleur)
moniteur.setCursorPos(x, y)
moniteur.setBackgroundColor(couleur or colors.gray)
moniteur.write(" " .. texte .. " ")
moniteur.setBackgroundColor(colors.black)
table.insert(zones, {
x1 = x, y1 = y, x2 = x + #texte + 1, y2 = y, action = action,
})
end
local function texte(x, y, contenu, couleur)
moniteur.setTextColor(couleur or colors.white)
moniteur.setCursorPos(x, y)
moniteur.write(contenu)
moniteur.setTextColor(colors.white)
end
-- ctx: { mode, consigneY, stress, position, carburantPct, minutes,
-- moteurOk, verrous = { mode -> raison|nil }, points = n }
function ihm.rafraichirMoniteur(ctx)
zones = {}
moniteur.setBackgroundColor(colors.black)
moniteur.clear()
texte(1, 1, "== MODES == actuel: " .. ctx.mode)
local modes = { "off", "inactif", "stationnement", "vol", "drone",
"atterrissage", "auto", "position" }
local x, y = 1, 2
for _, m in ipairs(modes) do
local verrou = ctx.verrous[m]
local couleur = colors.gray
if m == ctx.mode then couleur = colors.green
elseif verrou then couleur = colors.red end
if x + #m + 2 > 50 then x, y = 1, y + 1 end
bouton(x, y, m, { type = "mode", valeur = m, verrou = verrou },
couleur)
x = x + #m + 3
end
texte(1, y + 2, ("== CONSIGNE == %.0f"):format(ctx.consigneY or 0))
bouton(1, y + 3, "-10", { type = "delta", valeur = -10 })
bouton(7, y + 3, "-1", { type = "delta", valeur = -1 })
bouton(12, y + 3, "+1", { type = "delta", valeur = 1 })
bouton(17, y + 3, "+10", { type = "delta", valeur = 10 })
texte(1, y + 5, "== CALIBRATIONS ==")
local cx = 1
for _, c in ipairs({ "gimbal", "joystick", "typew", "rsc",
"capteurs", "pid" }) do
bouton(cx, y + 6, c, { type = "calib", valeur = c })
cx = cx + #c + 3
end
local ly = y + 8
texte(1, ly, "== INFOS ==")
local t, r = materiel.lireAssiette()
texte(1, ly + 1, ("assiette T %+.2f R %+.2f%s"):format(t, r,
ctx.gimbalOk and "" or " (NON CALIBRE)"))
texte(1, ly + 2, ("sol %.1f (%s%s)"):format(
materiel.lireDistanceSol(),
materiel.auSol() and "au sol" or "en vol",
materiel.solPosable() and "" or ", NON POSABLE"))
texte(1, ly + 3, ("stress %s moteur %s"):format(
ctx.stress and ("%.0f%%"):format(ctx.stress * 100) or "n/a",
ctx.moteurOk and "ok" or "ARRETE"),
ctx.moteurOk and colors.white or colors.red)
texte(1, ly + 4, ("carburant %s autonomie %s"):format(
ctx.carburantPct
and ("%.0f%%"):format(ctx.carburantPct * 100) or "n/a",
ctx.minutes and ("%dmin"):format(math.floor(ctx.minutes)) or "--"))
if ctx.position then
texte(1, ly + 5, ("gps %.0f %.0f %.0f points: %d")
:format(ctx.position.x, ctx.position.y, ctx.position.z,
ctx.points or 0))
else
texte(1, ly + 5, "gps n/a", colors.red)
end
end
function ihm.traiterToucher(tx, ty)
for _, z in ipairs(zones) do
if tx >= z.x1 and tx <= z.x2 and ty >= z.y1 and ty <= z.y2 then
return z.action
end
end
return nil
end
-- attend un toucher du moniteur (utilise par les calibrations)
function ihm.attendreToucher()
while true do
local ev = os.pullEvent("monitor_touch")
if ev then return end
end
end
return ihm
end
return Ihm