--[[
  Copyright (c) 2022-2025 by Plexim GmbH
  All rights reserved.

  A free license is granted to anyone to use this software for any legal
  non safety-critical purpose, including commercial applications, provided
  that:
  1) IT IS NOT USED TO DIRECTLY OR INDIRECTLY COMPETE WITH PLEXIM, and
  2) THIS COPYRIGHT NOTICE IS PRESERVED in its entirety.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
--]]--

local VREF = {}
local U = require('common.utils')

-- Note Target.Variables is global and not needed as a parameter

--[[ getAdcVref returns a table with two values:
    useExternalVref -- a flag [0 or 1]
    vref -- the desired Voltage Reference value
--]]--
function VREF.getAdcVref(globals, adcNum)
  local adcChar = string.char(65 + adcNum)

  return VREF.getAdcVrefFromChar(globals, adcChar)
end

function VREF.getAdcVrefFromChar(globals, adcChar)

  assert(U.isChar(adcChar))
  -- ADC Voltage Reference Configuration based on ADC Type
  -- Note that this function must match the configuration in info.xml for each target

  local useExternalVref = 0;  -- default to internal reference

  local adcParams = globals.target.getTargetParameters().adcs
  local vrefConfigInterfaceType = adcParams.vrefConfigInterfaceType

  local vrefDefault = adcParams.defaultVref or 3.3
  local vrefMin = adcParams.vref_min or 2.4
  local vrefMax = adcParams.vref_max or 3.3
  local vref = vrefDefault

  if (vrefConfigInterfaceType == 2) then

    local cbx_vrefSelect = U.enforceCO_newComboBox(
      'vrefDropDown',
      {'internal 3.0V'}
    )

    if cbx_vrefSelect.equals('internal 3.0V') then
      useExternalVref = 0
      vref = 3.0
    else
      error('Invalid Vref Combo value')
    end
  elseif (vrefConfigInterfaceType == 3) then

    local cbx_vrefSelect = U.enforceCO_newComboBox(
      'VrefComboBox%s' % {adcChar},
      {'internal 3.3V', 'external'}
    )

    if cbx_vrefSelect.equals('internal 3.3V') then
      useExternalVref = 0
      vref = 3.3
    elseif cbx_vrefSelect.equals('external') then
      useExternalVref = 1
      vref = U.enforceCO(U.isScalarInClosedInterval, 'VrefAdc%s' % {adcChar},
                         vrefMin, vrefMax, 'V')
    else
      error('Invalid Vref Combo value')
    end

  elseif (vrefConfigInterfaceType == 4) then
    -- for ADC Coder Options Interface Type 4, 
    -- each unit can be configured with a separate external reference.
    useExternalVref = 1;
    vref = U.enforceCO(U.isScalarInClosedInterval, 'VrefAdc%s' % {adcChar},
                       vrefMin, vrefMax, 'V')
  
  elseif (vrefConfigInterfaceType == 5) then
    -- ADC Coder Options Interface Type 5
    local thisAdcChar = adcChar
    --[[
        Currently only support a single reference, thus the adc.vrefMap is 
        not used. This code is written assuming in the future a flag for 
        advanced ADC config is selected, in which case there will be a comboBox
        for each independent ADC (VrefComboBoxA etc) and a unique widget for 
        each external reference (VrefAdcA etc).
    --]] 
    local advancedAdcConfigSelected = false
    -- We are not supporting chip variants with different references
    -- so for now, all will be the same:
    local refAdcChar = ''
    
    if advancedAdcConfigSelected then
      -- remap small pinout count packages to the right ADC reference
      local refAdcChar = adcParams.vrefMap[thisAdcChar] 
      if not refAdcChar then
        error('For the advanced Voltage configuration a vrefMap must be defined.')
      end
    end

    local cbx_vrefSelect = U.enforceCO_newComboBox(
      'VrefComboBox%s' % {refAdcChar},
      {'internal 3.3V', 'internal 2.5V', 'external'}
    )

    if cbx_vrefSelect.equals('internal 3.3V') then
      useExternalVref = 0
      vref = 3.3
    elseif cbx_vrefSelect.equals('internal 2.5V') then
      useExternalVref = 0
      vref = 2.5
    elseif cbx_vrefSelect.equals('external') then
      useExternalVref = 1
      vref = U.enforceCO(U.isScalarInClosedInterval, 'VrefAdc%s' % {refAdcChar}, 
                         vrefMin, vrefMax, 'V')
    else
      error('Invalid Vref Combo value')
    end
  else
    U.error('Invalid ADC Interface type! Please contact TSP developer.')
  end

  return {useExternalVref = useExternalVref, vref = vref}
end

--[[ getDacVref returns a table with two values:
    useExternalVref -- a flag [0 or 1]
    vref -- the desired Voltage Referfence value
--]]--
function VREF.getDacVref(globals, dacChar)
  local dacs = globals.target.getTargetParameters().dacs
  -- Look up the correct ADC reference for the selected DAC.
  local adcChar = dacs and dacs.vrefMap and dacs.vrefMap[dacChar]

  if not adcChar then                    
    error('The target.lua file must define a `dacs.vrefMap` entry for for DAC %s.' % {dacChar})
  end
  return VREF.getAdcVrefFromChar(globals, adcChar)
end

return VREF
