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.
16import time
17
18from acts.controllers.rohdeschwarz_lib import cmw500
19from acts.controllers import cellular_simulator as cc
20from acts.controllers.rohdeschwarz_lib import cmw500_scenario_generator as cg
21from acts.controllers.cellular_lib import LteSimulation
22
23CMW_TM_MAPPING = {
24    LteSimulation.TransmissionMode.TM1: cmw500.TransmissionModes.TM1,
25    LteSimulation.TransmissionMode.TM2: cmw500.TransmissionModes.TM2,
26    LteSimulation.TransmissionMode.TM3: cmw500.TransmissionModes.TM3,
27    LteSimulation.TransmissionMode.TM4: cmw500.TransmissionModes.TM4,
28    LteSimulation.TransmissionMode.TM7: cmw500.TransmissionModes.TM7,
29    LteSimulation.TransmissionMode.TM8: cmw500.TransmissionModes.TM8,
30    LteSimulation.TransmissionMode.TM9: cmw500.TransmissionModes.TM9
31}
32
33CMW_SCH_MAPPING = {
34    LteSimulation.SchedulingMode.STATIC: cmw500.SchedulingMode.USERDEFINEDCH
35}
36
37CMW_MIMO_MAPPING = {
38    LteSimulation.MimoMode.MIMO_1x1: cmw500.MimoModes.MIMO1x1,
39    LteSimulation.MimoMode.MIMO_2x2: cmw500.MimoModes.MIMO2x2,
40    LteSimulation.MimoMode.MIMO_4x4: cmw500.MimoModes.MIMO4x4
41}
42
43MIMO_ANTENNA_COUNT = {
44    LteSimulation.MimoMode.MIMO_1x1: 1,
45    LteSimulation.MimoMode.MIMO_2x2: 2,
46    LteSimulation.MimoMode.MIMO_4x4: 4,
47}
48
49IP_ADDRESS_TYPE_MAPPING = {
50    LteSimulation.IPAddressType.IPV4: cmw500.IPAddressType.IPV4,
51    LteSimulation.IPAddressType.IPV6: cmw500.IPAddressType.IPV6,
52    LteSimulation.IPAddressType.IPV4V6: cmw500.IPAddressType.IPV4V6,
53}
54
55# get mcs vs tbsi map with 256-qam disabled(downlink)
56get_mcs_tbsi_map_dl = {
57    cmw500.ModulationType.QPSK: {
58        0: 0,
59        1: 1,
60        2: 2,
61        3: 3,
62        4: 4,
63        5: 5,
64        6: 6,
65        7: 7,
66        8: 8,
67        9: 9
68    },
69    cmw500.ModulationType.Q16: {
70        10: 9,
71        11: 10,
72        12: 11,
73        13: 12,
74        14: 13,
75        15: 14,
76        16: 15
77    },
78    cmw500.ModulationType.Q64: {
79        17: 15,
80        18: 16,
81        19: 17,
82        20: 18,
83        21: 19,
84        22: 20,
85        23: 21,
86        24: 22,
87        25: 23,
88        26: 24,
89        27: 25,
90        28: 26
91    }
92}
93
94# get mcs vs tbsi map with 256-qam enabled(downlink)
95get_mcs_tbsi_map_for_256qam_dl = {
96    cmw500.ModulationType.QPSK: {
97        0: 0,
98        1: 2,
99        2: 4,
100        3: 6,
101        4: 8,
102    },
103    cmw500.ModulationType.Q16: {
104        5: 10,
105        6: 11,
106        7: 12,
107        8: 13,
108        9: 14,
109        10: 15
110    },
111    cmw500.ModulationType.Q64: {
112        11: 16,
113        12: 17,
114        13: 18,
115        14: 19,
116        15: 20,
117        16: 21,
118        17: 22,
119        18: 23,
120        19: 24
121    },
122    cmw500.ModulationType.Q256: {
123        20: 25,
124        21: 27,
125        22: 28,
126        23: 29,
127        24: 30,
128        25: 31,
129        26: 32,
130        27: 33
131    }
132}
133
134# get mcs vs tbsi map (uplink)
135get_mcs_tbsi_map_ul = {
136    cmw500.ModulationType.QPSK: {
137        0: 0,
138        1: 1,
139        2: 2,
140        3: 3,
141        4: 4,
142        5: 5,
143        6: 6,
144        7: 7,
145        8: 8,
146        9: 9
147    },
148    cmw500.ModulationType.Q16: {
149        10: 10,
150        11: 10,
151        12: 11,
152        13: 12,
153        14: 13,
154        15: 14,
155        16: 15,
156        17: 16,
157        18: 17,
158        19: 18,
159        20: 19,
160        21: 19,
161        22: 20,
162        23: 21,
163        24: 22,
164        25: 23,
165        26: 24,
166        27: 25,
167        28: 26
168    }
169}
170
171
172class CMW500CellularSimulator(cc.AbstractCellularSimulator):
173    """ A cellular simulator for telephony simulations based on the CMW 500
174    controller. """
175
176    # The maximum number of carriers that this simulator can support for LTE
177    LTE_MAX_CARRIERS = 1
178
179    def __init__(self, ip_address, port):
180        """ Initializes the cellular simulator.
181
182        Args:
183            ip_address: the ip address of the CMW500
184            port: the port number for the CMW500 controller
185        """
186        super().__init__()
187
188        try:
189            self.cmw = cmw500.Cmw500(ip_address, port)
190        except cmw500.CmwError:
191            raise cc.CellularSimulatorError('Could not connect to CMW500.')
192
193        self.bts = None
194        self.dl_modulation = None
195        self.ul_modulation = None
196
197    def destroy(self):
198        """ Sends finalization commands to the cellular equipment and closes
199        the connection. """
200        self.cmw.disconnect()
201
202    def setup_lte_scenario(self):
203        """ Configures the equipment for an LTE simulation. """
204        self.cmw.connection_type = cmw500.ConnectionType.DAU
205        # if bts has not yet been initialized
206        if not self.bts:
207            self.bts = [self.cmw.get_base_station()]
208        self.cmw.switch_lte_signalling(cmw500.LteState.LTE_ON)
209
210    def set_band_combination(self, bands, mimo_modes):
211        """ Prepares the test equipment for the indicated band/mimo combination.
212
213        Args:
214            bands: a list of bands represented as ints or strings
215            mimo_modes: a list of LteSimulation.MimoMode to use for each carrier
216        """
217        self.num_carriers = len(bands)
218        self.bts = [self.cmw.get_base_station(cmw500.BtsNumber.BTS1)]
219        for i in range(1, len(bands)):
220            self.bts.append(
221                self.cmw.get_base_station(cmw500.BtsNumber('SCC{}'.format(i))))
222
223        antennas = [MIMO_ANTENNA_COUNT[m] for m in mimo_modes]
224        self.set_scenario(bands, antennas)
225
226    def get_band_combination(self):
227        return [int(bts.band.strip('OB')) for bts in self.bts]
228
229    def set_lte_rrc_state_change_timer(self, enabled, time=10):
230        """ Configures the LTE RRC state change timer.
231
232        Args:
233            enabled: a boolean indicating if the timer should be on or off.
234            time: time in seconds for the timer to expire
235        """
236        if enabled:
237            self.cmw.rrc_connection = cmw500.RrcState.RRC_OFF
238            self.cmw.rrc_connection_timer = time
239        else:
240            self.cmw.rrc_connection = cmw500.RrcState.RRC_ON
241
242    def set_band(self, bts_index, band):
243        """ Sets the band for the indicated base station.
244
245        Args:
246            bts_index: the base station number
247            band: the new band
248        """
249        bts = self.bts[bts_index]
250        bts.duplex_mode = self.get_duplex_mode(band)
251        band = 'OB' + band
252        bts.band = band
253        self.log.debug('Band set to {}'.format(band))
254
255    def get_duplex_mode(self, band):
256        """ Determines if the band uses FDD or TDD duplex mode
257
258        Args:
259            band: a band number
260
261        Returns:
262            an variable of class DuplexMode indicating if band is FDD or TDD
263        """
264        if 33 <= int(band) <= 46:
265            return cmw500.DuplexMode.TDD
266        else:
267            return cmw500.DuplexMode.FDD
268
269    def set_input_power(self, bts_index, input_power):
270        """ Sets the input power for the indicated base station.
271
272        Args:
273            bts_index: the base station number
274            input_power: the new input power
275        """
276        bts = self.bts[bts_index]
277        if input_power > 23:
278            self.log.warning('Open loop supports-50dBm to 23 dBm. '
279                             'Setting it to max power 23 dBm')
280            input_power = 23
281        bts.tpc_closed_loop_target_power = input_power
282        bts.uplink_power_control = input_power
283        bts.tpc_power_control = cmw500.TpcPowerControl.CLOSED_LOOP
284
285    def set_output_power(self, bts_index, output_power):
286        """ Sets the output power for the indicated base station.
287
288        Args:
289            bts_index: the base station number
290            output_power: the new output power
291        """
292        bts = self.bts[bts_index]
293        bts.downlink_power_level = output_power
294
295    def set_tdd_config(self, bts_index, tdd_config):
296        """ Sets the tdd configuration number for the indicated base station.
297
298        Args:
299            bts_index: the base station number
300            tdd_config: the new tdd configuration number
301        """
302        self.bts[bts_index].uldl_configuration = tdd_config
303
304    def set_ssf_config(self, bts_index, ssf_config):
305        """ Sets the Special Sub-Frame config number for the indicated
306        base station.
307
308        Args:
309            bts_index: the base station number
310            ssf_config: the new ssf config number
311        """
312        if not 0 <= ssf_config <= 9:
313            raise ValueError('The Special Sub-Frame configuration has to be a '
314                             'number between 0 and 9.')
315
316        self.bts[bts_index].tdd_special_subframe = ssf_config
317
318    def set_bandwidth(self, bts_index, bandwidth):
319        """ Sets the bandwidth for the indicated base station.
320
321        Args:
322            bts_index: the base station number
323            bandwidth: the new bandwidth
324        """
325        bts = self.bts[bts_index]
326
327        if bandwidth == 20:
328            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_20MHz
329        elif bandwidth == 15:
330            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_15MHz
331        elif bandwidth == 10:
332            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_10MHz
333        elif bandwidth == 5:
334            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_5MHz
335        elif bandwidth == 3:
336            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_3MHz
337        elif bandwidth == 1.4:
338            bts.bandwidth = cmw500.LteBandwidth.BANDWIDTH_1MHz
339        else:
340            msg = 'Bandwidth {} MHz is not valid for LTE'.format(bandwidth)
341            raise ValueError(msg)
342
343    def set_downlink_channel_number(self, bts_index, channel_number):
344        """ Sets the downlink channel number for the indicated base station.
345
346        Args:
347            bts_index: the base station number
348            channel_number: the new channel number
349        """
350        bts = self.bts[bts_index]
351        bts.dl_channel = channel_number
352        self.log.debug('Downlink Channel set to {}'.format(bts.dl_channel))
353
354    def set_mimo_mode(self, bts_index, mimo_mode):
355        """ Sets the mimo mode for the indicated base station.
356
357        Args:
358            bts_index: the base station number
359            mimo_mode: the new mimo mode
360        """
361        bts = self.bts[bts_index]
362        mimo_mode = CMW_MIMO_MAPPING[mimo_mode]
363        if mimo_mode == cmw500.MimoModes.MIMO1x1:
364            self.set_bts_antenna(bts_index, 1)
365            bts.dl_antenna = cmw500.MimoModes.MIMO1x1
366
367        elif mimo_mode == cmw500.MimoModes.MIMO2x2:
368            self.set_bts_antenna(bts_index, 2)
369            bts.dl_antenna = cmw500.MimoModes.MIMO2x2
370            # set default transmission mode and DCI for this scenario
371            bts.transmode = cmw500.TransmissionModes.TM3
372            bts.dci_format = cmw500.DciFormat.D2A
373
374        elif mimo_mode == cmw500.MimoModes.MIMO4x4:
375            self.set_bts_antenna(bts_index, 4)
376            bts.dl_antenna = cmw500.MimoModes.MIMO4x4
377        else:
378            raise RuntimeError('The requested MIMO mode is not supported.')
379
380    def set_bts_antenna(self, bts_index, antenna_count):
381        """ Sets the mimo mode for a particular component carrier.
382
383        Args:
384            bts_index: index of the base station to configure.
385            antenna_count: number of antennas to use for the component carrier
386                either (1, 2, 4)
387        """
388        antennas = self.get_antenna_combination()
389        antennas[bts_index] = antenna_count
390        bands = self.get_band_combination()
391        self.set_scenario(bands, antennas)
392
393    def get_antenna_combination(self):
394        """ Gets the current antenna configuration.
395
396        Returns:
397            antenna_count: a list containing the number of antennas to use for
398                each bts/CC.
399        """
400        cmd = 'ROUTe:LTE:SIGN:SCENario?'
401        scenario_name = self.cmw.send_and_recv(cmd)
402        return cg.get_antennas(scenario_name)
403
404    def set_scenario(self, bands, antennas):
405        """ Sets the MIMO scenario on the CMW.
406
407        Args:
408            bands: a list defining the bands to use for each CC.
409            antennas: a list of integers defining the number of antennas to use
410                for each bts/CC.
411        """
412        self.log.debug('Setting scenario: bands: {}, antennas: {}'.format(
413            bands, antennas))
414        scenario = cg.get_scenario(bands, antennas)
415        cmd = 'ROUTe:LTE:SIGN:SCENario:{}:FLEXible {}'.format(
416            scenario.name, scenario.routing)
417        self.cmw.send_and_recv(cmd)
418        self.cmw.scc_activation_mode = cmw500.SccActivationMode.AUTO
419
420        # apply requested bands now
421        for i, band in enumerate(bands):
422            self.set_band(i, str(band))
423
424    def set_transmission_mode(self, bts_index, tmode):
425        """ Sets the transmission mode for the indicated base station.
426
427        Args:
428            bts_index: the base station number
429            tmode: the new transmission mode
430        """
431        bts = self.bts[bts_index]
432
433        tmode = CMW_TM_MAPPING[tmode]
434
435        if (tmode in [
436                cmw500.TransmissionModes.TM1, cmw500.TransmissionModes.TM7
437        ] and bts.dl_antenna == cmw500.MimoModes.MIMO1x1.value):
438            bts.transmode = tmode
439        elif (tmode.value in cmw500.TransmissionModes.__members__
440              and bts.dl_antenna == cmw500.MimoModes.MIMO2x2.value):
441            bts.transmode = tmode
442        elif (tmode in [
443                cmw500.TransmissionModes.TM2, cmw500.TransmissionModes.TM3,
444                cmw500.TransmissionModes.TM4, cmw500.TransmissionModes.TM9
445        ] and bts.dl_antenna == cmw500.MimoModes.MIMO4x4.value):
446            bts.transmode = tmode
447
448        else:
449            raise ValueError('Transmission modes should support the current '
450                             'mimo mode')
451
452    def set_scheduling_mode(self,
453                            bts_index,
454                            scheduling,
455                            mcs_dl=None,
456                            mcs_ul=None,
457                            nrb_dl=None,
458                            nrb_ul=None):
459        """ Sets the scheduling mode for the indicated base station.
460
461        Args:
462            bts_index: the base station number.
463            scheduling: the new scheduling mode.
464            mcs_dl: Downlink MCS.
465            mcs_ul: Uplink MCS.
466            nrb_dl: Number of RBs for downlink.
467            nrb_ul: Number of RBs for uplink.
468        """
469        bts = self.bts[bts_index]
470        bts.reduced_pdcch = cmw500.ReducedPdcch.ON
471
472        scheduling = CMW_SCH_MAPPING[scheduling]
473        bts.scheduling_mode = scheduling
474
475        if not (self.ul_modulation and self.dl_modulation):
476            raise ValueError('Modulation should be set prior to scheduling '
477                             'call')
478
479        if scheduling == cmw500.SchedulingMode.RMC:
480
481            if not nrb_ul and nrb_dl:
482                raise ValueError('nrb_ul and nrb dl should not be none')
483
484            bts.rb_configuration_ul = (nrb_ul, self.ul_modulation, 'KEEP')
485            self.log.info('ul rb configurations set to {}'.format(
486                bts.rb_configuration_ul))
487
488            time.sleep(1)
489
490            self.log.debug('Setting rb configurations for down link')
491            bts.rb_configuration_dl = (nrb_dl, self.dl_modulation, 'KEEP')
492            self.log.info('dl rb configurations set to {}'.format(
493                bts.rb_configuration_ul))
494
495        elif scheduling == cmw500.SchedulingMode.USERDEFINEDCH:
496
497            if not all([nrb_ul, nrb_dl, mcs_dl, mcs_ul]):
498                raise ValueError('All parameters are mandatory.')
499
500            tbs = get_mcs_tbsi_map_ul[self.ul_modulation][mcs_ul]
501
502            bts.rb_configuration_ul = (nrb_ul, 0, self.ul_modulation, tbs)
503            self.log.info('ul rb configurations set to {}'.format(
504                bts.rb_configuration_ul))
505
506            time.sleep(1)
507
508            if self.dl_256_qam_enabled:
509                tbs = get_mcs_tbsi_map_for_256qam_dl[
510                    self.dl_modulation][mcs_dl]
511            else:
512                tbs = get_mcs_tbsi_map_dl[self.dl_modulation][mcs_dl]
513
514            bts.rb_configuration_dl = (nrb_dl, 0, self.dl_modulation, tbs)
515            self.log.info('dl rb configurations set to {}'.format(
516                bts.rb_configuration_dl))
517
518    def set_dl_256_qam_enabled(self, bts_index, enabled):
519        """ Determines what MCS table should be used for the downlink.
520        This only saves the setting that will be used when configuring MCS.
521
522        Args:
523            bts_index: the base station number
524            enabled: whether 256 QAM should be used
525        """
526        self.log.info('Set 256 QAM DL MCS enabled: ' + str(enabled))
527        self.dl_modulation = cmw500.ModulationType.Q256 if enabled \
528            else cmw500.ModulationType.Q64
529        self.dl_256_qam_enabled = enabled
530
531    def set_ul_64_qam_enabled(self, bts_index, enabled):
532        """ Determines what MCS table should be used for the uplink.
533        This only saves the setting that will be used when configuring MCS.
534
535        Args:
536            bts_index: the base station number
537            enabled: whether 64 QAM should be used
538        """
539        self.log.info('Set 64 QAM UL MCS enabled: ' + str(enabled))
540        self.ul_modulation = cmw500.ModulationType.Q64 if enabled \
541            else cmw500.ModulationType.Q16
542        self.ul_64_qam_enabled = enabled
543
544    def set_mac_padding(self, bts_index, mac_padding):
545        """ Enables or disables MAC padding in the indicated base station.
546
547        Args:
548            bts_index: the base station number
549            mac_padding: the new MAC padding setting
550        """
551        # TODO (b/143918664): CMW500 doesn't have an equivalent setting.
552
553    def set_cfi(self, bts_index, cfi):
554        """ Sets the Channel Format Indicator for the indicated base station.
555
556        Args:
557            bts_index: the base station number
558            cfi: the new CFI setting
559        """
560        # TODO (b/143497738): implement.
561        self.log.error('Setting CFI is not yet implemented in the CMW500 '
562                       'controller.')
563
564    def set_paging_cycle(self, bts_index, cycle_duration):
565        """ Sets the paging cycle duration for the indicated base station.
566
567        Args:
568            bts_index: the base station number
569            cycle_duration: the new paging cycle duration in milliseconds
570        """
571        # TODO (b/146068532): implement.
572        self.log.error('Setting the paging cycle duration is not yet '
573                       'implemented in the CMW500 controller.')
574
575    def set_phich_resource(self, bts_index, phich):
576        """ Sets the PHICH Resource setting for the indicated base station.
577
578        Args:
579            bts_index: the base station number
580            phich: the new PHICH resource setting
581        """
582        self.log.error('Configuring the PHICH resource setting is not yet '
583                       'implemented in the CMW500 controller.')
584
585    def set_drx_connected_mode(self, bts_index, active):
586        """ Sets the time interval to wait before entering DRX mode
587
588        Args:
589            bts_index: the base station number
590            active: Boolean indicating whether cDRX mode
591                is active
592        """
593        self.cmw.drx_connected_mode = (cmw500.DrxMode.USER_DEFINED
594                                       if active else cmw500.DrxMode.OFF)
595
596    def set_drx_on_duration_timer(self, bts_index, timer):
597        """ Sets the amount of PDCCH subframes to wait for data after
598            waking up from a DRX cycle
599
600        Args:
601            bts_index: the base station number
602            timer: Number of PDCCH subframes to wait and check for user data
603                after waking from the DRX cycle
604        """
605        timer = 'PSF{}'.format(timer)
606        self.cmw.drx_on_duration_timer = timer
607
608    def set_drx_inactivity_timer(self, bts_index, timer):
609        """ Sets the number of PDCCH subframes to wait before entering DRX mode
610
611        Args:
612            bts_index: the base station number
613            timer: The amount of time to wait before entering DRX mode
614        """
615        timer = 'PSF{}'.format(timer)
616        self.cmw.drx_inactivity_timer = timer
617
618    def set_drx_retransmission_timer(self, bts_index, timer):
619        """ Sets the number of consecutive PDCCH subframes to wait
620        for retransmission
621
622        Args:
623            bts_index: the base station number
624            timer: Number of PDCCH subframes to remain active
625        """
626        timer = 'PSF{}'.format(timer)
627        self.cmw.drx_retransmission_timer = timer
628
629    def set_drx_long_cycle(self, bts_index, cycle):
630        """ Sets the amount of subframes representing a DRX long cycle.
631
632        Args:
633            bts_index: the base station number
634            cycle: The amount of subframes representing one long DRX cycle.
635                One cycle consists of DRX sleep + DRX on duration
636        """
637        cycle = 'SF{}'.format(cycle)
638        self.cmw.drx_long_cycle = cycle
639
640    def set_drx_long_cycle_offset(self, bts_index, offset):
641        """ Sets the offset used to determine the subframe number
642        to begin the long drx cycle
643
644        Args:
645            bts_index: the base station number
646            offset: Number in range 0 to (long cycle - 1)
647        """
648        self.cmw.drx_long_cycle_offset = offset
649
650    def set_apn(self, apn):
651        """ Configures the callbox network Access Point Name.
652
653        Args:
654            apn: the APN name
655        """
656        self.cmw.apn = apn
657
658    def set_ip_type(self, ip_type):
659        """ Configures the callbox network IP type.
660
661        Args:
662            ip_type: the network type to use.
663        """
664        self.cmw.ip_type = IP_ADDRESS_TYPE_MAPPING[ip_type]
665
666    def set_mtu(self, mtu):
667        """ Configures the callbox network Maximum Transmission Unit.
668
669        Args:
670            mtu: the MTU size.
671        """
672        self.cmw.mtu = mtu
673
674    def lte_attach_secondary_carriers(self, ue_capability_enquiry):
675        """ Activates the secondary carriers for CA. Requires the DUT to be
676        attached to the primary carrier first.
677
678        Args:
679            ue_capability_enquiry: UE capability enquiry message to be sent to
680        the UE before starting carrier aggregation.
681        """
682        for i in range(1, len(self.bts)):
683            bts = self.bts[i]
684            if bts.scc_state == cmw500.SccState.OFF.value:
685                if (self.cmw.scc_activation_mode ==
686                        cmw500.SccActivationMode.MANUAL.value):
687                    self.cmw.switch_scc_state(i, cmw500.SccState.ON)
688                # SEMI_AUTO -> directly to MAC activation
689                if (self.cmw.scc_activation_mode ==
690                        cmw500.SccActivationMode.SEMI_AUTO.value):
691                    self.cmw.switch_scc_state(i, cmw500.SccState.MAC)
692
693            # no need to do anything for auto
694            if self.cmw.scc_activation_mode != cmw500.SccActivationMode.AUTO.value:
695                if bts.scc_state == cmw500.SccState.ON.value:
696                    self.cmw.switch_scc_state(i, cmw500.SccState.RRC)
697
698                if bts.scc_state == cmw500.SccState.RRC.value:
699                    self.cmw.switch_scc_state(i, cmw500.SccState.MAC)
700
701            self.cmw.wait_for_scc_state(i, [cmw500.SccState.MAC])
702
703    def wait_until_attached(self, timeout=120):
704        """ Waits until the DUT is attached to the primary carrier.
705
706        Args:
707            timeout: after this amount of time the method will raise a
708                CellularSimulatorError exception. Default is 120 seconds.
709        """
710        try:
711            self.cmw.wait_for_attached_state(timeout=timeout)
712        except cmw500.CmwError:
713            raise cc.CellularSimulatorError('The phone was not in '
714                                            'attached state before '
715                                            'the timeout period ended.')
716
717    def wait_until_communication_state(self, timeout=120):
718        """ Waits until the DUT is in Communication state.
719
720        Args:
721            timeout: after this amount of time the method will raise a
722                CellularSimulatorError exception. Default is 120 seconds.
723        """
724        try:
725            self.cmw.wait_for_rrc_state(cmw500.LTE_CONN_RESP, timeout=timeout)
726        except cmw500.CmwError:
727            raise cc.CellularSimulatorError('The phone was not in '
728                                            'Communication state before '
729                                            'the timeout period ended.')
730
731    def wait_until_idle_state(self, timeout=120):
732        """ Waits until the DUT is in Idle state.
733
734        Args:
735            timeout: after this amount of time the method will raise a
736                CellularSimulatorError exception. Default is 120 seconds.
737        """
738        try:
739            self.cmw.wait_for_rrc_state(cmw500.LTE_IDLE_RESP, timeout=timeout)
740        except cmw500.CmwError:
741            raise cc.CellularSimulatorError('The phone was not in '
742                                            'Idle state before '
743                                            'the timeout period ended.')
744
745    def wait_until_quiet(self, timeout=120):
746        """Waits for all pending operations to finish on the simulator.
747
748        Args:
749            timeout: after this amount of time the method will raise a
750                CellularSimulatorError exception. Default is 120 seconds.
751        """
752        self.cmw.send_and_recv('*OPC?')
753
754    def detach(self):
755        """ Turns off all the base stations so the DUT loose connection."""
756        self.cmw.detach()
757
758    def stop(self):
759        """ Stops current simulation. After calling this method, the simulator
760        will need to be set up again. """
761        self.detach()
762        self.cmw.switch_lte_signalling(cmw500.LteState.LTE_OFF)
763
764    def start_data_traffic(self):
765        """ Starts transmitting data from the instrument to the DUT. """
766        raise NotImplementedError()
767
768    def stop_data_traffic(self):
769        """ Stops transmitting data from the instrument to the DUT. """
770        raise NotImplementedError()
771
772    def send_sms(self, message):
773        """ Sends an SMS message to the DUT.
774
775        Args:
776            message: the SMS message to send.
777        """
778        self.cmw.set_sms(message)
779        self.cmw.send_sms()
780