1#!/usr/bin/env python3
2#
3#   Copyright 2019 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the 'License');
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an 'AS IS' BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16from acts import logger
17from acts.test_utils.power import tel_simulations as sims
18
19
20class AbstractCellularSimulator:
21    """ A generic cellular simulator controller class that can be derived to
22    implement equipment specific classes and allows the tests to be implemented
23    without depending on a singular instrument model.
24
25    This class defines the interface that every cellular simulator controller
26    needs to implement and shouldn't be instantiated by itself. """
27
28    # Indicates if it is able to use 256 QAM as the downlink modulation for LTE
29    LTE_SUPPORTS_DL_256QAM = None
30
31    # Indicates if it is able to use 64 QAM as the uplink modulation for LTE
32    LTE_SUPPORTS_UL_64QAM = None
33
34    # Indicates if 4x4 MIMO is supported for LTE
35    LTE_SUPPORTS_4X4_MIMO = None
36
37    # The maximum number of carriers that this simulator can support for LTE
38    LTE_MAX_CARRIERS = None
39
40    # The maximum power that the equipment is able to transmit
41    MAX_DL_POWER = None
42
43    def __init__(self):
44        """ Initializes the cellular simulator. """
45        self.log = logger.create_tagged_trace_logger('CellularSimulator')
46
47    def destroy(self):
48        """ Sends finalization commands to the cellular equipment and closes
49        the connection. """
50        raise NotImplementedError()
51
52    def setup_lte_scenario(self):
53        """ Configures the equipment for an LTE simulation. """
54        raise NotImplementedError()
55
56    def setup_lte_ca_scenario(self):
57        """ Configures the equipment for an LTE with CA simulation. """
58        raise NotImplementedError()
59
60    def set_ca_combination(self, combination):
61        """ Prepares the test equipment for the indicated CA combination.
62
63        The reason why this is implemented in a separate method and not calling
64        LteSimulation.BtsConfig for each separate band is that configuring each
65        ssc cannot be done separately, as it is necessary to know which
66        carriers are on the same band in order to decide which RF outputs can
67        be shared in the test equipment.
68
69        Args:
70            combination: carrier aggregation configurations are indicated
71                with a list of strings consisting of the band number followed
72                by the CA class. For example, for 5 CA using 3C 7C and 28A
73                the parameter value should be [3c, 7c, 28a].
74        """
75        raise NotImplementedError()
76
77    def configure_bts(self, config, bts_index=0):
78        """ Commands the equipment to setup a base station with the required
79        configuration. This method applies configurations that are common to all
80        RATs.
81
82        Args:
83            config: a BaseSimulation.BtsConfig object.
84            bts_index: the base station number.
85        """
86
87        if config.output_power:
88            self.set_output_power(bts_index, config.output_power)
89
90        if config.input_power:
91            self.set_input_power(bts_index, config.input_power)
92
93        if isinstance(config, sims.LteSimulation.LteSimulation.BtsConfig):
94            self.configure_lte_bts(config, bts_index)
95
96    def configure_lte_bts(self, config, bts_index=0):
97        """ Commands the equipment to setup an LTE base station with the
98        required configuration.
99
100        Args:
101            config: an LteSimulation.BtsConfig object.
102            bts_index: the base station number.
103        """
104        if config.band:
105            self.set_band(bts_index, config.band)
106
107        if config.dlul_config:
108            self.set_tdd_config(bts_index, config.dlul_config)
109
110        if config.ssf_config:
111            self.set_ssf_config(bts_index, config.ssf_config)
112
113        if config.bandwidth:
114            self.set_bandwidth(bts_index, config.bandwidth)
115
116        if config.dl_channel:
117            self.set_downlink_channel_number(bts_index, config.dl_channel)
118
119        if config.mimo_mode:
120            self.set_mimo_mode(bts_index, config.mimo_mode)
121
122        if config.transmission_mode:
123            self.set_transmission_mode(bts_index, config.transmission_mode)
124
125        # Modulation order should be set before set_scheduling_mode being
126        # called.
127        if config.dl_modulation_order:
128            self.set_dl_modulation(bts_index, config.dl_modulation_order)
129
130        if config.ul_modulation_order:
131            self.set_ul_modulation(bts_index, config.ul_modulation_order)
132
133        if config.scheduling_mode:
134
135            if (config.scheduling_mode ==
136                    sims.LteSimulation.SchedulingMode.STATIC
137                    and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
138                             and config.ul_mcs)):
139                raise ValueError('When the scheduling mode is set to manual, '
140                                 'the RB and MCS parameters are required.')
141
142            # If scheduling mode is set to Dynamic, the RB and MCS parameters
143            # will be ignored by set_scheduling_mode.
144            self.set_scheduling_mode(bts_index, config.scheduling_mode,
145                                     config.dl_mcs, config.ul_mcs,
146                                     config.dl_rbs, config.ul_rbs)
147
148        # This variable stores a boolean value so the following is needed to
149        # differentiate False from None
150        if config.tbs_pattern_on is not None:
151            self.set_tbs_pattern_on(bts_index, config.tbs_pattern_on)
152
153        if config.cfi:
154            self.set_cfi(bts_index, config.cfi)
155
156        if config.paging_cycle:
157            self.set_paging_cycle(bts_index, config.paging_cycle)
158
159        if config.phich:
160            self.set_phich_resource(bts_index, config.phich)
161
162        if config.drx_connected_mode:
163            self.set_drx_connected_mode(bts_index, config.drx_connected_mode)
164
165            if config.drx_on_duration_timer:
166                self.set_drx_on_duration_timer(bts_index,
167                                               config.drx_on_duration_timer)
168
169            if config.drx_inactivity_timer:
170                self.set_drx_inactivity_timer(bts_index,
171                                              config.drx_inactivity_timer)
172
173            if config.drx_retransmission_timer:
174                self.set_drx_retransmission_timer(
175                    bts_index, config.drx_retransmission_timer)
176
177            if config.drx_long_cycle:
178                self.set_drx_long_cycle(bts_index, config.drx_long_cycle)
179
180            if config.drx_long_cycle_offset is not None:
181                self.set_drx_long_cycle_offset(bts_index,
182                                               config.drx_long_cycle_offset)
183
184    def set_lte_rrc_state_change_timer(self, enabled, time=10):
185        """ Configures the LTE RRC state change timer.
186
187        Args:
188            enabled: a boolean indicating if the timer should be on or off.
189            time: time in seconds for the timer to expire
190        """
191        raise NotImplementedError()
192
193    def set_band(self, bts_index, band):
194        """ Sets the band for the indicated base station.
195
196        Args:
197            bts_index: the base station number
198            band: the new band
199        """
200        raise NotImplementedError()
201
202    def set_input_power(self, bts_index, input_power):
203        """ Sets the input power for the indicated base station.
204
205        Args:
206            bts_index: the base station number
207            input_power: the new input power
208        """
209        raise NotImplementedError()
210
211    def set_output_power(self, bts_index, output_power):
212        """ Sets the output power for the indicated base station.
213
214        Args:
215            bts_index: the base station number
216            output_power: the new output power
217        """
218        raise NotImplementedError()
219
220    def set_tdd_config(self, bts_index, tdd_config):
221        """ Sets the tdd configuration number for the indicated base station.
222
223        Args:
224            bts_index: the base station number
225            tdd_config: the new tdd configuration number
226        """
227        raise NotImplementedError()
228
229    def set_ssf_config(self, bts_index, ssf_config):
230        """ Sets the Special Sub-Frame config number for the indicated
231        base station.
232
233        Args:
234            bts_index: the base station number
235            ssf_config: the new ssf config number
236        """
237        raise NotImplementedError()
238
239    def set_bandwidth(self, bts_index, bandwidth):
240        """ Sets the bandwidth for the indicated base station.
241
242        Args:
243            bts_index: the base station number
244            bandwidth: the new bandwidth
245        """
246        raise NotImplementedError()
247
248    def set_downlink_channel_number(self, bts_index, channel_number):
249        """ Sets the downlink channel number for the indicated base station.
250
251        Args:
252            bts_index: the base station number
253            channel_number: the new channel number
254        """
255        raise NotImplementedError()
256
257    def set_mimo_mode(self, bts_index, mimo_mode):
258        """ Sets the mimo mode for the indicated base station.
259
260        Args:
261            bts_index: the base station number
262            mimo_mode: the new mimo mode
263        """
264        raise NotImplementedError()
265
266    def set_transmission_mode(self, bts_index, transmission_mode):
267        """ Sets the transmission mode for the indicated base station.
268
269        Args:
270            bts_index: the base station number
271            transmission_mode: the new transmission mode
272        """
273        raise NotImplementedError()
274
275    def set_scheduling_mode(self, bts_index, scheduling_mode, mcs_dl, mcs_ul,
276                            nrb_dl, nrb_ul):
277        """ Sets the scheduling mode for the indicated base station.
278
279        Args:
280            bts_index: the base station number
281            scheduling_mode: the new scheduling mode
282            mcs_dl: Downlink MCS (only for STATIC scheduling)
283            mcs_ul: Uplink MCS (only for STATIC scheduling)
284            nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
285            nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
286        """
287        raise NotImplementedError()
288
289    def set_dl_modulation(self, bts_index, modulation):
290        """ Sets the DL modulation for the indicated base station.
291
292        Args:
293            bts_index: the base station number
294            modulation: the new DL modulation
295        """
296        raise NotImplementedError()
297
298    def set_ul_modulation(self, bts_index, modulation):
299        """ Sets the UL modulation for the indicated base station.
300
301        Args:
302            bts_index: the base station number
303            modulation: the new UL modulation
304        """
305        raise NotImplementedError()
306
307    def set_tbs_pattern_on(self, bts_index, tbs_pattern_on):
308        """ Enables or disables TBS pattern in the indicated base station.
309
310        Args:
311            bts_index: the base station number
312            tbs_pattern_on: the new TBS pattern setting
313        """
314        raise NotImplementedError()
315
316    def set_cfi(self, bts_index, cfi):
317        """ Sets the Channel Format Indicator for the indicated base station.
318
319        Args:
320            bts_index: the base station number
321            cfi: the new CFI setting
322        """
323        raise NotImplementedError()
324
325    def set_paging_cycle(self, bts_index, cycle_duration):
326        """ Sets the paging cycle duration for the indicated base station.
327
328        Args:
329            bts_index: the base station number
330            cycle_duration: the new paging cycle duration in milliseconds
331        """
332        raise NotImplementedError()
333
334    def set_phich_resource(self, bts_index, phich):
335        """ Sets the PHICH Resource setting for the indicated base station.
336
337        Args:
338            bts_index: the base station number
339            phich: the new PHICH resource setting
340        """
341        raise NotImplementedError()
342
343    def set_drx_connected_mode(self, bts_index, active):
344        """ Sets the time interval to wait before entering DRX mode
345
346        Args:
347            bts_index: the base station number
348            active: Boolean indicating whether cDRX mode
349                is active
350        """
351        raise NotImplementedError()
352
353    def set_drx_on_duration_timer(self, bts_index, timer):
354        """ Sets the amount of PDCCH subframes to wait for data after
355            waking up from a DRX cycle
356
357        Args:
358            bts_index: the base station number
359            timer: Number of PDCCH subframes to wait and check for user data
360                after waking from the DRX cycle
361        """
362        raise NotImplementedError()
363
364    def set_drx_inactivity_timer(self, bts_index, timer):
365        """ Sets the number of PDCCH subframes to wait before entering DRX mode
366
367        Args:
368            bts_index: the base station number
369            timer: The amount of time to wait before entering DRX mode
370        """
371        raise NotImplementedError()
372
373    def set_drx_retransmission_timer(self, bts_index, timer):
374        """ Sets the number of consecutive PDCCH subframes to wait
375        for retransmission
376
377        Args:
378            bts_index: the base station number
379            timer: Number of PDCCH subframes to remain active
380
381        """
382        raise NotImplementedError()
383
384    def set_drx_long_cycle(self, bts_index, cycle):
385        """ Sets the amount of subframes representing a DRX long cycle.
386
387        Args:
388            bts_index: the base station number
389            cycle: The amount of subframes representing one long DRX cycle.
390                One cycle consists of DRX sleep + DRX on duration
391        """
392        raise NotImplementedError()
393
394    def set_drx_long_cycle_offset(self, bts_index, offset):
395        """ Sets the offset used to determine the subframe number
396        to begin the long drx cycle
397
398        Args:
399            bts_index: the base station number
400            offset: Number in range 0 to (long cycle - 1)
401        """
402        raise NotImplementedError()
403
404    def lte_attach_secondary_carriers(self, ue_capability_enquiry):
405        """ Activates the secondary carriers for CA. Requires the DUT to be
406        attached to the primary carrier first.
407
408        Args:
409            ue_capability_enquiry: UE capability enquiry message to be sent to
410        the UE before starting carrier aggregation.
411        """
412        raise NotImplementedError()
413
414    def wait_until_attached(self, timeout=120):
415        """ Waits until the DUT is attached to the primary carrier.
416
417        Args:
418            timeout: after this amount of time the method will raise a
419                CellularSimulatorError exception. Default is 120 seconds.
420        """
421        raise NotImplementedError()
422
423    def wait_until_communication_state(self, timeout=120):
424        """ Waits until the DUT is in Communication state.
425
426        Args:
427            timeout: after this amount of time the method will raise a
428                CellularSimulatorError exception. Default is 120 seconds.
429        """
430        raise NotImplementedError()
431
432    def wait_until_idle_state(self, timeout=120):
433        """ Waits until the DUT is in Idle state.
434
435        Args:
436            timeout: after this amount of time the method will raise a
437                CellularSimulatorError exception. Default is 120 seconds.
438        """
439        raise NotImplementedError()
440
441    def detach(self):
442        """ Turns off all the base stations so the DUT loose connection."""
443        raise NotImplementedError()
444
445    def stop(self):
446        """ Stops current simulation. After calling this method, the simulator
447        will need to be set up again. """
448        raise NotImplementedError()
449
450    def start_data_traffic(self):
451        """ Starts transmitting data from the instrument to the DUT. """
452        raise NotImplementedError()
453
454    def stop_data_traffic(self):
455        """ Stops transmitting data from the instrument to the DUT. """
456        raise NotImplementedError()
457
458    def get_measured_pusch_power(self):
459        """ Queries PUSCH power measured at the callbox.
460
461        Returns:
462            The PUSCH power in the primary input port.
463        """
464        raise NotImplementedError()
465
466
467class CellularSimulatorError(Exception):
468    """ Exceptions thrown when the cellular equipment is unreachable or it
469    returns an error after receiving a command. """
470    pass
471