* new engage/disengage + amp config

* first family

* cleanup audible alerts

* tici isn't special

* fix up debug cycle alerts

* these were better

* extend range

* use distracted sound

* log scaling

* getting closer

* slightly louder

* prompt

* update tests

* update refs

* fix c2 test

* resolve todo

* adjust tolerance

* revert for now

* should work

Co-authored-by: Comma Device <device@comma.ai>
old-commit-hash: e679d05d9e
commatwo_master
Adeeb Shihadeh 4 years ago committed by GitHub
parent 2a57577b9d
commit dccb8b4010
  1. 2
      cereal
  2. 1
      release/files_tici
  3. 3
      selfdrive/assets/sounds/disengage.wav
  4. 3
      selfdrive/assets/sounds/disengaged.wav
  5. 3
      selfdrive/assets/sounds/engage.wav
  6. 3
      selfdrive/assets/sounds/engaged.wav
  7. 3
      selfdrive/assets/sounds/error.wav
  8. 3
      selfdrive/assets/sounds/prompt.wav
  9. 3
      selfdrive/assets/sounds/refuse.wav
  10. 3
      selfdrive/assets/sounds/warning_1.wav
  11. 3
      selfdrive/assets/sounds/warning_2.wav
  12. 3
      selfdrive/assets/sounds/warning_immediate.wav
  13. 3
      selfdrive/assets/sounds/warning_repeat.wav
  14. 3
      selfdrive/assets/sounds/warning_soft.wav
  15. 3
      selfdrive/assets/sounds_tici/disengaged.wav
  16. 3
      selfdrive/assets/sounds_tici/engaged.wav
  17. 3
      selfdrive/assets/sounds_tici/error.wav
  18. 3
      selfdrive/assets/sounds_tici/warning_1.wav
  19. 3
      selfdrive/assets/sounds_tici/warning_2.wav
  20. 3
      selfdrive/assets/sounds_tici/warning_repeat.wav
  21. 21
      selfdrive/controls/lib/alertmanager.py
  22. 65
      selfdrive/controls/lib/events.py
  23. 93
      selfdrive/debug/cycle_alerts.py
  24. 15
      selfdrive/hardware/tici/amplifier.py
  25. 4
      selfdrive/hardware/tici/hardware.h
  26. 2
      selfdrive/test/process_replay/ref_commit
  27. 14
      selfdrive/ui/soundd/sound.cc
  28. 17
      selfdrive/ui/soundd/sound.h
  29. 19
      selfdrive/ui/tests/test_soundd.py
  30. 2
      selfdrive/ui/ui.h

@ -1 +1 @@
Subproject commit d6f233bf7bd6d1ee3508b17667e44420ce38de0d
Subproject commit 9ce45916c6c27e8cfbbe2aa6b796fac41eeeba00

