diff --git a/selfdrive/car/gm/.gitignore b/selfdrive/car/gm/.gitignore new file mode 100644 index 00000000000000..89fa7bc7daf83e --- /dev/null +++ b/selfdrive/car/gm/.gitignore @@ -0,0 +1,2 @@ +buttons.msg +buttons.cc.msg diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index be0ca64ccb1996..6739da8f424c4b 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -4,7 +4,7 @@ from selfdrive.boardd.boardd import can_list_to_can_capnp from selfdrive.car import apply_std_steer_torque_limits from selfdrive.car.gm import gmcan -from selfdrive.car.gm.values import CAR, DBC +from selfdrive.car.gm.values import CAR, DBC, AccState from selfdrive.can.packer import CANPacker @@ -24,16 +24,20 @@ def __init__(self, car_fingerprint): self.STEER_DRIVER_ALLOWANCE = 50 # allowed driver torque before start limiting self.STEER_DRIVER_MULTIPLIER = 4 # weight driver torque heavily self.STEER_DRIVER_FACTOR = 100 # from dbc - self.NEAR_STOP_BRAKE_PHASE = 0.5 # m/s, more aggressive braking near full stop + self.NEAR_STOP_BRAKE_PHASE = 1.5 # m/s, more aggressive braking near full stop + + # Takes case of "Service Adaptive Cruise" and "Service Front Camera" + # dashboard messages. + self.ADAS_KEEPALIVE_STEP = 100 + self.CAMERA_KEEPALIVE_STEP = 100 - self.ADAS_KEEPALIVE_STEP = 10 # pedal lookups, only for Volt MAX_GAS = 3072 # Only a safety limit - ZERO_GAS = 2048 + self.ZERO_GAS = 2048 MAX_BRAKE = 350 # Should be around 3.5m/s^2, including regen self.MAX_ACC_REGEN = 1404 # ACC Regen braking is slightly less powerful than max regen paddle self.GAS_LOOKUP_BP = [-0.25, 0., 0.5] - self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, ZERO_GAS, MAX_GAS] + self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, self.ZERO_GAS, MAX_GAS] self.BRAKE_LOOKUP_BP = [-1., -0.25] self.BRAKE_LOOKUP_V = [MAX_BRAKE, 0] @@ -59,12 +63,11 @@ def __init__(self, canbus, car_fingerprint, allow_controls): self.pedal_steady = 0. self.start_time = sec_since_boot() self.chime = 0 - self.lkas_active = False - self.inhibit_steer_for = 0 self.steer_idx = 0 self.apply_steer_last = 0 self.car_fingerprint = car_fingerprint self.allow_controls = allow_controls + self.lka_icon_status_last = 0 # Setup detection helper. Routes commands to # an appropriate CAN bus number. @@ -77,13 +80,17 @@ def __init__(self, canbus, car_fingerprint, allow_controls): def update(self, sendcan, enabled, CS, frame, actuators, \ hud_v_cruise, hud_show_lanes, hud_show_car, chime, chime_cnt): """ Controls thread """ - +#update custom UI buttons and alerts + CS.UE.update_custom_ui() + if (frame % 1000 == 0): + CS.cstm_btns.send_button_info() + CS.UE.uiSetCarEvent(CS.cstm_btns.car_folder,CS.cstm_btns.car_name) + # Sanity check. if not self.allow_controls: return P = self.params - # Send CAN commands. can_sends = [] canbus = self.canbus @@ -100,7 +107,8 @@ def update(self, sendcan, enabled, CS, frame, actuators, \ self.apply_steer_last = apply_steer idx = (frame / P.STEER_STEP) % 4 - + if CS.cstm_btns.get_button_status("lka") == 0: + apply_steer = 0 if self.car_fingerprint == CAR.VOLT: can_sends.append(gmcan.create_steering_control(self.packer_pt, canbus.powertrain, apply_steer, idx, lkas_enabled)) @@ -131,12 +139,18 @@ def update(self, sendcan, enabled, CS, frame, actuators, \ if (frame % 4) == 0: idx = (frame / 4) % 4 - at_full_stop = enabled and CS.standstill - near_stop = enabled and (CS.v_ego < P.NEAR_STOP_BRAKE_PHASE) + car_stopping = apply_gas < P.ZERO_GAS + standstill = CS.pcm_acc_status == AccState.STANDSTILL + at_full_stop = enabled and standstill and car_stopping + near_stop = enabled and (CS.v_ego < P.NEAR_STOP_BRAKE_PHASE) and car_stopping can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, canbus.chassis, apply_brake, idx, near_stop, at_full_stop)) - at_full_stop = enabled and CS.standstill - can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, canbus.powertrain, apply_gas, idx, enabled, at_full_stop)) + # Auto-resume from full stop by resetting ACC control + acc_enabled = enabled + if standstill and not car_stopping: + acc_enabled = False + + can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, canbus.powertrain, apply_gas, idx, acc_enabled, at_full_stop)) # Send dashboard UI commands (ACC status), 25hz if (frame % 4) == 0: @@ -158,10 +172,21 @@ def update(self, sendcan, enabled, CS, frame, actuators, \ can_sends.append(gmcan.create_adas_steering_status(canbus.obstacle, idx)) can_sends.append(gmcan.create_adas_accelerometer_speed_status(canbus.obstacle, CS.v_ego, idx)) - # Send ADAS keepalive, 10hz if frame % P.ADAS_KEEPALIVE_STEP == 0: can_sends += gmcan.create_adas_keepalive(canbus.powertrain) + # Show green icon when LKA torque is applied, and + # alarming orange icon when approaching torque limit. + # If not sent periodically, LKA icon disappears in about 5 seconds. + # Conveniently, sending camera message periodically also works as a keepalive. + lka_active = CS.lkas_status == 1 + lka_critical = abs(actuators.steer) > 0.9 + lka_icon_status = lka_active + (int(lka_critical) << 1) + if frame % P.CAMERA_KEEPALIVE_STEP == 0 \ + or lka_icon_status != self.lka_icon_status_last: + can_sends.append(gmcan.create_lka_icon_command(canbus.sw_gmlan, lka_active, lka_critical)) + self.lka_icon_status_last = lka_icon_status + # Send chimes if self.chime != chime: duration = 0x3c diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 7c0c63f54631ce..fdc58eac422542 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -3,6 +3,8 @@ from common.kalman.simple_kalman import KF1D from selfdrive.config import Conversions as CV from selfdrive.can.parser import CANParser +from selfdrive.car.modules.UIBT_module import UIButtons,UIButton +from selfdrive.car.modules.UIEV_module import UIEvents from selfdrive.car.gm.values import DBC, CAR, parse_gear_shifter, \ CruiseButtons, is_eps_status_ok, \ STEER_THRESHOLD @@ -56,7 +58,19 @@ def __init__(self, CP, canbus): self.prev_left_blinker_on = False self.right_blinker_on = False self.prev_right_blinker_on = False - + + #BB UIEvents + self.UE = UIEvents(self) + + #BB variable for custom buttons + self.cstm_btns = UIButtons(self,"Gm","gm") + + #BB pid holder for ALCA + self.pid = None + + #BB custom message counter + self.custom_alert_counter = -1 #set to 100 for 1 second display; carcontroller will take down to zero + # vEgo kalman filter dt = 0.01 self.v_ego_kf = KF1D(x0=np.matrix([[0.], [0.]]), @@ -64,7 +78,23 @@ def __init__(self, CP, canbus): C=np.matrix([1., 0.]), K=np.matrix([[0.12287673], [0.29666309]])) self.v_ego = 0. - + #BB init ui buttons + def init_ui_buttons(self): + btns = [] + btns.append(UIButton("","",0,"",0)) + btns.append(UIButton("","",0,"",1)) + btns.append(UIButton("","",0,"",2)) + btns.append(UIButton("","",0,"",3)) + btns.append(UIButton("gas","GAS",0,"",4)) + btns.append(UIButton("lka","LKA",0,"",5)) + return btns + #BB update ui buttons + def update_ui_buttons(self,id,btn_status): + if self.cstm_btns.btns[id].btn_status > 0: + self.cstm_btns.btns[id].btn_status = btn_status * self.cstm_btns.btns[id].btn_status + else: + self.cstm_btns.btns[id].btn_status = btn_status + def update(self, pt_cp): self.can_valid = pt_cp.can_valid diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 47b0d8b38dfad4..1aedd7603e49d9 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -59,19 +59,16 @@ def create_gas_regen_command(packer, bus, throttle, idx, acc_engaged, at_full_st return packer.make_can_msg("ASCMGasRegenCmd", bus, values) def create_friction_brake_command(packer, bus, apply_brake, idx, near_stop, at_full_stop): - - if apply_brake == 0: - mode = 0x1 - else: + mode = 0x1 + if apply_brake > 0: mode = 0xa - if at_full_stop: - mode = 0xd - # TODO: this is to have GM bringing the car to complete stop, - # but currently it conflicts with OP controls, so turned off. - #elif near_stop: - # mode = 0xb + if near_stop: + mode = 0xb + if at_full_stop: + mode = 0xd + brake = (0x1000 - apply_brake) & 0xfff checksum = (0x10000 - (mode << 12) - brake - idx) & 0xffff @@ -134,6 +131,16 @@ def create_chime_command(bus, chime_type, duration, repeat_cnt): dat = [chime_type, duration, repeat_cnt, 0xff, 0] return [0x10400060, 0, "".join(map(chr, dat)), bus] +def create_lka_icon_command(bus, active, critical): + if active: + if critical: + dat = "\x40\xc0\x14" + else: + dat = "\x40\x40\x18" + else: + dat = "\x00\x00\x00" + return [0x104c006c, 0, dat, bus] + # TODO: WIP ''' def create_friction_brake_command_ct6(packer, bus, apply_brake, idx, near_stop, at_full_stop): diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 27d94b885b4af7..88d1e0fb45ba3f 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -52,7 +52,13 @@ def __init__(self, CP, sendcan=None): @staticmethod def compute_gb(accel, speed): - return float(accel) / 4.0 + # Ripped from compute_gb_honda in Honda's interface.py. Works well off shelf but may need more tuning + creep_brake = 0.0 + creep_speed = 2.68 + creep_brake_value = 0.10 + if speed < creep_speed: + creep_brake = (creep_speed - speed) / creep_speed * creep_brake_value + return float(accel) / 4.8 - creep_brake @staticmethod def calc_accel_override(a_ego, a_target, v_ego, v_target): @@ -76,7 +82,7 @@ def get_params(candidate, fingerprint): if candidate == CAR.VOLT: # supports stop and go, but initial engage must be above 18mph (which include conservatism) - ret.minEnableSpeed = 18 * CV.MPH_TO_MS + ret.minEnableSpeed = 7 * CV.MPH_TO_MS # kg of standard extra cargo to count for drive, gas, etc... ret.mass = 1607 + std_cargo ret.safetyModel = car.CarParams.SafetyModels.gm @@ -137,15 +143,15 @@ def get_params(candidate, fingerprint): ret.longPidDeadzoneBP = [0.] ret.longPidDeadzoneV = [0.] - ret.longitudinalKpBP = [5., 35.] - ret.longitudinalKpV = [2.4, 1.5] - ret.longitudinalKiBP = [0.] - ret.longitudinalKiV = [0.36] + ret.longitudinalKpBP = [0., 5., 35.] + ret.longitudinalKpV = [1.8, 2.425, 2.2] + ret.longitudinalKiBP = [0., 35.] + ret.longitudinalKiV = [0.26, 0.36] ret.steerLimitAlert = True ret.stoppingControl = True - ret.startAccel = 0.8 + ret.startAccel = 0.5 ret.steerActuatorDelay = 0.1 # Default delay, not measured yet ret.steerRateCost = 1.0 @@ -193,7 +199,7 @@ def update(self, c): ret.cruiseState.available = bool(self.CS.main_on) cruiseEnabled = self.CS.pcm_acc_status != 0 ret.cruiseState.enabled = cruiseEnabled - ret.cruiseState.standstill = self.CS.pcm_acc_status == 4 + ret.cruiseState.standstill = False ret.leftBlinker = self.CS.left_blinker_on ret.rightBlinker = self.CS.right_blinker_on @@ -237,7 +243,7 @@ def update(self, c): buttonEvents.append(be) ret.buttonEvents = buttonEvents - + ret.gasbuttonstatus = self.CS.cstm_btns.get_button_status("gas") events = [] if not self.CS.can_valid: self.can_invalid_count += 1 @@ -276,8 +282,6 @@ def update(self, c): events.append(create_event('pedalPressed', [ET.NO_ENTRY, ET.USER_DISABLE])) if ret.gasPressed: events.append(create_event('pedalPressed', [ET.PRE_ENABLE])) - if ret.cruiseState.standstill: - events.append(create_event('resumeRequired', [ET.WARNING])) # handle button presses for b in ret.buttonEvents: diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 8e93b677c8ae66..62529ed6d73578 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -12,6 +12,12 @@ class CruiseButtons: MAIN = 5 CANCEL = 6 +class AccState: + OFF = 0 + ACTIVE = 1 + FAULTED = 3 + STANDSTILL = 4 + def is_eps_status_ok(eps_status, car_fingerprint): valid_eps_status = [] if car_fingerprint == CAR.VOLT: @@ -49,6 +55,7 @@ def parse_gear_shifter(can_gear): STEER_THRESHOLD = 1.0 + STOCK_CONTROL_MSGS = { CAR.VOLT: [384, 715], # 384 = "ASCMLKASteeringCmd", 715 = "ASCMGasRegenCmd" CAR.CADILLAC_CT6: [], # Cadillac does not require ASCMs to be disconnected diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 7e04435802f370..0d51dbcee65b1b 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -183,7 +183,7 @@ def init_ui_buttons(self): btns.append(UIButton("","",0,"",2)) btns.append(UIButton("sound","SND",1,"",3)) btns.append(UIButton("","",0,"",4)) - btns.append(UIButton("","",0,"",5)) + btns.append(UIButton("gas","Gas",0,"",5)) return btns #BB update ui buttons diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 2bff2e74601b6d..d72f49887d57a1 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -472,7 +472,7 @@ def update(self, c): # TODO: more buttons? buttonEvents.append(be) ret.buttonEvents = buttonEvents - + ret.gasbuttonstatus = self.CS.cstm_btns.get_button_status("gas") # events # TODO: I don't like the way capnp does enums # These strings aren't checked at compile time diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 0366c2f2d68e08..6aa1afe886b4b7 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -83,6 +83,14 @@ def get_params(candidate, fingerprint): ret.steerKf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 # TODO: Prius seem to have very laggy actuators. Understand if it is lag or hysteresis ret.steerActuatorDelay = 0.25 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [3.6, 2.4, 1.5] + ret.longitudinalKiV = [0.54, 0.36] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 2.4, 1.5] + ret.longitudinalKiV = [0.54, 0.36] elif candidate in [CAR.RAV4, CAR.RAV4H]: stop_and_go = True if (candidate in CAR.RAV4H) else False @@ -94,6 +102,15 @@ def get_params(candidate, fingerprint): ret.wheelbase = 2.65 tire_stiffness_factor = 0.5533 ret.steerKf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] + elif candidate == CAR.COROLLA: stop_and_go = False ret.safetyParam = 100 # see conversion factor for STEER_TORQUE_EPS in dbc file @@ -103,6 +120,14 @@ def get_params(candidate, fingerprint): ret.mass = 2860 * CV.LB_TO_KG + std_cargo # mean between normal and hybrid ret.steerKpV, ret.steerKiV = [[0.2], [0.05]] ret.steerKf = 0.00003 # full torque for 20 deg at 80mph means 0.00007818594 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] elif candidate == CAR.LEXUS_RXH: stop_and_go = True @@ -113,6 +138,14 @@ def get_params(candidate, fingerprint): ret.mass = 4481 * CV.LB_TO_KG + std_cargo # mean between min and max ret.steerKpV, ret.steerKiV = [[0.6], [0.1]] ret.steerKf = 0.00006 # full torque for 10 deg at 80mph means 0.00007818594 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] elif candidate in [CAR.CHR, CAR.CHRH]: stop_and_go = True @@ -123,6 +156,14 @@ def get_params(candidate, fingerprint): ret.mass = 3300. * CV.LB_TO_KG + std_cargo ret.steerKpV, ret.steerKiV = [[0.723], [0.0428]] ret.steerKf = 0.00006 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] elif candidate in [CAR.CAMRY, CAR.CAMRYH]: stop_and_go = True @@ -133,6 +174,14 @@ def get_params(candidate, fingerprint): ret.mass = 3400 * CV.LB_TO_KG + std_cargo #mean between normal and hybrid ret.steerKpV, ret.steerKiV = [[0.6], [0.1]] ret.steerKf = 0.00006 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] elif candidate in [CAR.HIGHLANDER, CAR.HIGHLANDERH]: stop_and_go = True @@ -143,6 +192,14 @@ def get_params(candidate, fingerprint): ret.mass = 4607 * CV.LB_TO_KG + std_cargo #mean between normal and hybrid limited ret.steerKpV, ret.steerKiV = [[0.6], [0.05]] ret.steerKf = 0.00006 + if ret.enableGasInterceptor: + ret.gasMaxV = [0.7] + ret.longitudinalKpV = [1.2, 0.8, 0.5] + ret.longitudinalKiV = [0.18, 0.12] + else: + ret.gasMaxV = [0.2] + ret.longitudinalKpV = [3.6, 1.1, 1.0] + ret.longitudinalKiV = [0.5, 0.24] ret.steerRateCost = 1. ret.centerToFront = ret.wheelbase * 0.44 @@ -204,14 +261,7 @@ def get_params(candidate, fingerprint): return ret - if ret.enableGasInterceptor: - ret.gasMaxV = [0.7] - ret.longitudinalKpV = [1.2, 0.8, 0.5] - ret.longitudinalKiV = [0.18, 0.12] - else: - ret.gasMaxV = [0.2] - ret.longitudinalKpV = [3.6, 1.1, 1.0] - ret.longitudinalKiV = [0.5, 0.24] + return ret # returns a car.CarState diff --git a/selfdrive/ui/dashcam.h b/selfdrive/ui/dashcam.h new file mode 100644 index 00000000000000..9041c73f1e56f1 --- /dev/null +++ b/selfdrive/ui/dashcam.h @@ -0,0 +1,175 @@ +#include + +#define CAPTURE_STATE_NONE 0 +#define CAPTURE_STATE_CAPTURING 1 +#define CAPTURE_STATE_NOT_CAPTURING 2 +#define RECORD_INTERVAL 60 // Time in seconds to rotate recordings +#define RECORD_FILES 3 // Number of files to create before looping over + +int captureState = CAPTURE_STATE_NOT_CAPTURING; +int captureNum = 1; +int start_time = 0; +int elapsed_time = 0; // Time of current recording + +//TBD - need to implement locking current video +bool lock_current_video = false; // If true save the current video before rotating + +void stop_capture() { + if (captureState == CAPTURE_STATE_CAPTURING) { + //printf("Stop capturing screen\n"); + system("killall -SIGINT screenrecord"); + captureState = CAPTURE_STATE_NOT_CAPTURING; + } +} + +int get_time() { + // Get current time (in seconds) + + int iRet; + struct timeval tv; + int seconds = 0; + + iRet = gettimeofday(&tv,NULL); + if (iRet == 0) { + seconds = (int)tv.tv_sec; + } + return seconds; +} + +void start_capture() { + captureState = CAPTURE_STATE_CAPTURING; + char cmd[50] = ""; + char videos_dir[50] = "/sdcard/videos"; + + ////////////////////////////////// + // NOTE: make sure videos_dir folder exists on the device! + ////////////////////////////////// + struct stat st = {0}; + if (stat(videos_dir, &st) == -1) { + mkdir(videos_dir,0700); + } + + snprintf(cmd,sizeof(cmd),"screenrecord %s/video%d.mp4&",videos_dir,captureNum); + //printf("Capturing to file: %s\n",cmd); + start_time = get_time(); + system(cmd); + + if (captureNum >= RECORD_FILES) { + captureNum = 1; + } + else { + captureNum++; + } +} + +bool screen_button_clicked(int touch_x, int touch_y) { + if (touch_x >= 1660 && touch_x <= 1810) { + if (touch_y >= 885 && touch_y <= 1035) { + return true; + } + } + return false; +} + +void draw_date_time(UIState *s) { + // Draw the current date/time + + int rect_w = 465; + int rect_h = 80; + int rect_x = (1920-rect_w)/2; + int rect_y = (1080-rect_h-10); + + // Get local time to display + time_t t = time(NULL); + struct tm tm = *localtime(&t); + char now[50] = ""; + snprintf(now,sizeof(now),"%04d/%02d/%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, rect_x, rect_y, rect_w, rect_h, 15); + nvgStrokeColor(s->vg, nvgRGBA(255,255,255,80)); + nvgStrokeWidth(s->vg, 6); + nvgStroke(s->vg); + + nvgFontSize(s->vg, 60); + nvgFontFace(s->vg, "sans-semibold"); + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); + nvgText(s->vg,rect_x+17,rect_y+55,now,NULL); +} + +static void rotate_video() { + // Overwrite the existing video (if needed) + elapsed_time = 0; + stop_capture(); + captureState = CAPTURE_STATE_CAPTURING; + start_capture(); +} + +static void screen_draw_button(UIState *s, int touch_x, int touch_y) { + // Set button to bottom left of screen + if (s->vision_connected && s->plus_state == 0) { + + int btn_w = 150; + int btn_h = 150; + int btn_x = 1920 - btn_w; + int btn_y = 1080 - btn_h; + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, btn_x-110, btn_y-45, btn_w, btn_h, 100); + nvgStrokeColor(s->vg, nvgRGBA(255,255,255,80)); + nvgStrokeWidth(s->vg, 6); + nvgStroke(s->vg); + + nvgFontSize(s->vg, 70); + + if (captureState == CAPTURE_STATE_CAPTURING) { + NVGcolor fillColor = nvgRGBA(255,0,0,150); + nvgFillColor(s->vg, fillColor); + nvgFill(s->vg); + nvgFillColor(s->vg, nvgRGBA(255,255,255,200)); + } + else { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); + } + nvgText(s->vg,btn_x-88,btn_y+50,"REC",NULL); + } + + if (captureState == CAPTURE_STATE_CAPTURING) { + draw_date_time(s); + + elapsed_time = get_time() - start_time; + + if (elapsed_time >= RECORD_INTERVAL) { + rotate_video(); + } + } +} + +void screen_toggle_record_state() { + if (captureState == CAPTURE_STATE_CAPTURING) { + stop_capture(); + } + else { + //captureState = CAPTURE_STATE_CAPTURING; + start_capture(); + } +} + +void screen_capture( UIState *s, int touch_x, int touch_y ) { + screen_draw_button(s, touch_x, touch_y); + if (screen_button_clicked(touch_x,touch_y)) { + screen_toggle_record_state(); + +/* + if (captureState == CAPTURE_STATE_CAPTURING) { + start_capture(); + } + else if (captureState == CAPTURE_STATE_NOT_CAPTURING) { + stop_capture(); + } +*/ + } + else if (!s->vision_connected) { + // Assume car is not in drive so stop recording + stop_capture(); + } +} diff --git a/selfdrive/ui/ui.c b/selfdrive/ui/ui.c index c5f3b540378c55..9a316e077b7c16 100644 --- a/selfdrive/ui/ui.c +++ b/selfdrive/ui/ui.c @@ -240,7 +240,7 @@ typedef struct UIState { float light_sensor; } UIState; - +#include "dashcam.h" #include "bbui.h" static int last_brightness = -1;