Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility for Taranis x9d+ #8

Open
Tanmax-Payne opened this issue Mar 11, 2023 · 3 comments
Open

Possibility for Taranis x9d+ #8

Tanmax-Payne opened this issue Mar 11, 2023 · 3 comments

Comments

@Tanmax-Payne
Copy link

🏷️ Enhancement

@CapnBry
Copy link
Member

CapnBry commented Mar 11, 2023

There is no widget system for B&W screens, so it is a complete rewrite, not an enhancement.

I've started something for those type of screens, but for the smaller B&W screens most radios have these days, but it is a long ways off. It just looks so boring, I'm waiting for a spark of inspiration to hit.

@druckgott
Copy link

I have done it for X-Lite:
https://github.com/druckgott/express_lrs_status_lua

@CapnBry
Copy link
Member

CapnBry commented Dec 21, 2023

Great! I've been using something similar on my B&W radios except really tailored to my switch layout to let me know at a glance that my switches are in the right position. Probably still works on wide screens too.

image

local FH = 8
-- local mock = { ['1RSS'] = -105, RFMD = 7, RxBt = 15.6, RQly = 100, ANT = 0, RSNR = -3, TPWR = 250 }

local cache
local state

-- mapping:
-- ch5 (A1): ARM
-- ch6 (A2): low=Acro mid=Angle hi=beep
-- ch7 (A3): OSD select
-- ch8 (A4): low=BBoff mid=BBon hi=turtle
-- ch9 (A5): rateprofile select
-- ch10(A6): prearm

local function valExists(t, i)
  for _, v in ipairs(t) do
    if v == i then return true end
  end
  return false
end

local function loadCache()
  local lcache = {}

  local SRC = { 'ch5', 'ch6', 'ch7', 'ch8', 'ch9', '1RSS', '2RSS', 'RFMD', 'RxBt', 'RQly', 'ANT', 'RSNR', 'TPWR' }
  local OK_MISSING = { '1RSS', '2RSS', 'RFMD', 'RxBt', 'RQly', 'ANT', 'RSNR', 'TPWR' }
  for _, v in ipairs(SRC) do
    local item = getFieldInfo(v)
    if item then
      lcache[v] = item.id
    else
      -- If the item is not in the OK_MISSING list, then we can't do without it
      if not valExists(OK_MISSING, v) then
        print("Missing field " .. v)
        return
      end
    end
  end

  cache = lcache
end

local function getV(k)
  local retVal = (not state.online and mock) and mock[k]
  if not retVal then
    local id = cache and cache[k]
    retVal = (id and getValue(id))
  end
  return retVal
end

local function posL(ch) return getV(ch) < -512 end
local function posH(ch) return getV(ch) > 512 end
local function posM(ch) return not (posL(ch) or posH(ch)) end

local function drawDItem(label, Ys, dangFunc, warn)
  local danger = dangFunc()
  local yn, attrib
  if danger then
    yn = 'BAD'
    attrib = warn and 0 or INVERS
  else
    yn = 'ok'
    attrib = 0
  end

  local X, Y
  if warn then
    X = LCD_W/2 + 1
    Y = Ys[2]
    Ys[2] = Ys[2] + FH
  else
    X = 0
    Y = Ys[1]
    Ys[1] = Ys[1] + FH
  end
  lcd.drawText(X+9, Y, yn, attrib + SMLSIZE + CENTER)
  lcd.drawText(X+19, Y, label, SMLSIZE)

  return Ys
end

local function resetState()
  state = {
    cellCnt = 1,
    cellCntCnt = 0
  }
end

local function checkCellCount(v)
  -- once the cellCnt is the same N times in a row, we stop checking
  if state.cellCntCnt > 10 then
    return
  end

  -- try to lock on to the cell count, so if the voltage sags we don't change S
  local cellCnt = math.floor(v / 4.35) + 1
  -- Prevent lock on when no voltage is present
  if (v / cellCnt) < 3.0 then
    return
  end

  if state.cellCnt ~= cellCnt then
    state.cellCnt = cellCnt
    state.cellCntCnt = 0
  else
    -- The value has to change to count as an update
    if state.cellLastV == v then
      return
    end
    state.cellLastV = v
    state.cellCntCnt = state.cellCntCnt + 1
  end
end

local function drawVbat()
  local vbat = getV('RxBt') or 0

  checkCellCount(vbat)
  local vstr
  if state.cellCnt > 1 then
    vstr = string.format("%.2fV %dS", vbat/state.cellCnt, state.cellCnt)
  else
    vstr = string.format("%.1fV", vbat)
  end
  lcd.drawText(2, LCD_H-16, vstr, MIDSIZE)
