# instance-ors-enb translates ORS enb/gnb into generic enb with 1 SDR RU and 1 CELL.

{#- enb_mode indicates with which mode ors' enb is instantiated with - enb | gnb #}
{%- set enb_mode = slap_configuration['slap-software-type'] %}
{%- do assert(enb_mode in ('enb', 'gnb'), enb_mode) %}

{#- defaults for ORS parameters.
    TODO automatically load ORS/enb and ORS/gnb defaults from JSON schema #}
{%- set ors_enb_defaults = {
  "bandwidth": "20 MHz",
  "n_antenna_dl": 2,
  "n_antenna_ul": 2,
  "rf_mode": "tdd",
  "tdd_ul_dl_config": "[Configuration 2] 5ms 2UL 6DL (default)",
  "enb_id":  ors_id['enb_id'],
  "cell_id": ors_id['enb_cell_id'],
  "pci":     ors_id['enb_pci'],
  "root_sequence_index":     ors_id['root_sequence_index'],
  "tac": "0x0001",
  'mme_list': {
      'Local Core Network': {
          'mme_addr': '127.0.1.100'
      }
  },
  'plmn_list': {
      'Test PLNM': {
          'plmn': '00101',
          'tac': 100
      }
  },
  "ncell_list": {},
  "x2_peers": {},
  "inactivity_timer": 10000,
  "disable_sdr": false
} %}
{%- set ors_gnb_defaults = {
  "nr_bandwidth": 40,
  "n_antenna_dl": 2,
  "n_antenna_ul": 2,
  "rf_mode": "tdd",
  "tdd_ul_dl_config": "5ms 2UL 7DL 4/6 (default)",
  "ssb_pos_bitmap": "10000000",
  "gnb_id":  ors_id['gnb_id'],
  "cell_id": ors_id['gnb_cell_id'],
  "pci":     ors_id['gnb_pci'],
  "root_sequence_index":     ors_id['root_sequence_index'],
  "gnb_id_bits": 28,
  'amf_list': {
      'Local Core Network': {
          'amf_addr': '127.0.1.100'
      }
  },
  'plmn_list': {
      'Test PLNM': {
          'plmn': '00101',
          'tac': 100
      }
  },
  "ncell_list": {},
  "xn_peers": {},
  "inactivity_timer": 10000,
  "disable_sdr": false
} %}

{%- set ors_defaults = {'enb': ors_enb_defaults, 'gnb': ors_gnb_defaults} [enb_mode]  %}
{%- for k,v in ors_defaults|dictsort %}
{%-   do slapparameter_dict.setdefault(k, v) %}
{%- endfor %}


{#- make real ru/cell/peer/... shared instances to be rejected in ORS mode #}
{%- set ishared_list = slap_configuration.setdefault('slave-instance-list', [])  %}
{%- for ishared in ishared_list %}
{%-   set _ = json_module.loads(ishared['_']) %}
{%-   if 'ru_type' in _  or  'cell_type' in _ %}
{%-     do ishared.update({'_': {'REJECT': 1}|tojson})  %}
{%-   endif %}
{%- endfor  %}


{#- inject ru+cell synthesized from ORS-specific parameters #}
{%- macro iref(name)  %}
{{-   '%s.%s' % (slap_configuration['instance-title'], name)  -}}
{%- endmacro  %}
{%- do ishared_list.append({
      'slave_title':      iref('RU'),
      'slave_reference':  False,
      '_': {
        'ru_type':      'sdr',
        'ru_link_type': 'sdr',
        'sdr_dev_list': [0],
        'n_antenna_dl': slapparameter_dict.n_antenna_dl,
        'n_antenna_ul': slapparameter_dict.n_antenna_ul,
        'tx_gain':      ors_version['current-tx-gain'],
        'rx_gain':      ors_version['current-rx-gain'],
        'txrx_active':  'ACTIVE'  if (not slapparameter_dict.disable_sdr)  else  'INACTIVE',
      } |tojson
    })
%}

{%- if enb_mode == 'enb' %}
{%-   set cell = {
      'cell_type':  'lte',
      'dl_earfcn':  ors_version['current-earfcn'],
      'bandwidth':  float(slapparameter_dict.bandwidth.removesuffix(' MHz')),
      'tac':        slapparameter_dict.tac,
      'root_sequence_index':  slapparameter_dict.root_sequence_index,
    }
%}
{%- elif enb_mode == 'gnb' %}
{%-   set cell = {
      'cell_type':  'nr',
      'dl_nr_arfcn':  ors_version['current-nr-arfcn'],
      'nr_band':      ors_version['current-nr-band'],
      'bandwidth':    slapparameter_dict.nr_bandwidth,
      'ssb_pos_bitmap': slapparameter_dict.ssb_pos_bitmap,
      'root_sequence_index':  slapparameter_dict.root_sequence_index,
    }
%}
{%- endif %}

{%- do cell.update({
      'cell_kind':  'enb',
      'rf_mode':    slapparameter_dict.rf_mode,
      'pci':        slapparameter_dict.pci,
      'cell_id':    slapparameter_dict.cell_id,
      'tdd_ul_dl_config': slapparameter_dict.tdd_ul_dl_config,
      'inactivity_timer': slapparameter_dict.inactivity_timer,

      'ru': { 'ru_type':  'ru_ref',
              'ru_ref':   iref('RU') }
    })
%}

{%- do ishared_list.append({
      'slave_title':      iref('CELL'),
      'slave_reference':  False,
      '_': cell | tojson
    })
%}


{#- inject synthesized peer cells #}
{%- for k, ncell in slapparameter_dict.ncell_list|dictsort %}
{%-   do ishared_list.append({
        'slave_title':      '%s%s' % (iref('PEERCELL'), k),
        'slave_reference':  False,
        '_': ncell | tojson
      })
%}
{%- endfor %}


{#- inject synthesized peers #}
{%- if enb_mode == 'lte' %}
{%-   for k, peer in slapparameter_dict.x2_peers|dictsort %}
{%-     do ishared_list.append({
          'slave_title':      '%s%s' % (iref('X2_PEER'), k),
          'slave_reference':  False,
          '_': {
            'peer_type':  'nr',
            'x2_addr':    peer.x2_addr,
          } | tojson
        })
%}
{%-   endfor  %}
{%- elif enb_mode == 'nr' %}
{%-   for k, peer in slapparameter_dict.xn_peers|dictsort %}
{%-     do ishared_list.append({
          'slave_title':      '%s%s' % (iref('XN_PEER'), k),
          'slave_reference':  False,
          '_': {
            'peer_type':  'nr',
            'xn_addr':    peer.xn_addr
          } | tojson
        })
%}
{%-   endfor  %}
{%- endif %}


{#- gnb: plmn_list -> plmn_list_5g #}
{%- if enb_mode == 'gnb'  %}
{%-   set _ = slapparameter_dict  %}
{%-   do _.update({'plmn_list_5g': _.plmn_list})  %}
{%-   do _.pop('plmn_list') %}
{%- endif %}


{#- backward compatibility: if ORS is running in gnb mode, and gnb_* parameters
    are present, replace their generic enb_* counterparts with gnb_* ones #}
{%- if enb_mode == 'gnb'  %}
{%-   set _ = slapparameter_dict  %}
{%-   if 'gnb_stats_fetch_period' in _  %}
{%-     do _.update({'enb_stats_fetch_period': _.gnb_stats_fetch_period}) %}
{%-   endif %}
{%-   if 'gnb_drb_stats_enabled' in _  %}
{%-     do _.update({'enb_drb_stats_enabled':  _.gnb_drb_stats_enabled}) %}
{%-   endif %}
{%- endif %}


# code of generic enb
{%  include 'instance-enb-base.jinja2.cfg' %}


# let all templates know we are running in ORS mode
[config-base]
context -=
   json ors false
context +=
   key ors :ors
ors = {{ dumps(ors_version) }}


# add ORS-specific bits to published information
[publish-connection-information]
ors-version = {{ ors_version['ors-version'] }}
frequency-range-rating = {{ ors_version['range'] }}
current-tx-power-estimate = {{ ors_version['power-estimate'] }}
current-tx-gain = {{ ors_version['current-tx-gain'] }}
current-rx-gain = {{ ors_version['current-rx-gain'] }}
cell-id = {{ slapparameter_dict['cell_id'] }}
physical-cell-id = {{ slapparameter_dict['pci'] }}
root-sequence-index = {{ slapparameter_dict['root_sequence_index'] }}
{%- if enb_mode == "enb" %}
enb-id = {{ slapparameter_dict['enb_id'] }}
eutra-cell-id = {{ ors_id['eutra_cell_id'] }}
{%- else %}
gnb-id = {{ slapparameter_dict['gnb_id'] }}
nr-cell-id = {{ ors_id['nr_cell_id'] }}
{%- endif %}
{%- if enb_mode == 'enb'  %}
current-frequency  = {{ xearfcn_module.frequency(ors_version['current-earfcn']) }} MHz
current-band  = {{ xearfcn_module.band(ors_version['current-earfcn'])[0]["band"] }}
current-earfcn  = {{ ors_version['current-earfcn'] }}
{%- elif enb_mode == 'gnb' %}
current-frequency  = {{ xnrarfcn_module.frequency(ors_version['current-nr-arfcn']) }} MHz
current-nr-band = {{ ors_version['current-nr-band'] }}
current-nr-arfcn = {{ ors_version['current-nr-arfcn'] }}
{%-   if slapparameter_dict.get('ssb_nr_arfcn', False) %}
current-ssb-nr-arfcn = {{ slapparameter_dict['ssb_nr_arfcn'] }}
{%-   else %}
{%-   set ssb_nr_arfcn, max_ssb_scs_khz = xnrarfcn_module.dl2ssb(ors_version['current-nr-arfcn'], ors_version['current-nr-band']) %}
current-ssb-nr-arfcn = {{ ssb_nr_arfcn | tojson }}
{%-   endif %}
{%- endif %}


# hide ru-list, cell-list, peer-list and peer-cell-list from published information
[publish-connection-information]
depends += ${publish-connection-information-ors-cleanup:recipe}
[publish-connection-information-ors-cleanup]
recipe = slapos.recipe.build
init =
  publish = self.buildout['publish-connection-information']
  del publish['ru-list']
  del publish['cell-list']
  del publish['peer-list']
  del publish['peer-cell-list']

# Add custom promise to check if /dev/sdr0 is busy
[check-frequency-outofbounds.py]
<= macro.promise
promise = check_frequency_outofbounds
{%- if enb_mode == 'enb'  %}
config-frequency  = {{ xearfcn_module.frequency(ors_version['current-earfcn']) }}
{%- elif enb_mode == 'gnb' %}
config-frequency  = {{ xnrarfcn_module.frequency(ors_version['current-nr-arfcn']) }}
{%- endif %}
config-range-rating = {{ ors_version['range'] }}

[buildout]
extra-parts +=
  check-frequency-outofbounds.py
