Files
StarPilot/selfdrive/manager.py
T
George Hotz 640ab12c72 openpilot 0.4.3.1 (#220)
* Honda Pilot 2017 Port (#161)

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update interface.py

* Update interface.py

* Update README.md

* Update README.md

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update carstate.py

* Update hondacan.py

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update carstate.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update carstate.py

* Update carstate.py

* Update Pilot Fingerprint

* Update fingerprints.py

* Give pilot its own definition and not use ILX

* add pilot argument

* Add Pilot interface

* Add pilot argument

* Update interface.py

* Parse Different gear on pilot

* Add steer max

* Fixed duplication of steer max value

* Adjust PID's for steering

* Update carcontroller.py

* Change Steer Ratio and wheelbase

* Update Steer fault values

Steer fault value of 3, does not seem to effect anything

* Update Kp,Ki Ratio

* Update interface.py

* Update readme for Pilot

* add pilot

* Update fingerprints.py

* Update carstate.py

* add signals

* add signal

* fix restricting video upload to wifi

* Dibs on SAFETY_GM numerical value

To match Panda repo.

* Safety Reference for Honda Bosch

* Update fingerprints.py (#210)

Consolidated my fingerprint and removed duplicates and ordered the fingerprint for the RAV4H. Double Checked.

* Interpolate ki/kp for steering PID loop (#200)

* Interpolate ki/kp for steering PID loop

Very much needed for the Volt port: car ping-pongs with low kp
on high speeeds, and the loop is unstable with high kp on
low speeds.

Also, removes "number or array?" logic from PIController,
now that all the callers use interpolation ofr ki/kp.

* Pass speed to steering PID loop for ki/kp interpolation

* Remove unused numbers import

* Slight changes to UI and Fingerprint for Odyssey Elite (#196)

* Adding back drive time to UI

* Add fingerprint for Odyssey Elite

* Removed extended fingerprint for Elite

* Revert "Adding back drive time to UI"

This reverts commit b9b02f7ff2511f28922f0bea47cd8c70bb9f4010.

* Squashed 'panda/' changes from 98f29a4..67d5208

67d5208 fix signedness issue in toyota safety
fe15d3f bump pandacan
11c2b08 add fault invalid
2c26e45 add sleep
27c7637 forgot the counter
3a6d7db don't hang
bfa7d2e canloader works
b259e2a can flasher is close to working
83f2edf isotp can support in softloader
7ae7c79 typo
e85cc47 forgot the selfs
190b4f6 start work on canflasher
5c655c9 add recover support
ae3457f usbflash is reliable
f7a0ab0 pedal usbflash works
585d0f9 add way to call isotp
be82899 despite it being bad code, move isotp
000715b start work on pedal canloader
626e312 pedal has a bootstub now
3662d1e redundant check
81e6b0d fix bug
083cd12 should have bounty to refactor that ish
b65d30c bad asserts
b2e6c3f isotp untested support for subaddr
30fd66a Merge pull request #93 from vntarasov/volt
06f5109 Merge pull request #94 from gregjhogan/can-printer-hex
c7d098c Merge pull request #95 from gregjhogan/setup-script
22fe250 Merge pull request #99 from gregjhogan/bit-transition-example
ba16ba3 Merge pull request #100 from gregjhogan/j2534-troubleshooting-instructions
ad08ea4 Merge pull request #90 from gregjhogan/can-forwarding
f3b6f5d added j2534 troubleshooting instructions
858d150 added script to find bits that transition from 0 to 1
c6acac8 added checking pedal interceptor message length
f7226ff added brake safety checks
d0c2634 added gas safety checks
d378e4a removed bosch safety forwarding restriction on 29 bit addresses
5c7ef9e added bosch safety hooks and forwarding
90c64b6 add note
23de8d4 Merge pull request #97 from commaai/pedal_improvements
0261641 added missing python packages
b92b235 fix bytearray encode issue
2434f1c Tweak Volt's brake pedal stickiness
e2f73d2 enable has a whole byte to itself
d5a9e1e correct checksum
f8ed9fa better names
986a14c don't alias pointers
9b8472e add watchdog support
8f0add9 handle faults
1d917f8 split gas set into 2 values, and have a fault state
1b77026 j2534 isn't alpha anymore
fbcc872 Merge pull request #92 from commaai/pedal
8a6f44b pedal is sending messages
08f464c python 3 bro is bad bro
9390961 kline checksum algo was broken...
3b7c33b add kline debug support
aa622bc init values
631ea9f better refactor
eb1fd75 add PEDAL adc sets
ccaa310 don't build with usb
8d4d763 debug console works
bd09883 comma pedal is building
75a29d5 Merge pull request #84 from gregjhogan/j2534-hds
eece37d only the panda has gmlan
9f43abe Merge pull request #89 from vntarasov/volt
5364d43 Merge pull request #88 from vntarasov/smaller-firmware
377a1ec bump version for descriptor fix
4fabdf0 Merge pull request #87 from gregjhogan/usb-multi-packet-control
8580773 fix sending WinUSB Extended Properties Feature Descriptor
6908feb Chevy Volt safety
786a004 Enable optimization to reduce firmware size
d70f43b hack to fix thinkpad
95ab1ae fixed flow control message padding
bbd04d1 updated installer
62216d0 single standalone DLL for J2534 driver
5c9138d fixed 11 bit address issue
f3b0ad2 fix LOOPBACK getting set when DATA_RATE is set
b750d36 updated README
a9a097f lowered CPU utilization
7c26a70 TIS needs unsupported protocols to return an error
42692b4 TIS doesn't like ChannelID being zero
cf126bb SET_CONFIG return error for reserved parameters
2e99dbf fix HDS issues
8203cc8 add is_grey
e946a54 add insecure_okay flag
4363b3e check webpage
4f59ded add secure mode note
6b11fb5 add autosecuring to tests
b27d185 Merge pull request #86 from commaai/better_pairing
4b53b42 elm wifi isn't an automated test
99f85cb Merge pull request #85 from gregjhogan/usb-wcid
0d38060 auto-install WinUSB device driver
c6653ca from python import
38cc0ee add wifi_secure_mode, boots in insecure mode

git-subtree-dir: panda
git-subtree-split: 67d52089a1300b86800d897f2b271e0a24cf6dd6

* Squashed 'opendbc/' changes from 81d9871..aa067f7

aa067f7 Chevy Volt tweaks (#83)
a60c6c4 Toyota: change signal name in EPS_STATUS msg
ce70b1a extra setme field toyota LKAS_HUD
df2a552 toyota missing ACC_CONTROL checksum
48bb293 Revert "Toyota Prius: added a comma specific message to control the speed sent to the EPS"
5f42439 Toyota Prius: added a comma specific message to control the speed sent to the EPS
6f5e8b6 Pedal Interceptor: fault state VAL moved to _comma
efd5f5c add setme to honda ACC_HUD
97fc335 add interceptor to civic
6f40f16 update generator script to allow for multiple imports
9ca956b add setme to toyota STEERING_IPAS
e5afa57 run generator for ipas scaling
8bd1182 Toyota IPAS: proper steer angle unit
f57511e acceleration pedal for gasPressed
c8d1dbc high beams also. likely dashboard message.
9f1c78b high beams for genericToggle
f037d42 turn signal lights (and thus hazard lights)
b35bb08 turn signals
78986cf Revert "turn signals"
ba946c9 turn signals
2af3ecc Speed, braking, and distance signals
f40ab87 Set packet lengths, adding steering rate, adjusted speed
cd59bfa units for speed_right
c2fcce2 speed of right vs left side of car
4ef5fae value table for gear status
97c48e2 tighten up speed bits. brake pressue max comment.
a0cbfd1 add gear status PRNDL
0c82865 initial signals for chrysler pacifica 2017 hybrid
5ed0540 add set me to toyota LKAS_HUD
aecac5d add set me fields to toyota ACC_HUD
5417013 update toyota ACC_CONTROL fields
e91e967 Comma Pedal: made GAS_COMMAND 6 bytes
d04434a Comma Pedal: added state byte and enable bit
c30b2cd Comma Pedal: sending 2 tracks on 0x200
8f72467 Volt doors and belts status (#70)
60f8b6c add set me to lkas hud honda
3c9e335 fix honda pcm gas message size
7ca471d Add 2018 Toyota CHR dbc (#78)
637fe00 set scaling to 1 for brake and gas which have no real unit
62a88d4 Volt: switch to parsing ACC buttons from powertrain CAN (#74)
3fdd47b Volt's gas pedal only and combined gas/acc (#76)
45ec9c9 Add 2017 Honda Ridgeline (#77)
cbd186a Add 2018 Camry Hybrid DBC's (#73)
974eeaf Toyota: re-generated the files after cfbc9ae363f98ef
19ea195 Toyota: more vals for LKA_STATE
cfbc9ae fixed inconsistent factor for speed in Honda dbc files
e7db803 convert all line endings to unix style

git-subtree-dir: opendbc
git-subtree-split: aa067f7079aa12617f7a37d85233e51af44e1bb2

* openpilot v0.4.3 release

* Squashed 'panda/' changes from 67d5208..3125232

3125232 bump version
703c0b4 Gas Interceptor: another fix to gas pressed logic
196d383 Interceptor: fixed gas pressed logic

git-subtree-dir: panda
git-subtree-split: 31252324d98e701c33cb6aeda20af6b549175764

* Squashed 'opendbc/' changes from aa067f7..91e882d

91e882d Updating bosch dbcs to use new format and bringing in new honda changes (#82)
9b32e2e Fix Checksum errors for CH-R (#86)

git-subtree-dir: opendbc
git-subtree-split: 91e882d4a04c129e12d39bcff0bbe56b75166e0f

* openpilot v0.4.3 release

* openpilot v0.4.3.1 release

* fix bug in canpacker for Toyotas with DSU connected (#221)

* update year on civic
2018-03-22 22:11:57 -07:00

695 lines
20 KiB
Python
Executable File

#!/usr/bin/env python2.7
import os
import sys
import fcntl
import errno
import signal
if __name__ == "__main__":
if os.path.isfile("/init.qcom.rc") \
and (not os.path.isfile("/VERSION") or int(open("/VERSION").read()) < 4):
raise Exception("NEOS outdated")
# get a non-blocking stdout
child_pid, child_pty = os.forkpty()
if child_pid != 0: # parent
# child is in its own process group, manually pass kill signals
signal.signal(signal.SIGINT, lambda signum, frame: os.kill(child_pid, signal.SIGINT))
signal.signal(signal.SIGTERM, lambda signum, frame: os.kill(child_pid, signal.SIGTERM))
fcntl.fcntl(sys.stdout, fcntl.F_SETFL,
fcntl.fcntl(sys.stdout, fcntl.F_GETFL) | os.O_NONBLOCK)
while True:
try:
dat = os.read(child_pty, 4096)
except OSError as e:
if e.errno == errno.EIO:
break
continue
if not dat:
break
try:
sys.stdout.write(dat)
except (OSError, IOError):
pass
os._exit(os.wait()[1])
import glob
import shutil
import hashlib
import importlib
import subprocess
import traceback
from multiprocessing import Process
from common.basedir import BASEDIR
sys.path.append(os.path.join(BASEDIR, "pyextra"))
os.environ['BASEDIR'] = BASEDIR
import zmq
from setproctitle import setproctitle
from common.params import Params
from common.realtime import sec_since_boot
from selfdrive.services import service_list
from selfdrive.swaglog import cloudlog
import selfdrive.messaging as messaging
from selfdrive.thermal import read_thermal
from selfdrive.registration import register
from selfdrive.version import version, dirty
import selfdrive.crash as crash
from selfdrive.loggerd.config import ROOT
EON = os.path.exists("/EON")
# comment out anything you don't want to run
managed_processes = {
"uploader": "selfdrive.loggerd.uploader",
"controlsd": "selfdrive.controls.controlsd",
"radard": "selfdrive.controls.radard",
"ubloxd": "selfdrive.locationd.ubloxd",
"locationd_dummy": "selfdrive.locationd.locationd_dummy",
"loggerd": ("selfdrive/loggerd", ["./loggerd"]),
"logmessaged": "selfdrive.logmessaged",
"tombstoned": "selfdrive.tombstoned",
"logcatd": ("selfdrive/logcatd", ["./logcatd"]),
"proclogd": ("selfdrive/proclogd", ["./proclogd"]),
"boardd": ("selfdrive/boardd", ["./boardd"]), # not used directly
"pandad": "selfdrive.pandad",
"ui": ("selfdrive/ui", ["./ui"]),
"visiond": ("selfdrive/visiond", ["./visiond"]),
"sensord": ("selfdrive/sensord", ["./sensord"]),
"gpsd": ("selfdrive/sensord", ["./gpsd"]),
"updated": "selfdrive.updated",
#"gpsplanner": "selfdrive.controls.gps_plannerd",
}
running = {}
def get_running():
return running
# due to qualcomm kernel bugs SIGKILLing visiond sometimes causes page table corruption
unkillable_processes = ['visiond']
# processes to end with SIGINT instead of SIGTERM
interrupt_processes = []
persistent_processes = [
'logmessaged',
'logcatd',
'tombstoned',
'uploader',
'ui',
'gpsd',
'ubloxd',
'locationd_dummy',
'updated',
]
car_started_processes = [
'controlsd',
'loggerd',
'sensord',
'radard',
'visiond',
'proclogd',
# 'gpsplanner,
]
def register_managed_process(name, desc, car_started=False):
global managed_processes, car_started_processes, persistent_processes
print "registering", name
managed_processes[name] = desc
if car_started:
car_started_processes.append(name)
else:
persistent_processes.append(name)
# ****************** process management functions ******************
def launcher(proc, gctx):
try:
# import the process
mod = importlib.import_module(proc)
# rename the process
setproctitle(proc)
# exec the process
mod.main(gctx)
except KeyboardInterrupt:
cloudlog.warning("child %s got SIGINT" % proc)
except Exception:
# can't install the crash handler becuase sys.excepthook doesn't play nice
# with threads, so catch it here.
crash.capture_exception()
raise
def nativelauncher(pargs, cwd):
# exec the process
os.chdir(cwd)
# because when extracted from pex zips permissions get lost -_-
os.chmod(pargs[0], 0o700)
os.execvp(pargs[0], pargs)
def start_managed_process(name):
if name in running or name not in managed_processes:
return
proc = managed_processes[name]
if isinstance(proc, basestring):
cloudlog.info("starting python %s" % proc)
running[name] = Process(name=name, target=launcher, args=(proc, gctx))
else:
pdir, pargs = proc
cwd = os.path.join(BASEDIR, pdir)
cloudlog.info("starting process %s" % name)
running[name] = Process(name=name, target=nativelauncher, args=(pargs, cwd))
running[name].start()
def prepare_managed_process(p):
proc = managed_processes[p]
if isinstance(proc, basestring):
# import this python
cloudlog.info("preimporting %s" % proc)
importlib.import_module(proc)
else:
# build this process
cloudlog.info("building %s" % (proc,))
try:
subprocess.check_call(["make", "-j4"], cwd=os.path.join(BASEDIR, proc[0]))
except subprocess.CalledProcessError:
# make clean if the build failed
cloudlog.warning("building %s failed, make clean" % (proc, ))
subprocess.check_call(["make", "clean"], cwd=os.path.join(BASEDIR, proc[0]))
subprocess.check_call(["make", "-j4"], cwd=os.path.join(BASEDIR, proc[0]))
def kill_managed_process(name):
if name not in running or name not in managed_processes:
return
cloudlog.info("killing %s" % name)
if running[name].exitcode is None:
if name in interrupt_processes:
os.kill(running[name].pid, signal.SIGINT)
else:
running[name].terminate()
# give it 5 seconds to die
running[name].join(5.0)
if running[name].exitcode is None:
if name in unkillable_processes:
cloudlog.critical("unkillable process %s failed to exit! rebooting in 15 if it doesn't die" % name)
running[name].join(15.0)
if running[name].exitcode is None:
cloudlog.critical("FORCE REBOOTING PHONE!")
os.system("date >> /sdcard/unkillable_reboot")
os.system("reboot")
raise RuntimeError
else:
cloudlog.info("killing %s with SIGKILL" % name)
os.kill(running[name].pid, signal.SIGKILL)
running[name].join()
cloudlog.info("%s is dead with %d" % (name, running[name].exitcode))
del running[name]
def cleanup_all_processes(signal, frame):
cloudlog.info("caught ctrl-c %s %s" % (signal, frame))
for p in ("com.waze", "com.spotify.music", "ai.comma.plus.offroad", "ai.comma.plus.frame"):
system("am force-stop %s" % p)
for name in running.keys():
kill_managed_process(name)
cloudlog.info("everything is dead")
# ****************** run loop ******************
def manager_init(should_register=True):
global gctx
if should_register:
reg_res = register()
if reg_res:
dongle_id, dongle_secret = reg_res
else:
raise Exception("server registration failed")
else:
dongle_id = "c"*16
# set dongle id
cloudlog.info("dongle id is " + dongle_id)
os.environ['DONGLE_ID'] = dongle_id
cloudlog.info("dirty is %d" % dirty)
if not dirty:
os.environ['CLEAN'] = '1'
cloudlog.bind_global(dongle_id=dongle_id, version=version, dirty=dirty, is_eon=EON)
crash.bind_user(id=dongle_id)
crash.bind_extra(version=version, dirty=dirty, is_eon=EON)
os.umask(0)
try:
os.mkdir(ROOT, 0777)
except OSError:
pass
# set gctx
gctx = {}
def system(cmd):
try:
cloudlog.info("running %s" % cmd)
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError, e:
cloudlog.event("running failed",
cmd=e.cmd,
output=e.output[-1024:],
returncode=e.returncode)
def setup_eon_fan():
if not EON:
return
os.system("echo 2 > /sys/module/dwc3_msm/parameters/otg_switch")
from smbus2 import SMBus
bus = SMBus(7, force=True)
bus.write_byte_data(0x21, 0x10, 0xf) # mask all interrupts
bus.write_byte_data(0x21, 0x03, 0x1) # set drive current and global interrupt disable
bus.write_byte_data(0x21, 0x02, 0x2) # needed?
bus.write_byte_data(0x21, 0x04, 0x4) # manual override source
bus.close()
last_eon_fan_val = None
def set_eon_fan(val):
global last_eon_fan_val
if not EON:
return
from smbus2 import SMBus
if last_eon_fan_val is None or last_eon_fan_val != val:
bus = SMBus(7, force=True)
bus.write_byte_data(0x21, 0x04, 0x2)
bus.write_byte_data(0x21, 0x03, (val*2)+1)
bus.write_byte_data(0x21, 0x04, 0x4)
bus.close()
last_eon_fan_val = val
# temp thresholds to control fan speed - high hysteresis
_TEMP_THRS_H = [50., 65., 80., 10000]
# temp thresholds to control fan speed - low hysteresis
_TEMP_THRS_L = [42.5, 57.5, 72.5, 10000]
# fan speed options
_FAN_SPEEDS = [0, 16384, 32768, 65535]
# max fan speed only allowed if battery if hot
_BAT_TEMP_THERSHOLD = 45.
def handle_fan(max_temp, bat_temp, fan_speed):
new_speed_h = next(speed for speed, temp_h in zip(_FAN_SPEEDS, _TEMP_THRS_H) if temp_h > max_temp)
new_speed_l = next(speed for speed, temp_l in zip(_FAN_SPEEDS, _TEMP_THRS_L) if temp_l > max_temp)
if new_speed_h > fan_speed:
# update speed if using the high thresholds results in fan speed increment
fan_speed = new_speed_h
elif new_speed_l < fan_speed:
# update speed if using the low thresholds results in fan speed decrement
fan_speed = new_speed_l
if bat_temp < _BAT_TEMP_THERSHOLD:
# no max fan speed unless battery is hot
fan_speed = min(fan_speed, _FAN_SPEEDS[-2])
set_eon_fan(fan_speed/16384)
return fan_speed
class LocationStarter(object):
def __init__(self):
self.last_good_loc = 0
def update(self, started_ts, location):
rt = sec_since_boot()
if location is None or location.accuracy > 50 or location.speed < 2:
# bad location, stop if we havent gotten a location in a while
# dont stop if we're been going for less than a minute
if started_ts:
if rt-self.last_good_loc > 60. and rt-started_ts > 60:
cloudlog.event("location_stop",
ts=rt,
started_ts=started_ts,
last_good_loc=self.last_good_loc,
location=location.to_dict() if location else None)
return False
else:
return True
else:
return False
self.last_good_loc = rt
if started_ts:
return True
else:
cloudlog.event("location_start", location=location.to_dict() if location else None)
return location.speed*3.6 > 10
def manager_thread():
# now loop
context = zmq.Context()
thermal_sock = messaging.pub_sock(context, service_list['thermal'].port)
health_sock = messaging.sub_sock(context, service_list['health'].port)
location_sock = messaging.sub_sock(context, service_list['gpsLocation'].port)
cloudlog.info("manager start")
cloudlog.info({"environ": os.environ})
for p in persistent_processes:
start_managed_process(p)
# start frame
system("am start -n ai.comma.plus.frame/.MainActivity")
# do this before panda flashing
setup_eon_fan()
if os.getenv("NOBOARD") is None:
start_managed_process("pandad")
params = Params()
passive_starter = LocationStarter()
started_ts = None
logger_dead = False
count = 0
fan_speed = 0
ignition_seen = False
battery_was_high = False
panda_seen = False
health_sock.RCVTIMEO = 1500
while 1:
# get health of board, log this in "thermal"
td = messaging.recv_sock(health_sock, wait=True)
location = messaging.recv_sock(location_sock)
location = location.gpsLocation if location else None
print td
# replace thermald
msg = read_thermal()
# loggerd is gated based on free space
statvfs = os.statvfs(ROOT)
avail = (statvfs.f_bavail * 1.0)/statvfs.f_blocks
# thermal message now also includes free space
msg.thermal.freeSpace = avail
with open("/sys/class/power_supply/battery/capacity") as f:
msg.thermal.batteryPercent = int(f.read())
with open("/sys/class/power_supply/battery/status") as f:
msg.thermal.batteryStatus = f.read().strip()
with open("/sys/class/power_supply/usb/online") as f:
msg.thermal.usbOnline = bool(int(f.read()))
# TODO: add car battery voltage check
max_temp = max(msg.thermal.cpu0, msg.thermal.cpu1,
msg.thermal.cpu2, msg.thermal.cpu3) / 10.0
bat_temp = msg.thermal.bat/1000.
fan_speed = handle_fan(max_temp, bat_temp, fan_speed)
msg.thermal.fanSpeed = fan_speed
msg.thermal.started = started_ts is not None
msg.thermal.startedTs = int(1e9*(started_ts or 0))
thermal_sock.send(msg.to_bytes())
print msg
# uploader is gated based on the phone temperature
if max_temp > 85.0:
cloudlog.warning("over temp: %r", max_temp)
kill_managed_process("uploader")
elif max_temp < 70.0:
start_managed_process("uploader")
if avail < 0.05:
logger_dead = True
# start constellation of processes when the car starts
ignition = td is not None and td.health.started
ignition_seen = ignition_seen or ignition
# add voltage check for ignition
if not ignition_seen and td is not None and td.health.voltage > 13500:
ignition = True
do_uninstall = params.get("DoUninstall") == "1"
accepted_terms = params.get("HasAcceptedTerms") == "1"
should_start = ignition
# have we seen a panda?
panda_seen = panda_seen or td is not None
# start on gps movement if we haven't seen ignition and are in passive mode
should_start = should_start or (not (ignition_seen and td) # seen ignition and panda is connected
and params.get("Passive") == "1"
and passive_starter.update(started_ts, location))
# with 2% left, we killall, otherwise the phone will take a long time to boot
should_start = should_start and avail > 0.02
# require usb power
should_start = should_start and msg.thermal.usbOnline
should_start = should_start and accepted_terms and (not do_uninstall)
# if any CPU gets above 107 or the battery gets above 63, kill all processes
# controls will warn with CPU above 95 or battery above 60
if max_temp > 107.0 or msg.thermal.bat >= 63000:
# TODO: Add a better warning when this is happening
should_start = False
if should_start:
if not started_ts:
params.car_start()
started_ts = sec_since_boot()
for p in car_started_processes:
if p == "loggerd" and logger_dead:
kill_managed_process(p)
else:
start_managed_process(p)
else:
started_ts = None
logger_dead = False
for p in car_started_processes:
kill_managed_process(p)
# shutdown if the battery gets lower than 5%, we aren't running, and we are discharging
if msg.thermal.batteryPercent < 5 and msg.thermal.batteryStatus == "Discharging" and battery_was_high:
os.system('LD_LIBRARY_PATH="" svc power shutdown')
if msg.thermal.batteryPercent > 10:
battery_was_high = True
# check the status of all processes, did any of them die?
for p in running:
cloudlog.debug(" running %s %s" % (p, running[p]))
# report to server once per minute
if (count%60) == 0:
cloudlog.event("STATUS_PACKET",
running=running.keys(),
count=count,
health=(td.to_dict() if td else None),
location=(location.to_dict() if location else None),
thermal=msg.to_dict())
if do_uninstall:
break
count += 1
def get_installed_apks():
dat = subprocess.check_output(["pm", "list", "packages", "-f"]).strip().split("\n")
ret = {}
for x in dat:
if x.startswith("package:"):
v,k = x.split("package:")[1].split("=")
ret[k] = v
return ret
def install_apk(path):
# can only install from world readable path
install_path = "/sdcard/%s" % os.path.basename(path)
shutil.copyfile(path, install_path)
ret = subprocess.call(["pm", "install", "-r", install_path])
os.remove(install_path)
return ret == 0
def update_apks():
# patch apks
if os.getenv("PREPAREONLY"):
# assume we have internet, download too
patched = subprocess.call([os.path.join(BASEDIR, "apk/external/patcher.py")])
else:
patched = subprocess.call([os.path.join(BASEDIR, "apk/external/patcher.py"), "patch"])
cloudlog.info("patcher: %r" % (patched,))
# install apks
installed = get_installed_apks()
install_apks = (glob.glob(os.path.join(BASEDIR, "apk/*.apk"))
+ glob.glob(os.path.join(BASEDIR, "apk/external/out/*.apk")))
for apk in install_apks:
app = os.path.basename(apk)[:-4]
if app not in installed:
installed[app] = None
cloudlog.info("installed apks %s" % (str(installed), ))
for app in installed.iterkeys():
apk_path = os.path.join(BASEDIR, "apk/"+app+".apk")
if not os.path.exists(apk_path):
apk_path = os.path.join(BASEDIR, "apk/external/out/"+app+".apk")
if not os.path.exists(apk_path):
continue
h1 = hashlib.sha1(open(apk_path).read()).hexdigest()
h2 = None
if installed[app] is not None:
h2 = hashlib.sha1(open(installed[app]).read()).hexdigest()
cloudlog.info("comparing version of %s %s vs %s" % (app, h1, h2))
if h2 is None or h1 != h2:
cloudlog.info("installing %s" % app)
success = install_apk(apk_path)
if not success:
cloudlog.info("needing to uninstall %s" % app)
system("pm uninstall %s" % app)
success = install_apk(apk_path)
assert success
def manager_update():
update_apks()
def manager_prepare():
# build cereal first
subprocess.check_call(["make", "-j4"], cwd=os.path.join(BASEDIR, "cereal"))
# build all processes
os.chdir(os.path.dirname(os.path.abspath(__file__)))
for p in managed_processes:
prepare_managed_process(p)
def uninstall():
cloudlog.warning("uninstalling")
with open('/cache/recovery/command', 'w') as f:
f.write('--wipe_data\n')
# IPowerManager.reboot(confirm=false, reason="recovery", wait=true)
os.system("service call power 16 i32 0 s16 recovery i32 1")
def main():
if os.getenv("NOLOG") is not None:
del managed_processes['loggerd']
del managed_processes['tombstoned']
if os.getenv("NOUPLOAD") is not None:
del managed_processes['uploader']
if os.getenv("NOVISION") is not None:
del managed_processes['visiond']
if os.getenv("LEAN") is not None:
del managed_processes['uploader']
del managed_processes['loggerd']
del managed_processes['logmessaged']
del managed_processes['logcatd']
del managed_processes['tombstoned']
del managed_processes['proclogd']
if os.getenv("NOCONTROL") is not None:
del managed_processes['controlsd']
del managed_processes['radard']
# support additional internal only extensions
try:
import selfdrive.manager_extensions
selfdrive.manager_extensions.register(register_managed_process)
except ImportError:
pass
params = Params()
params.manager_start()
# set unset params
if params.get("IsMetric") is None:
params.put("IsMetric", "0")
if params.get("IsRearViewMirror") is None:
params.put("IsRearViewMirror", "0")
if params.get("IsFcwEnabled") is None:
params.put("IsFcwEnabled", "1")
if params.get("HasAcceptedTerms") is None:
params.put("HasAcceptedTerms", "0")
if params.get("IsUploadVideoOverCellularEnabled") is None:
params.put("IsUploadVideoOverCellularEnabled", "1")
# is this chffrplus?
if os.getenv("PASSIVE") is not None:
params.put("Passive", str(int(os.getenv("PASSIVE"))))
if params.get("Passive") is None:
raise Exception("Passive must be set to continue")
# put something on screen while we set things up
if os.getenv("PREPAREONLY") is not None:
spinner_proc = None
else:
spinner_proc = subprocess.Popen(["./spinner", "loading..."],
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"),
close_fds=True)
try:
manager_update()
manager_init()
manager_prepare()
finally:
if spinner_proc:
spinner_proc.terminate()
if os.getenv("PREPAREONLY") is not None:
return
# SystemExit on sigterm
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(1))
try:
manager_thread()
except Exception:
traceback.print_exc()
crash.capture_exception()
finally:
cleanup_all_processes(None, None)
if params.get("DoUninstall") == "1":
uninstall()
if __name__ == "__main__":
main()
# manual exit because we are forked
sys.exit(0)