end

local function drawLinkstats()
  -- RF Mode
  local rfmd = getV('RFMD') or 0
  rfmd = rfmd + 1
  local RFMODES = { 
    { hz='4Hz', sl=-5, sh=13 },
    { hz='25Hz', sl=-4, sh=4 },
    { hz='50Hz', sl=-1, sh=12 },
    { hz='100Hz', sl=-0, sh=4 },
    { hz='100Full', sl=-1, sh=12 },
    { hz='150Hz', sl=-1, sh=12 },
    { hz='200Hz', sl=0, sh=4 },
    { hz='250Hz', sl=2, sh=12 },
    { hz='333Full', sl=4, sh=12 },
    { hz='500Hz', sl=4, sh=12 },
    { hz='D250', sl=-90, sh=-60 },
    { hz='D500', sl=-90, sh=-60 },
    { hz='F500', sl=-90, sh=-60 },
    { hz='F1000', sl=-90, sh=-60 },
  }
  local rfdef = RFMODES[rfmd]
  local rfstr = rfdef and rfdef.hz or ('RFMD ' .. tostring(rfmd))
  lcd.drawText(LCD_W/2+2, 30, rfstr, 0)

  -- Power
  lcd.drawText(LCD_W-1, 30, getV('TPWR') .. 'mW', RIGHT)

  -- RSSI and LQ
  local ant = getV('ANT')
  if ant == 1 then state.isDivers = true end
  local rssi = ant == 0 and getV('1RSS') or getV('2RSS')
  local sigstr = string.format("%ddBm %d%%", rssi,  getV('RQly'))
  lcd.drawText(96, 41, sigstr, CENTER)
  
  -- SNR
  local snr = getV('RSNR')
  lcd.drawText(96, 57, tostring(snr) .. 'dB', CENTER + SMLSIZE)
  -- SNR bar (from -5 to +12)
  lcd.drawRectangle(65, 50, 62, 6)
  local lowest = rfdef and rfdef.sl or -5
  local highest = rfdef and rfdef.sh or 12
  -- If the sl/sh are lower than -16dB, then they are in rssi
  if lowest < -16 then
    snr = rssi
  end
  if snr < lowest then snr = lowest end
  if snr > highest then snr = highest end
  local w = (62-2) * (snr-lowest) / (highest-lowest)
  lcd.drawFilledRectangle(65+1, 51, w, 4)
end

local function drawDangerItems()
  lcd.drawFilledRectangle(0, 0, LCD_W, FH)
  lcd.drawText(32, 0, 'Errors', CENTER + INVERS)
  lcd.drawText(96, 0, 'Warnings', CENTER + INVERS)

  local Ys = {FH+2, FH+2}
  -- Errs
  Ys = drawDItem('Armed', Ys, function () return not posL('ch5') end)
  Ys = drawDItem('Mode', Ys, function () return not posL('ch6') end)
  Ys = drawDItem('Turtle', Ys, function () return posH('ch8') end)
  Ys = drawDItem('Rates', Ys, function () return not posL('ch9') end)
  -- Warns
  Ys = drawDItem('OSD Prof', Ys, function () return not posL('ch7') end, true)
  Ys = drawDItem('Blackbox', Ys, function () return posM('ch8') end, true)

  Ys[1] = Ys[1] + 1
  Ys[2] = Ys[2] + 1
  lcd.drawLine(63, 0, 63, 42, DOTTED, 0)  -- vert
  lcd.drawLine(0, Ys[1], 63, Ys[1], DOTTED, 0)
  lcd.drawLine(63, Ys[2], 127, Ys[2], DOTTED, 0)
end

local function drawOffline()
  lcd.drawText(LCD_W/2, LCD_H-16, 'Offline', MIDSIZE + CENTER)
end

local function checkOnline()
  local rssi = getRSSI()
  local online = (rssi ~= 0) or nil

  -- if was online and going offline, reset state
  if state.online and online == nil then
    resetState()
  end

  state.online = online
end

local function init_func()
  loadCache()
  resetState()

  loadCache = nil
end

local testModule
local function run_func(event)
  if (event or 0) ~= 0 then print(event, EVT_VIRTUAL_MENU, EVT_VIRTUAL_ENTER) end

  checkOnline()
  lcd.clear()
  drawDangerItems()
  -- Vals
  if state.online or mock then
    drawLinkstats()
    drawVbat()
  else
    drawOffline()
  end
end

local function back_func()
  --print(getTime())
end

return { run=run_func, init=init_func, background=back_func }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants