Example #1
0
def _qrtb_check_state_compatibility_with_ca(state: CBSDStateResult) -> bool:
    """
    Check if state returned by Domain Proxy contains data that can be applied
    to BaiCells QRTB BS in Carrier Aggregation Mode.
    BaiCells QRTB can apply carrier aggregation if:
    * 2 channels are available:
      * with symmetric bandwidths: 5+5, 10+10 or 20+20
      * with asymmetric bandwidths: 20+10 (10+20 theoretically supported)
    * Max IBW of the channels is 100MHz
        (IBW == max(high_frequency_hz) - min(low_frequency_hz), max and min taken from parameters of the 2 channels)

    Additionally, such channels may be available but Domain Proxy may explicitly disable CA

    Only check the first 2 channels (Domain Proxy may return more)
    """
    _MAX_IBW_HZ = 100_000_000
    _CA_SUPPORTED_BANDWIDTHS_MHZ = (
        (5, 5),
        (10, 10),
        (20, 20),
        (20, 10),
    )
    num_of_channels = len(state.channels)
    # Check if CA explicitly disabled, or not enough channels
    if num_of_channels < 2 or not state.carrier_aggregation_enabled:
        logger.debug(
            f"Domain Proxy state {num_of_channels=}, {state.carrier_aggregation_enabled=}."
        )
        return False

    ch1 = state.channels[0]
    ch2 = state.channels[1]

    # Check Max IBW
    high_frequency_hz = max(ch1.high_frequency_hz, ch2.high_frequency_hz)
    low_frequency_hz = min(ch1.low_frequency_hz, ch2.low_frequency_hz)
    if high_frequency_hz - low_frequency_hz > _MAX_IBW_HZ:
        logger.debug(
            f"Domain Proxy channel1 {ch1}, channel2 {ch2} exceed max IBW {_MAX_IBW_HZ}."
        )
        return False

    # Check supported bandwidths of the channels
    bw1 = calc_bandwidth_mhz(low_freq_hz=ch1.low_frequency_hz,
                             high_freq_hz=ch1.high_frequency_hz)
    bw2 = calc_bandwidth_mhz(low_freq_hz=ch2.low_frequency_hz,
                             high_freq_hz=ch2.high_frequency_hz)
    if not (bw1, bw2) in _CA_SUPPORTED_BANDWIDTHS_MHZ:
        logger.debug(
            f"Domain Proxy channel1 {ch1}, channel2 {ch2}, bandwidth configuration not in {_CA_SUPPORTED_BANDWIDTHS_MHZ}."
        )
        return False

    return True
Example #2
0
def qrtb_update_desired_config_from_cbsd_state(
        state: CBSDStateResult, config: EnodebConfiguration) -> None:
    """
    Call grpc endpoint on the Domain Proxy to update the desired config based on sas grant

    Args:
        state (CBSDStateResult): state result as received from DP
        config (EnodebConfiguration): configuration to update
    """
    logger.debug("Updating desired config based on sas grant")
    config.set_parameter(ParameterName.SAS_RADIO_ENABLE, state.radio_enabled)

    if not state.radio_enabled:
        return

    earfcn = calc_earfcn(state.channel.low_frequency_hz,
                         state.channel.high_frequency_hz)
    bandwidth_mhz = calc_bandwidth_mhz(state.channel.low_frequency_hz,
                                       state.channel.high_frequency_hz)
    bandwidth_rbs = calc_bandwidth_rbs(bandwidth_mhz)
    psd = _calc_psd(state.channel.max_eirp_dbm_mhz)

    params_to_set = {
        ParameterName.SAS_RADIO_ENABLE: True,
        ParameterName.BAND: BAND,
        ParameterName.DL_BANDWIDTH: bandwidth_rbs,
        ParameterName.UL_BANDWIDTH: bandwidth_rbs,
        ParameterName.EARFCNDL: earfcn,
        ParameterName.EARFCNUL: earfcn,
        ParameterName.POWER_SPECTRAL_DENSITY: psd,
    }

    for param, value in params_to_set.items():
        config.set_parameter(param, value)
