1#!/usr/bin/env python3 2# 3# Copyright (C) 2021 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. 16""" 17Python module for General abstract GNSS Simulator. 18@author: Clay Liao (jianhsiungliao@) 19""" 20from time import sleep 21from acts.controllers.spectracom_lib import gsg6 22from acts.controllers.spirent_lib import gss7000 23from acts import logger 24from acts.utils import ping 25from acts.libs.proc import job 26 27 28class AbstractGnssSimulator: 29 """General abstract GNSS Simulator""" 30 31 def __init__(self, simulator, ip_addr, ip_port, ip_port_ctrl=7717): 32 """Init AbstractGnssSimulator 33 34 Args: 35 simulator: GNSS simulator name, 36 Type, str 37 Option 'gss7000/gsg6' 38 ip_addr: IP Address. 39 Type, str 40 ip_port: TCPIP Port, 41 Type, str 42 ip_port_ctrl: TCPIP port, 43 Type, int 44 Default, 7717 45 """ 46 self.simulator_name = str(simulator).lower() 47 self.ip_addr = ip_addr 48 self.ip_port = ip_port 49 self.ip_port_ctrl = ip_port_ctrl 50 self._logger = logger.create_tagged_trace_logger( 51 '%s %s:%s' % (simulator, self.ip_addr, self.ip_port)) 52 if self.simulator_name == 'gsg6': 53 self._logger.info('GNSS simulator is GSG6') 54 self.simulator = gsg6.GSG6(self.ip_addr, self.ip_port) 55 elif self.simulator_name == 'gss7000': 56 self._logger.info('GNSS simulator is GSS7000') 57 self.simulator = gss7000.GSS7000(self.ip_addr, self.ip_port, 58 self.ip_port_ctrl) 59 else: 60 self._logger.error('No matched GNSS simulator') 61 raise AttributeError( 62 'The GNSS simulator in config file is {} which is not supported.' 63 .format(self.simulator_name)) 64 65 def connect(self): 66 """Connect to GNSS Simulator""" 67 self._logger.debug('Connect to GNSS Simulator {}'.format( 68 self.simulator_name.upper())) 69 self.simulator.connect() 70 71 def close(self): 72 """Disconnect from GNSS Simulator""" 73 self._logger.debug('Disconnect from GNSS Simulator {}'.format( 74 self.simulator_name.upper())) 75 self.simulator.close() 76 77 def start_scenario(self, scenario=''): 78 """Start the running scenario. 79 80 Args: 81 scenario: path of scenario, 82 Type, str 83 """ 84 self._logger.info('Start GNSS Scenario {}'.format(scenario)) 85 self.simulator.start_scenario(scenario) 86 87 def stop_scenario(self): 88 """Stop the running scenario.""" 89 self._logger.debug('Stop playing scenario') 90 self.simulator.stop_scenario() 91 92 def set_power(self, power_level=-130): 93 """Set scenario power level. 94 Args: 95 power_level: target power level in dBm for gsg6 or gss7000, 96 gsg6 power_level range is [-160, -65], 97 gss7000 power_level range is [-170, -115] 98 Type, float, 99 """ 100 self.simulator.set_power(power_level) 101 102 def set_power_offset(self, gss7000_ant=1, pwr_offset=0): 103 """Set scenario power level offset based on reference level. 104 The default reference level is -130dBm for GPS L1. 105 Args: 106 ant: target gss7000 RF port, 107 Type, int 108 pwr_offset: target power offset in dB, 109 Type, float 110 """ 111 if self.simulator_name == 'gsg6': 112 power_level = -130 + pwr_offset 113 self.simulator.set_power(power_level) 114 elif self.simulator_name == 'gss7000': 115 self.simulator.set_power_offset(gss7000_ant, pwr_offset) 116 else: 117 self._logger.error('No GNSS simulator is available') 118 119 def set_scenario_power(self, 120 power_level, 121 sat_id='', 122 sat_system='', 123 freq_band=''): 124 """Set dynamic power for the running scenario. 125 126 Args: 127 power_level: transmit power level 128 Type, float. 129 Decimal, unit [dBm] 130 sat_id: set power level for specific satellite identifiers 131 Type, str. 132 Option 133 For GSG-6: 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx' 134 where xx is satellite identifiers number 135 e.g.: G10 136 For GSS7000: Provide SVID. 137 Default, '', assumed All. 138 sat_system: to set power level for all Satellites 139 Type, str 140 Option [GPS, GLO, GAL, BDS, QZSS, IRNSS, SBAS] 141 Default, '', assumed All. 142 freq_band: Frequency band to set the power level 143 Type, str 144 Default, '', assumed to be L1. 145 Raises: 146 RuntimeError: raise when instrument does not support this function. 147 """ 148 self.simulator.set_scenario_power(power_level=power_level, 149 sat_id=sat_id, 150 sat_system=sat_system, 151 freq_band=freq_band) 152 153 def toggle_scenario_power(self, 154 toggle_onoff='ON', 155 sat_id='', 156 sat_system=''): 157 """Toggle ON OFF scenario. 158 159 Args: 160 toggle_onoff: turn on or off the satellites 161 Type, str. Option ON/OFF 162 Default, 'ON' 163 sat_id: satellite identifiers 164 Type, str. 165 Option 'Gxx/Rxx/Exx/Cxx/Jxx/Ixx/Sxxx' 166 where xx is satellite identifiers no. 167 e.g.: G10 168 sat_system: to toggle On/OFF for all Satellites 169 Type, str 170 Option 'GPS/GLO/GAL' 171 """ 172 # TODO: [b/208719212] Currently only support GSG-6. Will implement GSS7000 feature. 173 if self.simulator_name == 'gsg6': 174 self.simulator.toggle_scenario_power(toggle_onoff=toggle_onoff, 175 sat_id=sat_id, 176 sat_system=sat_system) 177 else: 178 raise RuntimeError('{} does not support this function'.format( 179 self.simulator_name)) 180 181 def ping_inst(self, retry=3, wait=1): 182 """Ping IP of instrument to check if the connection is stable. 183 Args: 184 retry: Retry times. 185 Type, int. 186 Default, 3. 187 wait: Wait time between each ping command when ping fail is met. 188 Type, int. 189 Default, 1. 190 Return: 191 True/False of ping result. 192 """ 193 for i in range(retry): 194 ret = ping(job, self.ip_addr) 195 self._logger.debug(f'Ping return results: {ret}') 196 if ret.get('packet_loss') == '0': 197 return True 198 self._logger.warning(f'Fail to ping GNSS Simulator: {i+1}') 199 sleep(wait) 200 return False 201