Alerts + Events refactor (#1466)
parent
44560b5bb7
commit
d976233f69
24 changed files with 987 additions and 1171 deletions
@ -1 +1 @@ |
||||
Subproject commit 4f68db8f6aa31e87d968da882460e196c6b101a3 |
||||
Subproject commit 856c9812d552fe0ac640b75074b080f76c9a3cba |
@ -1,825 +0,0 @@ |
||||
from cereal import car, log |
||||
|
||||
# Priority |
||||
class Priority: |
||||
LOWEST = 0 |
||||
LOWER = 1 |
||||
LOW = 2 |
||||
MID = 3 |
||||
HIGH = 4 |
||||
HIGHEST = 5 |
||||
|
||||
AlertSize = log.ControlsState.AlertSize |
||||
AlertStatus = log.ControlsState.AlertStatus |
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert |
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert |
||||
|
||||
class Alert(): |
||||
def __init__(self, |
||||
alert_type, |
||||
alert_text_1, |
||||
alert_text_2, |
||||
alert_status, |
||||
alert_size, |
||||
alert_priority, |
||||
visual_alert, |
||||
audible_alert, |
||||
duration_sound, |
||||
duration_hud_alert, |
||||
duration_text, |
||||
alert_rate=0.): |
||||
|
||||
self.alert_type = alert_type |
||||
self.alert_text_1 = alert_text_1 |
||||
self.alert_text_2 = alert_text_2 |
||||
self.alert_status = alert_status |
||||
self.alert_size = alert_size |
||||
self.alert_priority = alert_priority |
||||
self.visual_alert = visual_alert |
||||
self.audible_alert = audible_alert |
||||
|
||||
self.duration_sound = duration_sound |
||||
self.duration_hud_alert = duration_hud_alert |
||||
self.duration_text = duration_text |
||||
|
||||
self.start_time = 0. |
||||
self.alert_rate = alert_rate |
||||
|
||||
# typecheck that enums are valid on startup |
||||
tst = car.CarControl.new_message() |
||||
tst.hudControl.visualAlert = self.visual_alert |
||||
|
||||
def __str__(self): |
||||
return self.alert_text_1 + "/" + self.alert_text_2 + " " + str(self.alert_priority) + " " + str( |
||||
self.visual_alert) + " " + str(self.audible_alert) |
||||
|
||||
def __gt__(self, alert2): |
||||
return self.alert_priority > alert2.alert_priority |
||||
|
||||
|
||||
ALERTS = [ |
||||
# Miscellaneous alerts |
||||
Alert( |
||||
"enable", |
||||
"", |
||||
"", |
||||
AlertStatus.normal, AlertSize.none, |
||||
Priority.MID, VisualAlert.none, AudibleAlert.chimeEngage, .2, 0., 0.), |
||||
|
||||
Alert( |
||||
"disable", |
||||
"", |
||||
"", |
||||
AlertStatus.normal, AlertSize.none, |
||||
Priority.MID, VisualAlert.none, AudibleAlert.chimeDisengage, .2, 0., 0.), |
||||
|
||||
Alert( |
||||
"fcw", |
||||
"BRAKE!", |
||||
"Risk of Collision", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeat, 1., 2., 2.), |
||||
|
||||
Alert( |
||||
"fcwStock", |
||||
"BRAKE!", |
||||
"Risk of Collision", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), # no EON chime for stock FCW |
||||
|
||||
Alert( |
||||
"steerSaturated", |
||||
"TAKE CONTROL", |
||||
"Turn Exceeds Steering Limit", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), |
||||
|
||||
Alert( |
||||
"steerTempUnavailable", |
||||
"TAKE CONTROL", |
||||
"Steering Temporarily Unavailable", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"steerTempUnavailableMute", |
||||
"TAKE CONTROL", |
||||
"Steering Temporarily Unavailable", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2, .2, .2), |
||||
|
||||
Alert( |
||||
"preDriverDistracted", |
||||
"KEEP EYES ON ROAD: Driver Distracted", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
|
||||
Alert( |
||||
"promptDriverDistracted", |
||||
"KEEP EYES ON ROAD", |
||||
"Driver Appears Distracted", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), |
||||
|
||||
Alert( |
||||
"driverDistracted", |
||||
"DISENGAGE IMMEDIATELY", |
||||
"Driver Was Distracted", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), |
||||
|
||||
Alert( |
||||
"preDriverUnresponsive", |
||||
"TOUCH STEERING WHEEL: No Face Detected", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
|
||||
Alert( |
||||
"promptDriverUnresponsive", |
||||
"TOUCH STEERING WHEEL", |
||||
"Driver Is Unresponsive", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), |
||||
|
||||
Alert( |
||||
"driverUnresponsive", |
||||
"DISENGAGE IMMEDIATELY", |
||||
"Driver Was Unresponsive", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), |
||||
|
||||
Alert( |
||||
"driverMonitorLowAcc", |
||||
"CHECK DRIVER FACE VISIBILITY", |
||||
"Driver Monitor Model Output Uncertain", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.), |
||||
|
||||
Alert( |
||||
"geofence", |
||||
"DISENGAGEMENT REQUIRED", |
||||
"Not in Geofenced Area", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), |
||||
|
||||
Alert( |
||||
"startup", |
||||
"Be ready to take over at any time", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
|
||||
Alert( |
||||
"startupMaster", |
||||
"WARNING: This branch is not tested", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
|
||||
Alert( |
||||
"startupNoControl", |
||||
"Dashcam mode", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
|
||||
Alert( |
||||
"startupNoCar", |
||||
"Dashcam mode for unsupported car", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
|
||||
Alert( |
||||
"ethicalDilemma", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Ethical Dilemma Detected", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 1., 3., 3.), |
||||
|
||||
Alert( |
||||
"steerTempUnavailableNoEntry", |
||||
"openpilot Unavailable", |
||||
"Steering Temporarily Unavailable", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.), |
||||
|
||||
Alert( |
||||
"manualRestart", |
||||
"TAKE CONTROL", |
||||
"Resume Driving Manually", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"resumeRequired", |
||||
"STOPPED", |
||||
"Press Resume to Move", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"belowSteerSpeed", |
||||
"TAKE CONTROL", |
||||
"Steer Unavailable Below ", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3), |
||||
|
||||
Alert( |
||||
"debugAlert", |
||||
"DEBUG ALERT", |
||||
"", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, .1, .1), |
||||
Alert( |
||||
"preLaneChangeLeft", |
||||
"Steer Left to Start Lane Change", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
|
||||
Alert( |
||||
"preLaneChangeRight", |
||||
"Steer Right to Start Lane Change", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
|
||||
Alert( |
||||
"laneChange", |
||||
"Changing Lane", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1), |
||||
|
||||
Alert( |
||||
"posenetInvalid", |
||||
"TAKE CONTROL", |
||||
"Vision Model Output Uncertain", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), |
||||
|
||||
# Non-entry only alerts |
||||
Alert( |
||||
"wrongCarModeNoEntry", |
||||
"openpilot Unavailable", |
||||
"Main Switch Off", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.), |
||||
|
||||
Alert( |
||||
"dataNeededNoEntry", |
||||
"openpilot Unavailable", |
||||
"Calibration Needs Data. Upload Drive, Try Again", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.), |
||||
|
||||
Alert( |
||||
"outOfSpaceNoEntry", |
||||
"openpilot Unavailable", |
||||
"Out of Storage Space", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 0., 3.), |
||||
|
||||
Alert( |
||||
"pedalPressedNoEntry", |
||||
"openpilot Unavailable", |
||||
"Pedal Pressed During Attempt", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, "brakePressed", AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"speedTooLowNoEntry", |
||||
"openpilot Unavailable", |
||||
"Speed Too Low", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"brakeHoldNoEntry", |
||||
"openpilot Unavailable", |
||||
"Brake Hold Active", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"parkBrakeNoEntry", |
||||
"openpilot Unavailable", |
||||
"Park Brake Engaged", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"lowSpeedLockoutNoEntry", |
||||
"openpilot Unavailable", |
||||
"Cruise Fault: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"lowBatteryNoEntry", |
||||
"openpilot Unavailable", |
||||
"Low Battery", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"sensorDataInvalidNoEntry", |
||||
"openpilot Unavailable", |
||||
"No Data from Device Sensors", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"soundsUnavailableNoEntry", |
||||
"openpilot Unavailable", |
||||
"Speaker not found", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"tooDistractedNoEntry", |
||||
"openpilot Unavailable", |
||||
"Distraction Level Too High", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
# Cancellation alerts causing soft disabling |
||||
Alert( |
||||
"overheat", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"System Overheated", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"wrongGear", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Gear not D", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"calibrationInvalid", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Calibration Invalid: Reposition Device and Recalibrate", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"calibrationIncomplete", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Calibration in Progress", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"doorOpen", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Door Open", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"seatbeltNotLatched", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Seatbelt Unlatched", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"espDisabled", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"ESP Off", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"lowBattery", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Low Battery", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"commIssue", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Communication Issue between Processes", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"radarCommIssue", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Radar Communication Issue", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"radarCanError", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Radar Error: Restart the Car", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
Alert( |
||||
"radarFault", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Radar Error: Restart the Car", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
|
||||
Alert( |
||||
"lowMemory", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Low Memory: Reboot Your Device", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
# Cancellation alerts causing immediate disabling |
||||
Alert( |
||||
"controlsFailed", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Controls Failed", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"controlsMismatch", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Controls Mismatch", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"canError", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"CAN Error: Check Connections", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"steerUnavailable", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"LKAS Fault: Restart the Car", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"brakeUnavailable", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Cruise Fault: Restart the Car", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"gasUnavailable", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Gas Fault: Restart the Car", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"reverseGear", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Reverse Gear", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"cruiseDisabled", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Cruise Is Off", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"plannerError", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Planner Solution Error", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"relayMalfunction", |
||||
"TAKE CONTROL IMMEDIATELY", |
||||
"Harness Malfunction", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
Alert( |
||||
"speedTooHigh", |
||||
"Speed Too High", |
||||
"Slow down to resume operation", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, 2.2, 3., 4.), |
||||
|
||||
|
||||
# not loud cancellations (user is in control) |
||||
Alert( |
||||
"noTarget", |
||||
"openpilot Canceled", |
||||
"No close lead car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"speedTooLow", |
||||
"openpilot Canceled", |
||||
"Speed too low", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
|
||||
# Cancellation alerts causing non-entry |
||||
Alert( |
||||
"overheatNoEntry", |
||||
"openpilot Unavailable", |
||||
"System overheated", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"wrongGearNoEntry", |
||||
"openpilot Unavailable", |
||||
"Gear not D", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"calibrationInvalidNoEntry", |
||||
"openpilot Unavailable", |
||||
"Calibration Invalid: Reposition Device & Recalibrate", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"calibrationIncompleteNoEntry", |
||||
"openpilot Unavailable", |
||||
"Calibration in Progress", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"doorOpenNoEntry", |
||||
"openpilot Unavailable", |
||||
"Door open", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"seatbeltNotLatchedNoEntry", |
||||
"openpilot Unavailable", |
||||
"Seatbelt unlatched", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"espDisabledNoEntry", |
||||
"openpilot Unavailable", |
||||
"ESP Off", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"geofenceNoEntry", |
||||
"openpilot Unavailable", |
||||
"Not in Geofenced Area", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.MID, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"radarCanErrorNoEntry", |
||||
"openpilot Unavailable", |
||||
"Radar Error: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"radarFaultNoEntry", |
||||
"openpilot Unavailable", |
||||
"Radar Error: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"posenetInvalidNoEntry", |
||||
"openpilot Unavailable", |
||||
"Vision Model Output Uncertain", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"controlsFailedNoEntry", |
||||
"openpilot Unavailable", |
||||
"Controls Failed", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"canErrorNoEntry", |
||||
"openpilot Unavailable", |
||||
"CAN Error: Check Connections", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"steerUnavailableNoEntry", |
||||
"openpilot Unavailable", |
||||
"LKAS Fault: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"brakeUnavailableNoEntry", |
||||
"openpilot Unavailable", |
||||
"Cruise Fault: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"gasUnavailableNoEntry", |
||||
"openpilot Unavailable", |
||||
"Gas Error: Restart the Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"reverseGearNoEntry", |
||||
"openpilot Unavailable", |
||||
"Reverse Gear", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"cruiseDisabledNoEntry", |
||||
"openpilot Unavailable", |
||||
"Cruise is Off", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"noTargetNoEntry", |
||||
"openpilot Unavailable", |
||||
"No Close Lead Car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"plannerErrorNoEntry", |
||||
"openpilot Unavailable", |
||||
"Planner Solution Error", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"commIssueNoEntry", |
||||
"openpilot Unavailable", |
||||
"Communication Issue between Processes", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"radarCommIssueNoEntry", |
||||
"openpilot Unavailable", |
||||
"Radar Communication Issue", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"internetConnectivityNeededNoEntry", |
||||
"openpilot Unavailable", |
||||
"Please Connect to Internet", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"lowMemoryNoEntry", |
||||
"openpilot Unavailable", |
||||
"Low Memory: Reboot Your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"speedTooHighNoEntry", |
||||
"Speed Too High", |
||||
"Slow down to engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
Alert( |
||||
"relayMalfunctionNoEntry", |
||||
"openpilot Unavailable", |
||||
"Harness Malfunction", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
|
||||
# permanent alerts |
||||
Alert( |
||||
"steerUnavailablePermanent", |
||||
"LKAS Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"brakeUnavailablePermanent", |
||||
"Cruise Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"lowSpeedLockoutPermanent", |
||||
"Cruise Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"calibrationIncompletePermanent", |
||||
"Calibration in Progress: ", |
||||
"Drive Above ", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"invalidGiraffeToyotaPermanent", |
||||
"Unsupported Giraffe Configuration", |
||||
"Visit comma.ai/tg", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"invalidLkasSettingPermanent", |
||||
"Stock LKAS is turned on", |
||||
"Turn off stock LKAS to engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"internetConnectivityNeededPermanent", |
||||
"Please connect to Internet", |
||||
"An Update Check Is Required to Engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"communityFeatureDisallowedPermanent", |
||||
"Community Feature Detected", |
||||
"Enable Community Features in Developer Settings", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), # LOW priority to overcome Cruise Error |
||||
|
||||
Alert( |
||||
"sensorDataInvalidPermanent", |
||||
"No Data from Device Sensors", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"soundsUnavailablePermanent", |
||||
"Speaker not found", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"lowMemoryPermanent", |
||||
"RAM Critically Low", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"carUnrecognizedPermanent", |
||||
"Dashcam Mode", |
||||
"Car Unrecognized", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"relayMalfunctionPermanent", |
||||
"Harness Malfunction", |
||||
"Please Check Hardware", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
Alert( |
||||
"vehicleModelInvalid", |
||||
"Vehicle Parameter Identification Failed", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWEST, VisualAlert.steerRequired, AudibleAlert.none, .0, .0, .1), |
||||
|
||||
Alert( |
||||
"ldwPermanent", |
||||
"TAKE CONTROL", |
||||
"Lane Departure Detected", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), |
||||
] |
@ -0,0 +1,694 @@ |
||||
from cereal import log, car |
||||
|
||||
from selfdrive.config import Conversions as CV |
||||
|
||||
from selfdrive.locationd.calibration_helpers import Filter |
||||
|
||||
AlertSize = log.ControlsState.AlertSize |
||||
AlertStatus = log.ControlsState.AlertStatus |
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert |
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert |
||||
EventName = car.CarEvent.EventName |
||||
|
||||
# Alert priorities |
||||
class Priority: |
||||
LOWEST = 0 |
||||
LOWER = 1 |
||||
LOW = 2 |
||||
MID = 3 |
||||
HIGH = 4 |
||||
HIGHEST = 5 |
||||
|
||||
# Event types |
||||
class ET: |
||||
ENABLE = 'enable' |
||||
PRE_ENABLE = 'preEnable' |
||||
NO_ENTRY = 'noEntry' |
||||
WARNING = 'warning' |
||||
USER_DISABLE = 'userDisable' |
||||
SOFT_DISABLE = 'softDisable' |
||||
IMMEDIATE_DISABLE = 'immediateDisable' |
||||
PERMANENT = 'permanent' |
||||
|
||||
# get event name from enum |
||||
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()} |
||||
|
||||
class Events: |
||||
def __init__(self): |
||||
self.events = [] |
||||
self.static_events = [] |
||||
|
||||
@property |
||||
def names(self): |
||||
return self.events |
||||
|
||||
def __len__(self): |
||||
return len(self.events) |
||||
|
||||
def add(self, event_name, static=False): |
||||
if static: |
||||
self.static_events.append(event_name) |
||||
self.events.append(event_name) |
||||
|
||||
def clear(self): |
||||
self.events = self.static_events.copy() |
||||
|
||||
def any(self, event_type): |
||||
for e in self.events: |
||||
if event_type in EVENTS.get(e, {}).keys(): |
||||
return True |
||||
return False |
||||
|
||||
def create_alerts(self, event_types, callback_args=[]): |
||||
ret = [] |
||||
for e in self.events: |
||||
types = EVENTS[e].keys() |
||||
for et in event_types: |
||||
if et in types: |
||||
alert = EVENTS[e][et] |
||||
if not isinstance(alert, Alert): |
||||
alert = alert(*callback_args) |
||||
alert.alert_type = EVENT_NAME[e] |
||||
ret.append(alert) |
||||
return ret |
||||
|
||||
def add_from_msg(self, events): |
||||
for e in events: |
||||
self.events.append(e.name.raw) |
||||
|
||||
def to_msg(self): |
||||
ret = [] |
||||
for event_name in self.events: |
||||
event = car.CarEvent.new_message() |
||||
event.name = event_name |
||||
for event_type in EVENTS.get(event_name, {}).keys(): |
||||
setattr(event, event_type , True) |
||||
ret.append(event) |
||||
return ret |
||||
|
||||
class Alert: |
||||
def __init__(self, |
||||
alert_text_1, |
||||
alert_text_2, |
||||
alert_status, |
||||
alert_size, |
||||
alert_priority, |
||||
visual_alert, |
||||
audible_alert, |
||||
duration_sound, |
||||
duration_hud_alert, |
||||
duration_text, |
||||
alert_rate=0.): |
||||
|
||||
self.alert_type = "" |
||||
self.alert_text_1 = alert_text_1 |
||||
self.alert_text_2 = alert_text_2 |
||||
self.alert_status = alert_status |
||||
self.alert_size = alert_size |
||||
self.alert_priority = alert_priority |
||||
self.visual_alert = visual_alert |
||||
self.audible_alert = audible_alert |
||||
|
||||
self.duration_sound = duration_sound |
||||
self.duration_hud_alert = duration_hud_alert |
||||
self.duration_text = duration_text |
||||
|
||||
self.start_time = 0. |
||||
self.alert_rate = alert_rate |
||||
|
||||
# typecheck that enums are valid on startup |
||||
tst = car.CarControl.new_message() |
||||
tst.hudControl.visualAlert = self.visual_alert |
||||
|
||||
def __str__(self): |
||||
return self.alert_text_1 + "/" + self.alert_text_2 + " " + str(self.alert_priority) + " " + str( |
||||
self.visual_alert) + " " + str(self.audible_alert) |
||||
|
||||
def __gt__(self, alert2): |
||||
return self.alert_priority > alert2.alert_priority |
||||
|
||||
class NoEntryAlert(Alert): |
||||
def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError, |
||||
visual_alert=VisualAlert.none, duration_hud_alert=2.): |
||||
super().__init__("openpilot Unavailable", alert_text_2, AlertStatus.normal, |
||||
AlertSize.mid, Priority.LOW, visual_alert, |
||||
audible_alert, .4, duration_hud_alert, 3.) |
||||
|
||||
|
||||
class SoftDisableAlert(Alert): |
||||
def __init__(self, alert_text_2): |
||||
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2, |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.MID, VisualAlert.steerRequired, |
||||
AudibleAlert.chimeWarningRepeat, .1, 2., 2.), |
||||
|
||||
|
||||
class ImmediateDisableAlert(Alert): |
||||
def __init__(self, alert_text_2, alert_text_1="TAKE CONTROL IMMEDIATELY"): |
||||
super().__init__(alert_text_1, alert_text_2, |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.steerRequired, |
||||
AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.), |
||||
|
||||
class EngagementAlert(Alert): |
||||
def __init__(self, audible_alert=True): |
||||
super().__init__("", "", |
||||
AlertStatus.normal, AlertSize.none, |
||||
Priority.MID, VisualAlert.none, |
||||
audible_alert, .2, 0., 0.), |
||||
|
||||
def below_steer_speed_alert(CP, sm, metric): |
||||
speed = CP.minSteerSpeed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH) |
||||
unit = "kph" if metric else "mph" |
||||
return Alert( |
||||
"TAKE CONTROL", |
||||
"Steer Unavailable Below %d %s" % (speed, unit), |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3), |
||||
|
||||
def calibration_incomplete_alert(CP, sm, metric): |
||||
speed = int(Filter.MIN_SPEED * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)) |
||||
unit = "kph" if metric else "mph" |
||||
return Alert( |
||||
"Calibration in Progress: %d" % sm['liveCalibration'].calPerc, |
||||
"Drive Above %d %s" % (speed, unit), |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
|
||||
EVENTS = { |
||||
# ********** events with no alerts ********** |
||||
|
||||
EventName.gasPressed: {ET.PRE_ENABLE: None}, |
||||
|
||||
# ********** events only containing alerts displayed in all states ********** |
||||
|
||||
EventName.debugAlert: { |
||||
ET.PERMANENT: Alert( |
||||
"DEBUG ALERT", |
||||
"", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .1, .1, .1), |
||||
}, |
||||
|
||||
EventName.startup: { |
||||
ET.PERMANENT: Alert( |
||||
"Be ready to take over at any time", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
}, |
||||
|
||||
EventName.startupMaster: { |
||||
ET.PERMANENT: Alert( |
||||
"WARNING: This branch is not tested", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
}, |
||||
|
||||
EventName.startupNoControl: { |
||||
ET.PERMANENT: Alert( |
||||
"Dashcam mode", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
}, |
||||
|
||||
EventName.startupNoCar: { |
||||
ET.PERMANENT: Alert( |
||||
"Dashcam mode for unsupported car", |
||||
"Always keep hands on wheel and eyes on road", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.), |
||||
}, |
||||
|
||||
EventName.invalidGiraffeToyota: { |
||||
ET.PERMANENT: Alert( |
||||
"Unsupported Giraffe Configuration", |
||||
"Visit comma.ai/tg", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.invalidLkasSetting: { |
||||
ET.PERMANENT: Alert( |
||||
"Stock LKAS is turned on", |
||||
"Turn off stock LKAS to engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.communityFeatureDisallowed: { |
||||
# LOW priority to overcome Cruise Error |
||||
ET.PERMANENT: Alert( |
||||
"", |
||||
"Community Feature Detected", |
||||
"Enable Community Features in Developer Settings", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.carUnrecognized: { |
||||
ET.PERMANENT: Alert( |
||||
"Dashcam Mode", |
||||
"Car Unrecognized", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.stockAeb: { |
||||
ET.PERMANENT: Alert( |
||||
"BRAKE!", |
||||
"Stock AEB: Risk of Collision", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), |
||||
}, |
||||
|
||||
EventName.stockFcw: { |
||||
ET.PERMANENT: Alert( |
||||
"BRAKE!", |
||||
"Stock FCW: Risk of Collision", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.none, 1., 2., 2.), |
||||
}, |
||||
|
||||
EventName.fcw: { |
||||
ET.PERMANENT: Alert( |
||||
"BRAKE!", |
||||
"Risk of Collision", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeat, 1., 2., 2.), |
||||
}, |
||||
|
||||
EventName.ldw: { |
||||
ET.PERMANENT: Alert( |
||||
"TAKE CONTROL", |
||||
"Lane Departure Detected", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), |
||||
}, |
||||
|
||||
# ********** events only containing alerts that display while engaged ********** |
||||
|
||||
EventName.vehicleModelInvalid: { |
||||
ET.WARNING: Alert( |
||||
"Vehicle Parameter Identification Failed", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWEST, VisualAlert.steerRequired, AudibleAlert.none, .0, .0, .1), |
||||
}, |
||||
|
||||
EventName.steerTempUnavailableMute: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Steering Temporarily Unavailable", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, .2, .2, .2), |
||||
}, |
||||
|
||||
EventName.preDriverDistracted: { |
||||
ET.WARNING: Alert( |
||||
"KEEP EYES ON ROAD: Driver Distracted", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
}, |
||||
|
||||
EventName.promptDriverDistracted: { |
||||
ET.WARNING: Alert( |
||||
"KEEP EYES ON ROAD", |
||||
"Driver Appears Distracted", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), |
||||
}, |
||||
|
||||
EventName.driverDistracted: { |
||||
ET.WARNING: Alert( |
||||
"DISEventName.AGE IMMEDIATELY", |
||||
"Driver Was Distracted", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), |
||||
}, |
||||
|
||||
EventName.preDriverUnresponsive: { |
||||
ET.WARNING: Alert( |
||||
"TOUCH STEERING WHEEL: No Face Detected", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
}, |
||||
|
||||
EventName.promptDriverUnresponsive: { |
||||
ET.WARNING: Alert( |
||||
"TOUCH STEERING WHEEL", |
||||
"Driver Is Unresponsive", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), |
||||
}, |
||||
|
||||
EventName.driverUnresponsive: { |
||||
ET.WARNING: Alert( |
||||
"DISEventName.AGE IMMEDIATELY", |
||||
"Driver Was Unresponsive", |
||||
AlertStatus.critical, AlertSize.full, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), |
||||
}, |
||||
|
||||
EventName.driverMonitorLowAcc: { |
||||
ET.WARNING: Alert( |
||||
"CHECK DRIVER FACE VISIBILITY", |
||||
"Driver Monitor Model Output Uncertain", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.), |
||||
}, |
||||
|
||||
EventName.manualRestart: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Resume Driving Manually", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.resumeRequired: { |
||||
ET.WARNING: Alert( |
||||
"STOPPED", |
||||
"Press Resume to Move", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
}, |
||||
|
||||
EventName.belowSteerSpeed: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Steer Unavailable Below ", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3), |
||||
}, |
||||
|
||||
EventName.preLaneChangeLeft: { |
||||
ET.WARNING: Alert( |
||||
"Steer Left to Start Lane Change", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
}, |
||||
|
||||
EventName.preLaneChangeRight: { |
||||
ET.WARNING: Alert( |
||||
"Steer Right to Start Lane Change", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), |
||||
}, |
||||
|
||||
EventName.laneChange: { |
||||
ET.WARNING: Alert( |
||||
"Changing Lane", |
||||
"Monitor Other Vehicles", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1), |
||||
}, |
||||
|
||||
EventName.steerSaturated: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Turn Exceeds Steering Limit", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), |
||||
}, |
||||
|
||||
# ********** events that affect controls state transitions ********** |
||||
|
||||
EventName.pcmEnable: { |
||||
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage), |
||||
}, |
||||
|
||||
EventName.buttonEnable: { |
||||
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage), |
||||
}, |
||||
|
||||
EventName.pcmDisable: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.buttonCancel: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.brakeHold: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"), |
||||
}, |
||||
|
||||
EventName.parkBrake: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
ET.NO_ENTRY: NoEntryAlert("Park Brake Engaged"), |
||||
}, |
||||
|
||||
EventName.pedalPressed: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
ET.NO_ENTRY: NoEntryAlert("Pedal Pressed During Attempt", |
||||
visual_alert=VisualAlert.brakePressed), |
||||
}, |
||||
|
||||
EventName.wrongCarMode: { |
||||
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), |
||||
ET.NO_ENTRY: NoEntryAlert("Main Switch Off", |
||||
duration_hud_alert=0.), |
||||
}, |
||||
|
||||
EventName.steerTempUnavailable: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Steering Temporarily Unavailable", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), |
||||
ET.NO_ENTRY: NoEntryAlert("Steering Temporarily Unavailable", |
||||
duration_hud_alert=0.), |
||||
}, |
||||
|
||||
EventName.posenetInvalid: { |
||||
ET.WARNING: Alert( |
||||
"TAKE CONTROL", |
||||
"Vision Model Output Uncertain", |
||||
AlertStatus.userPrompt, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3.), |
||||
ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"), |
||||
}, |
||||
|
||||
EventName.outOfSpace: { |
||||
ET.NO_ENTRY: NoEntryAlert("Out of Storage Space", |
||||
duration_hud_alert=0.), |
||||
}, |
||||
|
||||
EventName.sensorDataInvalid: { |
||||
ET.PERMANENT: Alert( |
||||
"No Data from Device Sensors", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("No Data from Device Sensors"), |
||||
}, |
||||
|
||||
EventName.soundsUnavailable: { |
||||
ET.PERMANENT: Alert( |
||||
"Speaker not found", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("Speaker not found"), |
||||
}, |
||||
|
||||
EventName.tooDistracted: { |
||||
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"), |
||||
}, |
||||
|
||||
EventName.overheat: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("System Overheated"), |
||||
ET.NO_ENTRY: NoEntryAlert("System overheated"), |
||||
}, |
||||
|
||||
EventName.wrongGear: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Gear not D"), |
||||
ET.NO_ENTRY: NoEntryAlert("Gear not D"), |
||||
}, |
||||
|
||||
EventName.calibrationInvalid: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Calibration Invalid: Reposition Device and Recalibrate"), |
||||
ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Reposition Device & Recalibrate"), |
||||
}, |
||||
|
||||
EventName.calibrationIncomplete: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Calibration in Progress"), |
||||
ET.PERMANENT: calibration_incomplete_alert, |
||||
ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"), |
||||
}, |
||||
|
||||
EventName.doorOpen: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Door Open"), |
||||
ET.NO_ENTRY: NoEntryAlert("Door open"), |
||||
}, |
||||
|
||||
EventName.seatbeltNotLatched: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Seatbelt Unlatched"), |
||||
ET.NO_ENTRY: NoEntryAlert("Seatbelt unlatched"), |
||||
}, |
||||
|
||||
EventName.espDisabled: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("ESP Off"), |
||||
ET.NO_ENTRY: NoEntryAlert("ESP Off"), |
||||
}, |
||||
|
||||
EventName.lowBattery: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Low Battery"), |
||||
ET.NO_ENTRY: NoEntryAlert("Low Battery"), |
||||
}, |
||||
|
||||
EventName.commIssue: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"), |
||||
ET.NO_ENTRY: NoEntryAlert("Communication Issue between Processes", |
||||
audible_alert=AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.radarCommIssue: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Radar Communication Issue"), |
||||
ET.NO_ENTRY: NoEntryAlert("Radar Communication Issue", |
||||
audible_alert=AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.radarCanError: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Radar Error: Restart the Car"), |
||||
ET.NO_ENTRY: NoEntryAlert("Radar Error: Restart the Car"), |
||||
}, |
||||
|
||||
EventName.radarFault: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Radar Error: Restart the Car"), |
||||
ET.NO_ENTRY : NoEntryAlert("Radar Error: Restart the Car"), |
||||
}, |
||||
|
||||
EventName.lowMemory: { |
||||
ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"), |
||||
ET.PERMANENT: Alert( |
||||
"RAM Critically Low", |
||||
"Reboot your Device", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY : NoEntryAlert("Low Memory: Reboot Your Device", |
||||
audible_alert=AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.controlsFailed: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Failed"), |
||||
ET.NO_ENTRY: NoEntryAlert("Controls Failed"), |
||||
}, |
||||
|
||||
EventName.controlsMismatch: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Controls Mismatch"), |
||||
}, |
||||
|
||||
EventName.canError: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error: Check Connections"), |
||||
ET.NO_ENTRY: NoEntryAlert("CAN Error: Check Connections"), |
||||
}, |
||||
|
||||
EventName.steerUnavailable: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"), |
||||
ET.PERMANENT: Alert( |
||||
"LKAS Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("LKAS Fault: Restart the Car"), |
||||
}, |
||||
|
||||
EventName.brakeUnavailable: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Fault: Restart the Car"), |
||||
ET.PERMANENT: Alert( |
||||
"Cruise Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), |
||||
}, |
||||
|
||||
EventName.gasUnavailable: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Gas Fault: Restart the Car"), |
||||
ET.NO_ENTRY: NoEntryAlert("Gas Error: Restart the Car"), |
||||
}, |
||||
|
||||
EventName.reverseGear: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Reverse Gear"), |
||||
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"), |
||||
}, |
||||
|
||||
EventName.cruiseDisabled: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Is Off"), |
||||
}, |
||||
|
||||
EventName.plannerError: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Planner Solution Error"), |
||||
ET.NO_ENTRY: NoEntryAlert("Planner Solution Error"), |
||||
}, |
||||
|
||||
EventName.relayMalfunction: { |
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Malfunction"), |
||||
ET.PERMANENT: Alert( |
||||
"Harness Malfunction", |
||||
"Please Check Hardware", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("Harness Malfunction"), |
||||
}, |
||||
|
||||
EventName.noTarget: { |
||||
ET.IMMEDIATE_DISABLE: Alert( |
||||
"openpilot Canceled", |
||||
"No close lead car", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
ET.NO_ENTRY : NoEntryAlert("No Close Lead Car"), |
||||
}, |
||||
|
||||
EventName.speedTooLow: { |
||||
ET.IMMEDIATE_DISABLE: Alert( |
||||
"openpilot Canceled", |
||||
"Speed too low", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), |
||||
ET.NO_ENTRY: NoEntryAlert("Speed Too Low"), |
||||
}, |
||||
|
||||
EventName.speedTooHigh: { |
||||
ET.IMMEDIATE_DISABLE: Alert( |
||||
"Speed Too High", |
||||
"Slow down to resume operation", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, 2.2, 3., 4.), |
||||
ET.NO_ENTRY: Alert( |
||||
"Speed Too High", |
||||
"Slow down to engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), |
||||
}, |
||||
|
||||
EventName.internetConnectivityNeeded: { |
||||
ET.PERMANENT: Alert( |
||||
"Please connect to Internet", |
||||
"An Update Check Is Required to Engage", |
||||
AlertStatus.normal, AlertSize.mid, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("Please Connect to Internet", |
||||
audible_alert=AudibleAlert.chimeDisengage), |
||||
}, |
||||
|
||||
EventName.lowSpeedLockout: { |
||||
ET.PERMANENT: Alert( |
||||
"Cruise Fault: Restart the car to engage", |
||||
"", |
||||
AlertStatus.normal, AlertSize.small, |
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), |
||||
ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), |
||||
}, |
||||
|
||||
} |
@ -1,48 +0,0 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import unittest |
||||
from PIL import Image, ImageDraw, ImageFont |
||||
|
||||
from cereal import log |
||||
from common.basedir import BASEDIR |
||||
from selfdrive.controls.lib.alerts import ALERTS |
||||
|
||||
AlertSize = log.ControlsState.AlertSize |
||||
|
||||
FONT_PATH = os.path.join(BASEDIR, "selfdrive/assets/fonts") |
||||
REGULAR_FONT_PATH = os.path.join(FONT_PATH, "opensans_semibold.ttf") |
||||
BOLD_FONT_PATH = os.path.join(FONT_PATH, "opensans_semibold.ttf") |
||||
SEMIBOLD_FONT_PATH = os.path.join(FONT_PATH, "opensans_semibold.ttf") |
||||
|
||||
MAX_TEXT_WIDTH = 1920 - 300 # full screen width is useable, minus sidebar |
||||
# TODO: get exact scale factor. found this empirically, works well enough |
||||
FONT_SIZE_SCALE = 1.85 # factor to scale from nanovg units to PIL |
||||
|
||||
class TestAlerts(unittest.TestCase): |
||||
|
||||
# ensure alert text doesn't exceed allowed width |
||||
def test_alert_text_length(self): |
||||
draw = ImageDraw.Draw(Image.new('RGB', (0, 0))) |
||||
|
||||
fonts = { |
||||
AlertSize.small: [ImageFont.truetype(SEMIBOLD_FONT_PATH, int(40*FONT_SIZE_SCALE))], |
||||
AlertSize.mid: [ImageFont.truetype(BOLD_FONT_PATH, int(48*FONT_SIZE_SCALE)), |
||||
ImageFont.truetype(REGULAR_FONT_PATH, int(36*FONT_SIZE_SCALE))], |
||||
} |
||||
|
||||
for alert in ALERTS: |
||||
# for full size alerts, both text fields wrap the text, |
||||
# so it's unlikely that they would go past the max width |
||||
if alert.alert_size in [AlertSize.none, AlertSize.full]: |
||||
continue |
||||
|
||||
for i, txt in enumerate([alert.alert_text_1, alert.alert_text_2]): |
||||
if i >= len(fonts[alert.alert_size]): break |
||||
|
||||
font = fonts[alert.alert_size][i] |
||||
w, h = draw.textsize(txt, font) |
||||
msg = "type: %s msg: %s" % (alert.alert_type, txt) |
||||
self.assertLessEqual(w, MAX_TEXT_WIDTH, msg=msg) |
||||
|
||||
if __name__ == "__main__": |
||||
unittest.main() |
@ -0,0 +1,63 @@ |
||||
#!/usr/bin/env python3 |
||||
import os |
||||
import unittest |
||||
from PIL import Image, ImageDraw, ImageFont |
||||
|
||||
from cereal import log, car |
||||
from common.basedir import BASEDIR |
||||
from selfdrive.controls.lib.events import Alert, EVENTS |
||||
|
||||
AlertSize = log.ControlsState.AlertSize |
||||
|
||||
class TestAlerts(unittest.TestCase): |
||||
|
||||
def test_events_defined(self): |
||||
# Ensure all events in capnp schema are defined in events.py |
||||
events = car.CarEvent.EventName.schema.enumerants |
||||
|
||||
for name, e in events.items(): |
||||
if not name.endswith("DEPRECATED"): |
||||
fail_msg = "%s @%d not in EVENTS" % (name, e) |
||||
self.assertTrue(e in EVENTS.keys(), msg=fail_msg) |
||||
|
||||
# ensure alert text doesn't exceed allowed width |
||||
def test_alert_text_length(self): |
||||
font_path = os.path.join(BASEDIR, "selfdrive/assets/fonts") |
||||
regular_font_path = os.path.join(font_path, "opensans_semibold.ttf") |
||||
bold_font_path = os.path.join(font_path, "opensans_semibold.ttf") |
||||
semibold_font_path = os.path.join(font_path, "opensans_semibold.ttf") |
||||
|
||||
max_text_width = 1920 - 300 # full screen width is useable, minus sidebar |
||||
# TODO: get exact scale factor. found this empirically, works well enough |
||||
font_scale_factor = 1.85 # factor to scale from nanovg units to PIL |
||||
|
||||
draw = ImageDraw.Draw(Image.new('RGB', (0, 0))) |
||||
|
||||
fonts = { |
||||
AlertSize.small: [ImageFont.truetype(semibold_font_path, int(40*font_scale_factor))], |
||||
AlertSize.mid: [ImageFont.truetype(bold_font_path, int(48*font_scale_factor)), |
||||
ImageFont.truetype(regular_font_path, int(36*font_scale_factor))], |
||||
} |
||||
|
||||
alerts = [] |
||||
for event_types in EVENTS.values(): |
||||
for alert in event_types.values(): |
||||
if isinstance(alert, Alert): |
||||
alerts.append(alert) |
||||
|
||||
for alert in alerts: |
||||
# for full size alerts, both text fields wrap the text, |
||||
# so it's unlikely that they would go past the max width |
||||
if alert.alert_size in [AlertSize.none, AlertSize.full]: |
||||
continue |
||||
|
||||
for i, txt in enumerate([alert.alert_text_1, alert.alert_text_2]): |
||||
if i >= len(fonts[alert.alert_size]): break |
||||
|
||||
font = fonts[alert.alert_size][i] |
||||
w, h = draw.textsize(txt, font) |
||||
msg = "type: %s msg: %s" % (alert.alert_type, txt) |
||||
self.assertLessEqual(w, max_text_width, msg=msg) |
||||
|
||||
if __name__ == "__main__": |
||||
unittest.main() |
@ -1 +1 @@ |
||||
1050a84363baf1e7910d3f8f9a01e201e6041e70 |
||||
76e577b86d113139167275b4a7379f3591abfa02 |
Loading…
Reference in new issue