import os
import binascii
import itertools
import re
import struct
import subprocess
import random
from cereal import log
NetworkType = log . ThermalData . NetworkType
NetworkStrength = log . ThermalData . NetworkStrength
ANDROID = os . path . isfile ( ' /EON ' )
def getprop ( key ) :
if not ANDROID :
return " "
return subprocess . check_output ( [ " getprop " , key ] , encoding = ' utf8 ' ) . strip ( )
def get_imei ( slot ) :
slot = str ( slot )
if slot not in ( " 0 " , " 1 " ) :
raise ValueError ( " SIM slot must be 0 or 1 " )
ret = parse_service_call_string ( service_call ( [ " iphonesubinfo " , " 3 " , " i32 " , str ( slot ) ] ) )
if not ret :
# allow non android to be identified differently
ret = " %015d " % random . randint ( 0 , 1 << 32 )
return ret
def get_serial ( ) :
ret = getprop ( " ro.serialno " )
if ret == " " :
ret = " cccccccc "
return ret
def get_subscriber_info ( ) :
ret = parse_service_call_string ( service_call ( [ " iphonesubinfo " , " 7 " ] ) )
if ret is None or len ( ret ) < 8 :
return " "
return ret
def reboot ( reason = None ) :
if reason is None :
reason_args = [ " null " ]
else :
reason_args = [ " s16 " , reason ]
subprocess . check_output ( [
" service " , " call " , " power " , " 16 " , # IPowerManager.reboot
" i32 " , " 0 " , # no confirmation,
* reason_args ,
" i32 " , " 1 " # wait
] )
def service_call ( call ) :
if not ANDROID :
return None
ret = subprocess . check_output ( [ " service " , " call " , * call ] , encoding = ' utf8 ' ) . strip ( )
if ' Parcel ' not in ret :
return None
return parse_service_call_bytes ( ret )
def parse_service_call_unpack ( r , fmt ) :
try :
return struct . unpack ( fmt , r ) [ 0 ]
except Exception :
return None
def parse_service_call_string ( r ) :
try :
r = r [ 8 : ] # Cut off length field
r = r . decode ( ' utf_16_be ' )
# All pairs of two characters seem to be swapped. Not sure why
result = " "
for a , b , in itertools . zip_longest ( r [ : : 2 ] , r [ 1 : : 2 ] , fillvalue = ' \x00 ' ) :
result + = b + a
result = result . replace ( ' \x00 ' , ' ' )
return result
except Exception :
return None
def parse_service_call_bytes ( ret ) :
try :
r = b " "
for hex_part in re . findall ( r ' [ (]([0-9a-f] {8} ) ' , ret ) :
r + = binascii . unhexlify ( hex_part )
return r
except Exception :
return None
def get_network_type ( ) :
if not ANDROID :
return NetworkType . none
wifi_check = parse_service_call_string ( service_call ( [ " connectivity " , " 2 " ] ) )
if wifi_check is None :
return NetworkType . none
elif ' WIFI ' in wifi_check :
return NetworkType . wifi
else :
cell_check = parse_service_call_unpack ( service_call ( [ ' phone ' , ' 59 ' ] ) , " >q " )
# from TelephonyManager.java
cell_networks = {
0 : NetworkType . none ,
1 : NetworkType . cell2G ,
2 : NetworkType . cell2G ,
3 : NetworkType . cell3G ,
4 : NetworkType . cell2G ,
5 : NetworkType . cell3G ,
6 : NetworkType . cell3G ,
7 : NetworkType . cell3G ,
8 : NetworkType . cell3G ,
9 : NetworkType . cell3G ,
10 : NetworkType . cell3G ,
11 : NetworkType . cell2G ,
12 : NetworkType . cell3G ,
13 : NetworkType . cell4G ,
14 : NetworkType . cell4G ,
15 : NetworkType . cell3G ,
16 : NetworkType . cell2G ,
17 : NetworkType . cell3G ,
18 : NetworkType . cell4G ,
19 : NetworkType . cell4G
}
return cell_networks . get ( cell_check , NetworkType . none )
def get_network_strength ( network_type ) :
network_strength = NetworkStrength . unknown
# from SignalStrength.java
def get_lte_level ( rsrp , rssnr ) :
INT_MAX = 2147483647
if rsrp == INT_MAX :
lvl_rsrp = NetworkStrength . unknown
elif rsrp > = - 95 :
lvl_rsrp = NetworkStrength . great
elif rsrp > = - 105 :
lvl_rsrp = NetworkStrength . good
elif rsrp > = - 115 :
lvl_rsrp = NetworkStrength . moderate
else :
lvl_rsrp = NetworkStrength . poor
if rssnr == INT_MAX :
lvl_rssnr = NetworkStrength . unknown
elif rssnr > = 45 :
lvl_rssnr = NetworkStrength . great
elif rssnr > = 10 :
lvl_rssnr = NetworkStrength . good
elif rssnr > = - 30 :
lvl_rssnr = NetworkStrength . moderate
else :
lvl_rssnr = NetworkStrength . poor
return max ( lvl_rsrp , lvl_rssnr )
def get_tdscdma_level ( tdscmadbm ) :
lvl = NetworkStrength . unknown
if tdscmadbm > - 25 :
lvl = NetworkStrength . unknown
elif tdscmadbm > = - 49 :
lvl = NetworkStrength . great
elif tdscmadbm > = - 73 :
lvl = NetworkStrength . good
elif tdscmadbm > = - 97 :
lvl = NetworkStrength . moderate
elif tdscmadbm > = - 110 :
lvl = NetworkStrength . poor
return lvl
def get_gsm_level ( asu ) :
if asu < = 2 or asu == 99 :
lvl = NetworkStrength . unknown
elif asu > = 12 :
lvl = NetworkStrength . great
elif asu > = 8 :
lvl = NetworkStrength . good
elif asu > = 5 :
lvl = NetworkStrength . moderate
else :
lvl = NetworkStrength . poor
return lvl
def get_evdo_level ( evdodbm , evdosnr ) :
lvl_evdodbm = NetworkStrength . unknown
lvl_evdosnr = NetworkStrength . unknown
if evdodbm > = - 65 :
lvl_evdodbm = NetworkStrength . great
elif evdodbm > = - 75 :
lvl_evdodbm = NetworkStrength . good
elif evdodbm > = - 90 :
lvl_evdodbm = NetworkStrength . moderate
elif evdodbm > = - 105 :
lvl_evdodbm = NetworkStrength . poor
if evdosnr > = 7 :
lvl_evdosnr = NetworkStrength . great
elif evdosnr > = 5 :
lvl_evdosnr = NetworkStrength . good
elif evdosnr > = 3 :
lvl_evdosnr = NetworkStrength . moderate
elif evdosnr > = 1 :
lvl_evdosnr = NetworkStrength . poor
return max ( lvl_evdodbm , lvl_evdosnr )
def get_cdma_level ( cdmadbm , cdmaecio ) :
lvl_cdmadbm = NetworkStrength . unknown
lvl_cdmaecio = NetworkStrength . unknown
if cdmadbm > = - 75 :
lvl_cdmadbm = NetworkStrength . great
elif cdmadbm > = - 85 :
lvl_cdmadbm = NetworkStrength . good
elif cdmadbm > = - 95 :
lvl_cdmadbm = NetworkStrength . moderate
elif cdmadbm > = - 100 :
lvl_cdmadbm = NetworkStrength . poor
if cdmaecio > = - 90 :
lvl_cdmaecio = NetworkStrength . great
elif cdmaecio > = - 110 :
lvl_cdmaecio = NetworkStrength . good
elif cdmaecio > = - 130 :
lvl_cdmaecio = NetworkStrength . moderate
elif cdmaecio > = - 150 :
lvl_cdmaecio = NetworkStrength . poor
return max ( lvl_cdmadbm , lvl_cdmaecio )
if network_type == NetworkType . none :
return network_strength
if network_type == NetworkType . wifi :
out = subprocess . check_output ( ' dumpsys connectivity ' , shell = True ) . decode ( ' utf-8 ' )
network_strength = NetworkStrength . unknown
for line in out . split ( ' \n ' ) :
signal_str = " SignalStrength: "
if signal_str in line :
lvl_idx_start = line . find ( signal_str ) + len ( signal_str )
lvl_idx_end = line . find ( ' ] ' , lvl_idx_start )
lvl = int ( line [ lvl_idx_start : lvl_idx_end ] )
if lvl > = - 50 :
network_strength = NetworkStrength . great
elif lvl > = - 60 :
network_strength = NetworkStrength . good
elif lvl > = - 70 :
network_strength = NetworkStrength . moderate
else :
network_strength = NetworkStrength . poor
return network_strength
else :
# check cell strength
out = subprocess . check_output ( ' dumpsys telephony.registry ' , shell = True ) . decode ( ' utf-8 ' )
for line in out . split ( ' \n ' ) :
if " mSignalStrength " in line :
arr = line . split ( ' ' )
ns = 0
if ( " gsm " in arr [ 14 ] ) :
rsrp = int ( arr [ 9 ] )
rssnr = int ( arr [ 11 ] )
ns = get_lte_level ( rsrp , rssnr )
if ns == NetworkStrength . unknown :
tdscmadbm = int ( arr [ 13 ] )
ns = get_tdscdma_level ( tdscmadbm )
if ns == NetworkStrength . unknown :
asu = int ( arr [ 1 ] )
ns = get_gsm_level ( asu )
else :
cdmadbm = int ( arr [ 3 ] )
cdmaecio = int ( arr [ 4 ] )
evdodbm = int ( arr [ 5 ] )
evdosnr = int ( arr [ 7 ] )
lvl_cdma = get_cdma_level ( cdmadbm , cdmaecio )
lvl_edmo = get_evdo_level ( evdodbm , evdosnr )
if lvl_edmo == NetworkStrength . unknown :
ns = lvl_cdma
elif lvl_cdma == NetworkStrength . unknown :
ns = lvl_edmo
else :
ns = min ( lvl_cdma , lvl_edmo )
network_strength = max ( network_strength , ns )
return network_strength