Example #3
0
def qrtb_update_desired_config_from_cbsd_state(state: CBSDStateResult, config: EnodebConfiguration) -> None:
    """
    Call grpc endpoint on the Domain Proxy to update the desired config based on sas grant

    Args:
        state (CBSDStateResult): state result as received from DP
        config (EnodebConfiguration): configuration to update
    """
    logger.debug("Updating desired config based on Domain Proxy state.")
    num_of_channels = len(state.channels)
    radio_enabled = num_of_channels > 0 and state.radio_enabled
    config.set_parameter(ParameterName.SAS_RADIO_ENABLE, radio_enabled)

    if not radio_enabled:
        return

    # FAPService.1
    channel = state.channels[0]
    earfcn = calc_earfcn(channel.low_frequency_hz, channel.high_frequency_hz)
    bandwidth_mhz = calc_bandwidth_mhz(channel.low_frequency_hz, channel.high_frequency_hz)
    bandwidth_rbs = calc_bandwidth_rbs(bandwidth_mhz)
    psd = _calc_psd(channel.max_eirp_dbm_mhz)
    logger.debug(f"Channel1: {earfcn=}, {bandwidth_rbs=}, {psd=}")

    can_enable_carrier_aggregation = _qrtb_check_state_compatibility_with_ca(state)
    logger.debug(f"Should Carrier Aggregation be enabled on eNB: {can_enable_carrier_aggregation=}")
    # Enabling Carrier Aggregation on QRTB eNB means:
    # 1. Set CA_ENABLE to 1
    # 2. Set CA_NUM_OF_CELLS to 2
    # 3. Configure appropriate TR nodes for FAPSerivce.2 like EARFCNDL/UL etc
    # Otherwise we need to disable Carrier Aggregation on eNB and switch to Single Carrier configuration
    # 1. Set CA_ENABLE to 0
    # 2. Set CA_NUM_OF_CELLS to 1
    # Those two nodes should handle everything else accordingly.
    # (NOTE: carrier aggregation may still be enabled on Domain Proxy, but Domain Proxy may not have 2 channels granted by SAS.
    #        In such case, we still have to switch eNB to Single Carrier)
    num_of_cells = 2 if can_enable_carrier_aggregation else 1
    ca_enable = 1 if can_enable_carrier_aggregation else 0

    params_to_set = {
        ParameterName.SAS_RADIO_ENABLE: True,
        ParameterName.BAND: BAND,
        ParameterName.DL_BANDWIDTH: bandwidth_rbs,
        ParameterName.UL_BANDWIDTH: bandwidth_rbs,
        ParameterName.EARFCNDL: earfcn,
        ParameterName.EARFCNUL: earfcn,
        ParameterName.POWER_SPECTRAL_DENSITY: psd,
        CarrierAggregationParameters.CA_ENABLE: ca_enable,
        CarrierAggregationParameters.CA_NUM_OF_CELLS: num_of_cells,
    }
    if can_enable_carrier_aggregation:
        # Configure FAPService.2
        # NOTE: We set PCI and CELL_ID to the values of FAP1 "+1"
        #       This was suggested by BaiCells
        channel = state.channels[1]
        earfcn = calc_earfcn(channel.low_frequency_hz, channel.high_frequency_hz)
        bandwidth_mhz = calc_bandwidth_mhz(channel.low_frequency_hz, channel.high_frequency_hz)
        bandwidth_rbs = calc_bandwidth_rbs(bandwidth_mhz)
        psd = _calc_psd(channel.max_eirp_dbm_mhz)
        logger.debug(f"Channel2: {earfcn=}, {bandwidth_rbs=}, {psd=}")
        params_to_set.update({
            CarrierAggregationParameters.CA_DL_BANDWIDTH: bandwidth_rbs,
            CarrierAggregationParameters.CA_UL_BANDWIDTH: bandwidth_rbs,
            CarrierAggregationParameters.CA_BAND: BAND,
            CarrierAggregationParameters.CA_EARFCNDL: earfcn,
            CarrierAggregationParameters.CA_EARFCNUL: earfcn,
            CarrierAggregationParameters.CA_PCI: config.get_parameter(ParameterName.PCI) + 1,
            CarrierAggregationParameters.CA_CELL_ID: config.get_parameter(ParameterName.CELL_ID) + 1,
            CarrierAggregationParameters.CA_RADIO_ENABLE: True,
        })

    for param, value in params_to_set.items():
        config.set_parameter(param, value)