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.controllers import cellular_lib
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    # The maximum number of carriers that this simulator can support for LTE
29    LTE_MAX_CARRIERS = None
30
31    # The maximum power that the equipment is able to transmit
32    MAX_DL_POWER = None
33
34    def __init__(self):
35        """ Initializes the cellular simulator. """
36        self.log = logger.create_tagged_trace_logger('CellularSimulator')
37        self.num_carriers = None
38
39    def destroy(self):
40        """ Sends finalization commands to the cellular equipment and closes
41        the connection. """
42        raise NotImplementedError()
43
44    def setup_lte_scenario(self):
45        """ Configures the equipment for an LTE simulation. """
46        raise NotImplementedError()
47
48    def set_band_combination(self, bands, mimo_modes):
49        """ Prepares the test equipment for the indicated band/mimo combination.
50
51        Args:
52            bands: a list of bands represented as ints or strings
53            mimo_modes: a list of LteSimulation.MimoMode to use for each antenna
54        """
55        raise NotImplementedError()
56
57    def configure_bts(self, config, bts_index=0):
58        """ Commands the equipment to setup a base station with the required
59        configuration. This method applies configurations that are common to all
60        RATs.
61
62        Args:
63            config: a BaseSimulation.BtsConfig object.
64            bts_index: the base station number.
65        """
66
67        config_vars = vars(config)
68        config_dict = {
69            key: config_vars[key]
70            for key in config_vars if config_vars[key]
71        }
72        self.log.info('The config for {} is {}'.format(bts_index, config_dict))
73
74        if config.output_power:
75            self.set_output_power(bts_index, config.output_power)
76
77        if config.input_power:
78            self.set_input_power(bts_index, config.input_power)
79
80        if isinstance(config, cellular_lib.LteCellConfig.LteCellConfig):
81            self.configure_lte_bts(config, bts_index)
82
83        if isinstance(config, cellular_lib.NrCellConfig.NrCellConfig):
84            self.configure_nr_bts(config, bts_index)
85
86    def configure_bts_after_started(self, config, bts_index=0):
87        """ Commands the equipment to setup a base station with the required
88        configuration after simulation started. This method applies
89        configurations for some simulator.
90
91        Args:
92            config: a BaseSimulation.BtsConfig object.
93            bts_index: the base station number.
94        """
95
96        self.log.info('Configure after simulation started for some simulator')
97
98        if isinstance(config, cellular_lib.LteCellConfig.LteCellConfig):
99            self.configure_lte_bts_after_started(config, bts_index)
100
101        if isinstance(config, cellular_lib.NrCellConfig.NrCellConfig):
102            self.configure_nr_bts_after_started(config, bts_index)
103
104
105    def configure_lte_bts_after_started(self, config, bts_index=0):
106        """ Commands the equipment to further setup a lte base station.
107
108        This is for some simulator where further setup is needed after the
109           simulation started.
110
111        Args:
112            config: a BaseSimulation.BtsConfig object.
113            bts_index: the base station number.
114        """
115        pass
116
117    def configure_nr_bts_after_started(self, config, bts_index=0):
118        """ Commands the equipment to further setup a lte base station.
119
120        This is for some simulator where further setup is needed after the
121           simulation started.
122
123        Args:
124            config: a BaseSimulation.BtsConfig object.
125            bts_index: the base station number.
126        """
127        pass
128
129    def configure_lte_bts_base(self, config, bts_index=0):
130        """ Commands the equipment to setup an LTE base station with the
131        required configuration.
132
133        Args:
134            config: an LteSimulation.BtsConfig object.
135            bts_index: the base station number.
136        """
137        if config.tracking_area:
138            self.set_tracking_area(bts_index, config.tracking_area)
139
140        if config.band:
141            self.set_band(bts_index, config.band)
142
143        if config.dlul_config:
144            self.set_tdd_config(bts_index, config.dlul_config)
145
146        if config.ssf_config:
147            self.set_ssf_config(bts_index, config.ssf_config)
148
149        if config.bandwidth:
150            self.set_bandwidth(bts_index, config.bandwidth)
151
152        if config.dl_channel:
153            self.set_downlink_channel_number(bts_index, config.dl_channel)
154
155        if config.mimo_mode:
156            self.set_mimo_mode(bts_index, config.mimo_mode)
157
158        if config.transmission_mode:
159            self.set_transmission_mode(bts_index, config.transmission_mode)
160
161        # Modulation order should be set before set_scheduling_mode being
162        # called.
163        if config.dl_256_qam_enabled is not None:
164            self.set_dl_256_qam_enabled(bts_index, config.dl_256_qam_enabled)
165
166        if config.ul_64_qam_enabled is not None:
167            self.set_ul_64_qam_enabled(bts_index, config.ul_64_qam_enabled)
168
169        if config.scheduling_mode:
170
171            if (config.scheduling_mode
172                    == cellular_lib.LteSimulation.SchedulingMode.STATIC
173                    and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
174                             and config.ul_mcs)):
175                raise ValueError('When the scheduling mode is set to manual, '
176                                 'the RB and MCS parameters are required.')
177
178            # If scheduling mode is set to Dynamic, the RB and MCS parameters
179            # will be ignored by set_scheduling_mode.
180            self.set_scheduling_mode(bts_index, config.scheduling_mode,
181                                     config.dl_mcs, config.ul_mcs,
182                                     config.dl_rbs, config.ul_rbs)
183
184        # This variable stores a boolean value so the following is needed to
185        # differentiate False from None
186        if config.mac_padding is not None:
187            self.set_mac_padding(bts_index, config.mac_padding)
188
189        if config.cfi:
190            self.set_cfi(bts_index, config.cfi)
191
192        if config.paging_cycle:
193            self.set_paging_cycle(bts_index, config.paging_cycle)
194
195        if config.phich:
196            self.set_phich_resource(bts_index, config.phich)
197
198    def configure_lte_bts(self, config, bts_index=0):
199        """ Commands the equipment to setup an LTE base station with the
200        required configuration.
201
202        For some simulator (for example cmx500), cdrx has to be configured after
203        similation started in some cases (for example nsa test). Also, it is
204        fine for this simulator to configure cdrx after the cell starts. Thus,
205        split the method of configure_lte_bts to two parts so that the cdrx
206        configuration could be done after the simulation starts for some
207        simulator.
208
209        Args:
210            config: an LteSimulation.BtsConfig object.
211            bts_index: the base station number.
212        """
213
214        self.configure_lte_bts_base(config, bts_index=bts_index)
215        if config.drx_connected_mode:
216            self.set_drx_connected_mode(bts_index, config.drx_connected_mode)
217
218            if config.drx_on_duration_timer:
219                self.set_drx_on_duration_timer(bts_index,
220                                               config.drx_on_duration_timer)
221
222            if config.drx_inactivity_timer:
223                self.set_drx_inactivity_timer(bts_index,
224                                              config.drx_inactivity_timer)
225
226            if config.drx_retransmission_timer:
227                self.set_drx_retransmission_timer(
228                    bts_index, config.drx_retransmission_timer)
229
230            if config.drx_long_cycle:
231                self.set_drx_long_cycle(bts_index, config.drx_long_cycle)
232
233            if config.drx_long_cycle_offset is not None:
234                self.set_drx_long_cycle_offset(bts_index,
235                                               config.drx_long_cycle_offset)
236
237    def configure_nr_bts(self, config, bts_index=1):
238        """ Commands the equipment to setup an LTE base station with the
239        required configuration.
240
241        Args:
242            config: an LteSimulation.BtsConfig object.
243            bts_index: the base station number.
244        """
245        if config.tracking_area:
246            self.set_tracking_area(bts_index, config.tracking_area)
247
248        if config.band:
249            self.set_band(bts_index, config.band)
250
251        if config.nr_arfcn:
252            self.set_downlink_channel_number(bts_index, config.nr_arfcn)
253
254        if config.bandwidth:
255            self.set_bandwidth(bts_index, config.bandwidth)
256
257        if config.mimo_mode:
258            self.set_mimo_mode(bts_index, config.mimo_mode)
259
260        if config.scheduling_mode:
261
262            if (config.scheduling_mode
263                    == cellular_lib.LteSimulation.SchedulingMode.STATIC
264                    and not (config.dl_rbs and config.ul_rbs and config.dl_mcs
265                             and config.ul_mcs)):
266                raise ValueError('When the scheduling mode is set to manual, '
267                                 'the RB and MCS parameters are required.')
268
269            # If scheduling mode is set to Dynamic, the RB and MCS parameters
270            # will be ignored by set_scheduling_mode.
271            self.set_scheduling_mode(bts_index, config.scheduling_mode,
272                                     config.dl_mcs, config.ul_mcs,
273                                     config.dl_rbs, config.ul_rbs)
274        if config.mac_padding is not None:
275            self.set_mac_padding(bts_index, config.mac_padding)
276
277    def set_lte_rrc_state_change_timer(self, enabled, time=10):
278        """ Configures the LTE RRC state change timer.
279
280        Args:
281            enabled: a boolean indicating if the timer should be on or off.
282            time: time in seconds for the timer to expire
283        """
284        raise NotImplementedError()
285
286    def set_band(self, bts_index, band):
287        """ Sets the band for the indicated base station.
288
289        Args:
290            bts_index: the base station number
291            band: the new band
292        """
293        raise NotImplementedError()
294
295    def set_input_power(self, bts_index, input_power):
296        """ Sets the input power for the indicated base station.
297
298        Args:
299            bts_index: the base station number
300            input_power: the new input power
301        """
302        raise NotImplementedError()
303
304    def set_output_power(self, bts_index, output_power):
305        """ Sets the output power for the indicated base station.
306
307        Args:
308            bts_index: the base station number
309            output_power: the new output power
310        """
311        raise NotImplementedError()
312
313    def set_tdd_config(self, bts_index, tdd_config):
314        """ Sets the tdd configuration number for the indicated base station.
315
316        Args:
317            bts_index: the base station number
318            tdd_config: the new tdd configuration number
319        """
320        raise NotImplementedError()
321
322    def set_ssf_config(self, bts_index, ssf_config):
323        """ Sets the Special Sub-Frame config number for the indicated
324        base station.
325
326        Args:
327            bts_index: the base station number
328            ssf_config: the new ssf config number
329        """
330        raise NotImplementedError()
331
332    def set_bandwidth(self, bts_index, bandwidth):
333        """ Sets the bandwidth for the indicated base station.
334
335        Args:
336            bts_index: the base station number
337            bandwidth: the new bandwidth
338        """
339        raise NotImplementedError()
340
341    def set_downlink_channel_number(self, bts_index, channel_number):
342        """ Sets the downlink channel number for the indicated base station.
343
344        Args:
345            bts_index: the base station number
346            channel_number: the new channel number
347        """
348        raise NotImplementedError()
349
350    def set_mimo_mode(self, bts_index, mimo_mode):
351        """ Sets the mimo mode for the indicated base station.
352
353        Args:
354            bts_index: the base station number
355            mimo_mode: the new mimo mode
356        """
357        raise NotImplementedError()
358
359    def set_transmission_mode(self, bts_index, transmission_mode):
360        """ Sets the transmission mode for the indicated base station.
361
362        Args:
363            bts_index: the base station number
364            transmission_mode: the new transmission mode
365        """
366        raise NotImplementedError()
367
368    def set_scheduling_mode(self, bts_index, scheduling_mode, mcs_dl, mcs_ul,
369                            nrb_dl, nrb_ul):
370        """ Sets the scheduling mode for the indicated base station.
371
372        Args:
373            bts_index: the base station number
374            scheduling_mode: the new scheduling mode
375            mcs_dl: Downlink MCS (only for STATIC scheduling)
376            mcs_ul: Uplink MCS (only for STATIC scheduling)
377            nrb_dl: Number of RBs for downlink (only for STATIC scheduling)
378            nrb_ul: Number of RBs for uplink (only for STATIC scheduling)
379        """
380        raise NotImplementedError()
381
382    def set_dl_256_qam_enabled(self, bts_index, enabled):
383        """ Determines what MCS table should be used for the downlink.
384
385        Args:
386            bts_index: the base station number
387            enabled: whether 256 QAM should be used
388        """
389        raise NotImplementedError()
390
391    def set_ul_64_qam_enabled(self, bts_index, enabled):
392        """ Determines what MCS table should be used for the uplink.
393
394        Args:
395            bts_index: the base station number
396            enabled: whether 64 QAM should be used
397        """
398        raise NotImplementedError()
399
400    def set_mac_padding(self, bts_index, mac_padding):
401        """ Enables or disables MAC padding in the indicated base station.
402
403        Args:
404            bts_index: the base station number
405            mac_padding: the new MAC padding setting
406        """
407        raise NotImplementedError()
408
409    def set_cfi(self, bts_index, cfi):
410        """ Sets the Channel Format Indicator for the indicated base station.
411
412        Args:
413            bts_index: the base station number
414            cfi: the new CFI setting
415        """
416        raise NotImplementedError()
417
418    def set_paging_cycle(self, bts_index, cycle_duration):
419        """ Sets the paging cycle duration for the indicated base station.
420
421        Args:
422            bts_index: the base station number
423            cycle_duration: the new paging cycle duration in milliseconds
424        """
425        raise NotImplementedError()
426
427    def set_phich_resource(self, bts_index, phich):
428        """ Sets the PHICH Resource setting for the indicated base station.
429
430        Args:
431            bts_index: the base station number
432            phich: the new PHICH resource setting
433        """
434        raise NotImplementedError()
435
436    def set_drx_connected_mode(self, bts_index, active):
437        """ Sets the time interval to wait before entering DRX mode
438
439        Args:
440            bts_index: the base station number
441            active: Boolean indicating whether cDRX mode
442                is active
443        """
444        raise NotImplementedError()
445
446    def set_drx_on_duration_timer(self, bts_index, timer):
447        """ Sets the amount of PDCCH subframes to wait for data after
448            waking up from a DRX cycle
449
450        Args:
451            bts_index: the base station number
452            timer: Number of PDCCH subframes to wait and check for user data
453                after waking from the DRX cycle
454        """
455        raise NotImplementedError()
456
457    def set_drx_inactivity_timer(self, bts_index, timer):
458        """ Sets the number of PDCCH subframes to wait before entering DRX mode
459
460        Args:
461            bts_index: the base station number
462            timer: The amount of time to wait before entering DRX mode
463        """
464        raise NotImplementedError()
465
466    def set_drx_retransmission_timer(self, bts_index, timer):
467        """ Sets the number of consecutive PDCCH subframes to wait
468        for retransmission
469
470        Args:
471            bts_index: the base station number
472            timer: Number of PDCCH subframes to remain active
473
474        """
475        raise NotImplementedError()
476
477    def set_drx_long_cycle(self, bts_index, cycle):
478        """ Sets the amount of subframes representing a DRX long cycle.
479
480        Args:
481            bts_index: the base station number
482            cycle: The amount of subframes representing one long DRX cycle.
483                One cycle consists of DRX sleep + DRX on duration
484        """
485        raise NotImplementedError()
486
487    def set_drx_long_cycle_offset(self, bts_index, offset):
488        """ Sets the offset used to determine the subframe number
489        to begin the long drx cycle
490
491        Args:
492            bts_index: the base station number
493            offset: Number in range 0 to (long cycle - 1)
494        """
495        raise NotImplementedError()
496
497    def set_tracking_area(self, bts_index, tac):
498        """ Assigns the cell to a specific tracking area.
499
500        Args:
501            tac: the unique tac to assign the cell to.
502        """
503        raise NotImplementedError()
504
505    def set_apn(self, apn):
506        """ Configures the callbox network Access Point Name.
507
508        Args:
509            apn: the APN name
510        """
511        raise NotImplementedError()
512
513    def set_ip_type(self, ip_type):
514        """ Configures the callbox network IP type.
515
516        Args:
517            ip_type: the network type to use.
518        """
519        raise NotImplementedError()
520
521    def set_mtu(self, mtu):
522        """ Configures the callbox network Maximum Transmission Unit.
523
524        Args:
525            mtu: the MTU size.
526        """
527        raise NotImplementedError()
528
529    def lte_attach_secondary_carriers(self, ue_capability_enquiry):
530        """ Activates the secondary carriers for CA. Requires the DUT to be
531        attached to the primary carrier first.
532
533        Args:
534            ue_capability_enquiry: UE capability enquiry message to be sent to
535        the UE before starting carrier aggregation.
536        """
537        raise NotImplementedError()
538
539    def wait_until_attached(self, timeout=120):
540        """ Waits until the DUT is attached to the primary carrier.
541
542        Args:
543            timeout: after this amount of time the method will raise a
544                CellularSimulatorError exception. Default is 120 seconds.
545        """
546        raise NotImplementedError()
547
548    def wait_until_communication_state(self, timeout=120):
549        """ Waits until the DUT is in Communication state.
550
551        Args:
552            timeout: after this amount of time the method will raise a
553                CellularSimulatorError exception. Default is 120 seconds.
554        """
555        raise NotImplementedError()
556
557    def wait_until_idle_state(self, timeout=120):
558        """ Waits until the DUT is in Idle state.
559
560        Args:
561            timeout: after this amount of time the method will raise a
562                CellularSimulatorError exception. Default is 120 seconds.
563        """
564        raise NotImplementedError()
565
566    def wait_until_quiet(self, timeout=120):
567        """Waits for all pending operations to finish on the simulator.
568
569        Args:
570            timeout: after this amount of time the method will raise a
571                CellularSimulatorError exception. Default is 120 seconds.
572        """
573        raise NotImplementedError()
574
575    def detach(self):
576        """ Turns off all the base stations so the DUT loose connection."""
577        raise NotImplementedError()
578
579    def stop(self):
580        """ Stops current simulation. After calling this method, the simulator
581        will need to be set up again. """
582        raise NotImplementedError()
583
584    def start_data_traffic(self):
585        """ Starts transmitting data from the instrument to the DUT. """
586        raise NotImplementedError()
587
588    def stop_data_traffic(self):
589        """ Stops transmitting data from the instrument to the DUT. """
590        raise NotImplementedError()
591
592    def get_measured_pusch_power(self):
593        """ Queries PUSCH power measured at the callbox.
594
595        Returns:
596            The PUSCH power in the primary input port.
597        """
598        raise NotImplementedError()
599
600    def send_sms(self, message):
601        """ Sends an SMS message to the DUT.
602
603        Args:
604            message: the SMS message to send.
605        """
606        raise NotImplementedError()
607
608
609class CellularSimulatorError(Exception):
610    """ Exceptions thrown when the cellular equipment is unreachable or it
611    returns an error after receiving a command. """
612