@ -4,7 +4,6 @@ selfdrive/timezoned.py
selfdrive/assets/navigation/*
selfdrive/assets/training_wide/*
selfdrive/assets/sounds_tici/*
selfdrive/camerad/cameras/camera_qcom2.cc
selfdrive/camerad/cameras/camera_qcom2.h

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4b1294c17f2c19a390d1d5f09c0ef887496e46b5494fe7e94289c5b536e1e014
size 155804

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5db18c6fb1e975d6d2bdb62372214a981e179d9af790a0e579e7d7a4c32bbb75
size 40662

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ad87ff4f54b3b058a00d6dd2142b881c583be5124940cd90ec91a6c714ec4567
size 92172

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:165a121885f67004ffbeb34d6ad265c6e54dc5456674379434ff6f66ca6f688a
size 40654

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bfe1b73efabfcbd36dae63d39d0c1e2d4c1ead63daac0430a648e4686307e06c
size 40650

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3007836472db496398397eb409778b2e0018cce66033afc791b108e5202ad371
size 127172

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:079121f2e0272117afc21074d79602c9939a1a4f0c19ca0ed82547d7d9537c22
size 209238

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:80b08552196740078647d35ef20781018a8fe97e75a1ff99e297f40fc3721b72
size 21468

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:29ea3f93348689ce82b2bb0815cc9c99bdf91aabd3be36076bbb601e3572e30e
size 124708

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b5e3b2d20d604902eb19fb773bce89fa6fdc9a7e0610ec6ac729fd1512455f98
size 133412

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c776220f534ba5776a6bd831050ba767b5439badc74b67666fe70e44cd62692
size 62760

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cc0b574afbee712a971b7347dc01eadaf824b14b7365ae6b3e0639de8917a1cd
size 76108

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c6ef7f760160e1c5d9ec7a9b2cd46a79866acfdd3dbba6a8fd49051490b37aa7
size 50316

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5429a1633695013bcd69a6d8e529e4ac95a9e0e4c50e8ae0027b06003ed662e2
size 50288

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1c31dab68d1498b84912c6e424fd783d054942242ca40a5dfb311edd148b744a
size 50304

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:209c3328f1eb924917f78438c2faf43d9c23ae7f39b7ba6105b7ca509e279e15
size 31094

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8687abcc94d4bb30dd18be37ed03e2a224cc6ddc227c1e8c0c3ba9bdfc85b302
size 134392

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:92a69b8847a51b7d60af4447f930b50e343f7f04316a765d0a13ae4d0152160f
size 70114

@ -41,6 +41,7 @@ class AlertManager:
self.activealerts: Dict[str, AlertEntry] = defaultdict(AlertEntry)
def reset(self) -> None:
self.alert: Optional[Alert] = None
self.alert_type: str = ""
self.alert_text_1: str = ""
self.alert_text_2: str = ""
@ -74,13 +75,13 @@ class AlertManager:
# clear current alert
self.reset()
a = current_alert.alert
if a is not None:
self.alert_type = a.alert_type
self.audible_alert = a.audible_alert
self.visual_alert = a.visual_alert
self.alert_text_1 = a.alert_text_1
self.alert_text_2 = a.alert_text_2
self.alert_status = a.alert_status
self.alert_size = a.alert_size
self.alert_rate = a.alert_rate
self.alert = current_alert.alert
if self.alert is not None:
self.alert_type = self.alert.alert_type
self.audible_alert = self.alert.audible_alert
self.visual_alert = self.alert.visual_alert
self.alert_text_1 = self.alert.alert_text_1
self.alert_text_2 = self.alert.alert_text_2
self.alert_status = self.alert.alert_status
self.alert_size = self.alert.alert_size
self.alert_rate = self.alert.alert_rate

@ -139,11 +139,10 @@ class Alert:
class NoEntryAlert(Alert):
def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError,
visual_alert=VisualAlert.none):
def __init__(self, alert_text_2, visual_alert=VisualAlert.none):
super().__init__("openpilot Unavailable", alert_text_2, AlertStatus.normal,
AlertSize.mid, Priority.LOW, visual_alert,
audible_alert, 3.)
AudibleAlert.refuse, 3.)
class SoftDisableAlert(Alert):
@ -151,7 +150,7 @@ class SoftDisableAlert(Alert):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.userPrompt, AlertSize.full,
Priority.MID, VisualAlert.steerRequired,
AudibleAlert.chimeWarningRepeatInfinite, 2.),
AudibleAlert.warningSoft, 2.),
class ImmediateDisableAlert(Alert):
@ -159,7 +158,7 @@ class ImmediateDisableAlert(Alert):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired,
AudibleAlert.chimeWarningRepeatInfinite, 4.),
AudibleAlert.warningImmediate, 4.),
class EngagementAlert(Alert):
@ -201,7 +200,7 @@ def below_steer_speed_alert(CP: car.CarParams, sm: messaging.SubMaster, metric:
f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 0.4)
Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
@ -321,7 +320,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"BRAKE!",
"Risk of Collision",
AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeatInfinite, 2.),
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
},
EventName.ldw: {
@ -329,7 +328,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TAKE CONTROL",
"Lane Departure Detected",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.ldw, AudibleAlert.chimePrompt, 3.),
Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
},
# ********** events only containing alerts that display while engaged **********
@ -360,7 +359,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Steering Temporarily Unavailable",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1.),
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.),
},
EventName.preDriverDistracted: {
@ -376,7 +375,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"KEEP EYES ON ROAD",
"Driver Distracted",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, .1),
Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, .1),
},
EventName.driverDistracted: {
@ -384,7 +383,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"DISENGAGE IMMEDIATELY",
"Driver Distracted",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeatInfinite, .1),
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.preDriverUnresponsive: {
@ -400,7 +399,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TOUCH STEERING WHEEL",
"Driver Unresponsive",
AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, .1),
Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, .1),
},
EventName.driverUnresponsive: {
@ -408,7 +407,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"DISENGAGE IMMEDIATELY",
"Driver Unresponsive",
AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeatInfinite, .1),
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
},
EventName.manualRestart: {
@ -452,7 +451,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Car Detected in Blindspot",
"",
AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.chimePrompt, .1),
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
},
EventName.laneChange: {
@ -468,7 +467,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TAKE CONTROL",
"Turn Exceeds Steering Limit",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, 1.),
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 1.),
},
# Thrown when the fan is driven at >50% but is not rotating
@ -496,44 +495,44 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
# ********** events that affect controls state transitions **********
EventName.pcmEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage),
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventName.buttonEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage),
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
},
EventName.pcmDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
},
EventName.buttonCancel: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
},
EventName.brakeHold: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
},
EventName.parkBrake: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Park Brake Engaged"),
},
EventName.pedalPressed: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Pedal Pressed During Attempt",
visual_alert=VisualAlert.brakePressed),
},
EventName.wrongCarMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: wrong_car_mode_alert,
},
EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage),
ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Enable Adaptive Cruise"),
},
@ -627,14 +626,12 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
# ten times the regular interval, or the average interval is more than 10% too high.
EventName.commIssue: {
ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"),
ET.NO_ENTRY: NoEntryAlert("Communication Issue between Processes",
audible_alert=AudibleAlert.chimeDisengage),
ET.NO_ENTRY: NoEntryAlert("Communication Issue between Processes"),
},
# Thrown when manager detects a service exited unexpectedly while driving
EventName.processNotRunning: {
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device",
audible_alert=AudibleAlert.chimeDisengage),
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device"),
},
EventName.radarFault: {
@ -670,15 +667,13 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.lowMemory: {
ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"),
ET.PERMANENT: NormalPermanentAlert("Low Memory", "Reboot your Device"),
ET.NO_ENTRY: NoEntryAlert("Low Memory: Reboot Your Device",
audible_alert=AudibleAlert.chimeDisengage),
ET.NO_ENTRY: NoEntryAlert("Low Memory: Reboot Your Device"),
},
EventName.highCpuUsage: {
#ET.SOFT_DISABLE: SoftDisableAlert("System Malfunction: Reboot Your Device"),
#ET.PERMANENT: NormalPermanentAlert("System Malfunction", "Reboot your Device"),
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device",
audible_alert=AudibleAlert.chimeDisengage),
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device"),
},
EventName.accFaulted: {
@ -782,7 +777,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"openpilot Canceled",
"No close lead car",
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, 3.),
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
ET.NO_ENTRY: NoEntryAlert("No Close Lead Car"),
},
@ -791,7 +786,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"openpilot Canceled",
"Speed too low",
AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, 3.),
Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
},
# When the car is driving faster than most cars in the training data the model outputs can be unpredictable
@ -800,7 +795,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Speed Too High",
"Model uncertain at this speed",
AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, 4.),
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
ET.NO_ENTRY: NoEntryAlert("Slow down to engage"),
},

@ -7,18 +7,31 @@ import time
from cereal import car, log
import cereal.messaging as messaging
from common.realtime import DT_CTRL
from selfdrive.car.honda.interface import CarInterface
from selfdrive.controls.lib.events import ET, EVENTS, Events
from selfdrive.controls.lib.alertmanager import AlertManager
EventName = car.CarEvent.EventName
def cycle_alerts(duration=2000, is_metric=False):
alerts = list(EVENTS.keys())
print(alerts)
def cycle_alerts(duration=200, is_metric=False):
# all alerts
#alerts = list(EVENTS.keys())
alerts = [EventName.preDriverDistracted, EventName.promptDriverDistracted, EventName.driverDistracted]
#alerts = [EventName.preLaneChangeLeft, EventName.preLaneChangeRight]
# this plays each type of audible alert
alerts = [
(EventName.buttonEnable, ET.ENABLE),
(EventName.buttonCancel, ET.USER_DISABLE),
(EventName.wrongGear, ET.NO_ENTRY),
(EventName.vehicleModelInvalid, ET.SOFT_DISABLE),
(EventName.accFaulted, ET.IMMEDIATE_DISABLE),
# DM sequence
(EventName.preDriverDistracted, ET.WARNING),
(EventName.promptDriverDistracted, ET.WARNING),
(EventName.driverDistracted, ET.WARNING),
]
CP = CarInterface.get_params("HONDA CIVIC 2016")
sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration',
@ -30,43 +43,45 @@ def cycle_alerts(duration=2000, is_metric=False):
AM = AlertManager()
frame = 0
idx, last_alert_millis = 0, 0
while 1:
if frame % duration == 0:
idx = (idx + 1) % len(alerts)
events.clear()
events.add(alerts[idx])
while True:
current_alert_types = [ET.PERMANENT, ET.USER_DISABLE, ET.IMMEDIATE_DISABLE,
ET.SOFT_DISABLE, ET.PRE_ENABLE, ET.NO_ENTRY,
ET.ENABLE, ET.WARNING]
a = events.create_alerts(current_alert_types, [CP, sm, is_metric])
AM.add_many(frame, a)
AM.process_alerts(frame)
dat = messaging.new_message()
dat.init('controlsState')
dat.controlsState.alertText1 = AM.alert_text_1
dat.controlsState.alertText2 = AM.alert_text_2
dat.controlsState.alertSize = AM.alert_size
dat.controlsState.alertStatus = AM.alert_status
dat.controlsState.alertBlinkingRate = AM.alert_rate
dat.controlsState.alertType = AM.alert_type
dat.controlsState.alertSound = AM.audible_alert
pm.send('controlsState', dat)
dat = messaging.new_message()
dat.init('deviceState')
dat.deviceState.started = True
pm.send('deviceState', dat)
dat = messaging.new_message('pandaStates', 1)
dat.pandaStates[0].ignitionLine = True
dat.pandaStates[0].pandaType = log.PandaState.PandaType.uno
pm.send('pandaStates', dat)
time.sleep(0.01)
for alert, et in alerts:
events.clear()
events.add(alert)
a = events.create_alerts([et, ], [CP, sm, is_metric])
AM.add_many(frame, a)
AM.process_alerts(frame)
print(AM.alert)
for _ in range(duration):
dat = messaging.new_message()
dat.init('controlsState')
dat.controlsState.enabled = True
dat.controlsState.alertText1 = AM.alert_text_1
dat.controlsState.alertText2 = AM.alert_text_2
dat.controlsState.alertSize = AM.alert_size
dat.controlsState.alertStatus = AM.alert_status
dat.controlsState.alertBlinkingRate = AM.alert_rate
dat.controlsState.alertType = AM.alert_type
dat.controlsState.alertSound = AM.audible_alert
pm.send('controlsState', dat)
dat = messaging.new_message()
dat.init('deviceState')
dat.deviceState.started = True
pm.send('deviceState', dat)
dat = messaging.new_message('pandaStates', 1)
dat.pandaStates[0].ignitionLine = True
dat.pandaStates[0].pandaType = log.PandaState.PandaType.uno
pm.send('pandaStates', dat)
frame += 1
time.sleep(DT_CTRL)
if __name__ == '__main__':
cycle_alerts()

@ -31,17 +31,18 @@ BASE_CONFIG = [
AmpConfig("Enable PLL2", 0b1, 0x1A, 7, 0b10000000),
AmpConfig("DAI1: I2S mode", 0b00100, 0x14, 2, 0b01111100),
AmpConfig("DAI2: I2S mode", 0b00100, 0x1C, 2, 0b01111100),
AmpConfig("Right speaker output volume", 0x1a, 0x3E, 0, 0b00011111),
AmpConfig("Right speaker output volume", 0x1c, 0x3E, 0, 0b00011111),
AmpConfig("DAI1 Passband filtering: music mode", 0b1, 0x18, 7, 0b10000000),
AmpConfig("DAI1 voice mode gain (DV1G)", 0b00, 0x2F, 4, 0b00110000),
AmpConfig("DAI1 attenuation (DV1)", 0x0, 0x2F, 0, 0b00001111),
AmpConfig("DAI2 attenuation (DV2)", 0x0, 0x31, 0, 0b00001111),
AmpConfig("DAI2: DC blocking", 0b1, 0x20, 0, 0b00000001),
AmpConfig("DAI2: High sample rate", 0b0, 0x20, 3, 0b00001000),
AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000),
AmpConfig("ALC enable", 0b1, 0x43, 7, 0b10000000),
AmpConfig("ALC/excursion limiter release time", 0b101, 0x43, 4, 0b01110000),
AmpConfig("ALC multiband enable", 0b1, 0x43, 3, 0b00001000),
AmpConfig("DAI1 EQ enable", 0b0, 0x49, 0, 0b00000001),
AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010),
AmpConfig("DAI2 EQ enable", 0b1, 0x49, 1, 0b00000010),
AmpConfig("DAI2 EQ clip detection disabled", 0b1, 0x32, 4, 0b00010000),
AmpConfig("DAI2 EQ attenuation", 0x5, 0x32, 0, 0b00001111),
AmpConfig("Excursion limiter upper corner freq", 0b100, 0x41, 4, 0b01110000),
@ -62,11 +63,11 @@ BASE_CONFIG = [
AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000),
]
BASE_CONFIG += configs_from_eq_params(0x84, EQParams(0x65C4, 0xC07C, 0x3D66, 0x07D9, 0x120F))
BASE_CONFIG += configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656))
BASE_CONFIG += configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF))
BASE_CONFIG += configs_from_eq_params(0x98, EQParams(0x2822, 0xC1C7, 0x3B50, 0x0EF8, 0x180A))
BASE_CONFIG += configs_from_eq_params(0xA2, EQParams(0x1009, 0xC5C2, 0x271F, 0x1A87, 0x32A6))
BASE_CONFIG += configs_from_eq_params(0xAC, EQParams(0x2000, 0xCA1E, 0x4000, 0x2287, 0x0000))
BASE_CONFIG += configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42))
BASE_CONFIG += configs_from_eq_params(0xA2, EQParams(0x091F, 0x3D4C, 0xCE11, 0x1266, 0x2807))
BASE_CONFIG += configs_from_eq_params(0xAC, EQParams(0x0A9E, 0x3F20, 0xE573, 0x0A8B, 0x3A3B))
class Amplifier:
AMP_I2C_BUS = 0

@ -9,8 +9,8 @@
class HardwareTici : public HardwareNone {
public:
static constexpr float MAX_VOLUME = 1.0;
static constexpr float MIN_VOLUME = 0.4;
static constexpr float MAX_VOLUME = 0.9;
static constexpr float MIN_VOLUME = 0.3;
static bool TICI() { return true; }
static std::string get_os_version() {
return "AGNOS " + util::read_file("/VERSION");

@ -1 +1 @@
e0926a8b9f7cffc35808109a710648a7f57c0b71
9cbef406393a83b35a8f25aa75099da8f8d68276

@ -1,5 +1,9 @@
#include "selfdrive/ui/soundd/sound.h"
#include <QAudio>
#include <QAudioDeviceInfo>
#include <QDebug>
#include "cereal/messaging/messaging.h"
#include "selfdrive/common/util.h"
@ -7,14 +11,15 @@
// TODO: detect when we can't display the UI
Sound::Sound(QObject *parent) : sm({"carState", "controlsState", "deviceState"}) {
const QString sound_asset_path = Hardware::TICI() ? "../../assets/sounds_tici/" : "../../assets/sounds/";
qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName();
for (auto &[alert, fn, loops] : sound_list) {
QSoundEffect *s = new QSoundEffect(this);
QObject::connect(s, &QSoundEffect::statusChanged, [=]() {
assert(s->status() != QSoundEffect::Error);
});
s->setVolume(Hardware::MIN_VOLUME);
s->setSource(QUrl::fromLocalFile(sound_asset_path + fn));
s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn));
sounds[alert] = {s, loops};
}
@ -42,8 +47,9 @@ void Sound::update() {
// scale volume with speed
if (sm.updated("carState")) {
float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f,
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
float volume = std::clamp(sm["carState"].getCarState().getVEgo() / 29.f, 0.1f, 1.0f);
volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
volume = util::map_val(volume, 0.f, 1.f, Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
for (auto &[s, loops] : sounds) {
s->setVolume(std::round(100 * volume) / 100);
}

@ -7,14 +7,15 @@
const std::tuple<AudibleAlert, QString, int> sound_list[] = {
// AudibleAlert, file name, loop count
{AudibleAlert::CHIME_DISENGAGE, "disengaged.wav", 0},
{AudibleAlert::CHIME_ENGAGE, "engaged.wav", 0},
{AudibleAlert::CHIME_WARNING1, "warning_1.wav", 0},
{AudibleAlert::CHIME_WARNING_REPEAT, "warning_repeat.wav", 10},
{AudibleAlert::CHIME_WARNING_REPEAT_INFINITE, "warning_repeat.wav", QSoundEffect::Infinite},
{AudibleAlert::CHIME_WARNING2_REPEAT_INFINITE, "warning_2.wav", QSoundEffect::Infinite},
{AudibleAlert::CHIME_ERROR, "error.wav", 0},
{AudibleAlert::CHIME_PROMPT, "error.wav", 0},
{AudibleAlert::ENGAGE, "engage.wav", 0},
{AudibleAlert::DISENGAGE, "disengage.wav", 0},
{AudibleAlert::REFUSE, "refuse.wav", 0},
{AudibleAlert::PROMPT, "prompt.wav", 0},
{AudibleAlert::PROMPT_REPEAT, "prompt.wav", QSoundEffect::Infinite},
{AudibleAlert::WARNING_SOFT, "warning_soft.wav", QSoundEffect::Infinite},
{AudibleAlert::WARNING_IMMEDIATE, "warning_immediate.wav", 10},
};
class Sound : public QObject {

@ -15,14 +15,13 @@ AudibleAlert = car.CarControl.HUDControl.AudibleAlert
SOUNDS = {
# sound: total writes
AudibleAlert.none: 0,
AudibleAlert.chimeEngage: 173,
AudibleAlert.chimeDisengage: 173,
AudibleAlert.chimeError: 173,
AudibleAlert.chimePrompt: 173,
AudibleAlert.chimeWarning1: 163,
AudibleAlert.chimeWarningRepeat: 468,
AudibleAlert.chimeWarningRepeatInfinite: 468,
AudibleAlert.chimeWarning2RepeatInfinite: 470,
AudibleAlert.engage: 197,
AudibleAlert.disengage: 230,
AudibleAlert.refuse: 223,
AudibleAlert.prompt: 217,
AudibleAlert.promptRepeat: 475,
AudibleAlert.warningSoft: 477,
AudibleAlert.warningImmediate: 468,
}
def get_total_writes():
@ -40,7 +39,7 @@ class TestSoundd(unittest.TestCase):
pm = messaging.PubMaster(['deviceState', 'controlsState'])
# make sure they're all defined
alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items()}
alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items() if not k.endswith('DEPRECATED')}
diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys())
assert len(diff) == 0, f"not all sounds defined in test: {diff}"
@ -65,7 +64,7 @@ class TestSoundd(unittest.TestCase):
pm.send('controlsState', msg)
time.sleep(DT_CTRL)
tolerance = (expected_writes % 100) * 2
tolerance = expected_writes / 10
actual_writes = get_total_writes() - start_writes
assert abs(expected_writes - actual_writes) <= tolerance, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}"

@ -78,7 +78,7 @@ struct Alert {
// car is started, but controls is lagging or died
return {"TAKE CONTROL IMMEDIATELY", "Controls Unresponsive",
"controlsUnresponsive", cereal::ControlsState::AlertSize::FULL,
AudibleAlert::CHIME_WARNING_REPEAT};
AudibleAlert::WARNING_IMMEDIATE};
}
}
return {};

Loading…
Cancel
Save