      // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
      if (!ignition && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
        panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
      }
  #endif
  
      // clear VIN, CarParams, and set new safety on car start
      if (ignition && !ignition_last) {
        params.clearAll(CLEAR_ON_IGNITION_ON);
  
 
</s> remove     // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
    if (!ignition && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
      panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
 </s> add void send_peripheral_state(PubMaster *pm, Panda *panda) {
  health_t pandaState = panda->get_state();

  // build msg
  MessageBuilder msg;
  auto evt = msg.initEvent();
  evt.setValid(panda->comms_healthy);

  auto ps = evt.initPeripheralState();
  ps.setPandaType(panda->hw_type);

  if (Hardware::TICI()) {
    double read_time = millis_since_boot();
    ps.setVoltage(std::atoi(util::read_file("/sys/class/hwmon/hwmon1/in1_input").c_str()));
    ps.setCurrent(std::atoi(util::read_file("/sys/class/hwmon/hwmon1/curr1_input").c_str()));
    read_time = millis_since_boot() - read_time;
    if (read_time > 50) {
      LOGW("reading hwmon took %lfms", read_time); </s> remove     if (ignition) {
      no_ignition_cnt = 0;
    } else {
      no_ignition_cnt += 1;
    }
 </s> add   // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
  if (!ignition && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
    panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
  }
#endif </s> remove #ifndef __x86_64__
    bool power_save_desired = !ignition;
    if (pandaState.power_save_enabled != power_save_desired) {
      panda->set_power_saving(power_save_desired);
 </s> add   // build msg
  MessageBuilder msg;
  auto evt = msg.initEvent();
  evt.setValid(panda->comms_healthy);

  auto ps = evt.initPandaState();
  ps.setUptime(pandaState.uptime);
  ps.setIgnitionLine(pandaState.ignition_line);
  ps.setIgnitionCan(pandaState.ignition_can);
  ps.setControlsAllowed(pandaState.controls_allowed);
  ps.setGasInterceptorDetected(pandaState.gas_interceptor_detected);
  ps.setCanRxErrs(pandaState.can_rx_errs);
  ps.setCanSendErrs(pandaState.can_send_errs);
  ps.setCanFwdErrs(pandaState.can_fwd_errs);
  ps.setGmlanSendErrs(pandaState.gmlan_send_errs);
  ps.setPandaType(panda->hw_type);
  ps.setSafetyModel(cereal::CarParams::SafetyModel(pandaState.safety_model));
  ps.setSafetyParam(pandaState.safety_param);
  ps.setFaultStatus(cereal::PandaState::FaultStatus(pandaState.fault_status));
  ps.setPowerSaveEnabled((bool)(pandaState.power_save_enabled));
  ps.setHeartbeatLost((bool)(pandaState.heartbeat_lost));
  ps.setHarnessStatus(cereal::PandaState::HarnessStatus(pandaState.car_harness_status));

  // Convert faults bitset to capnp list
  std::bitset<sizeof(pandaState.faults) * 8> fault_bits(pandaState.faults);
  auto faults = ps.initFaults(fault_bits.count());

  size_t i = 0;
  for (size_t f = size_t(cereal::PandaState::FaultType::RELAY_MALFUNCTION);
      f <= size_t(cereal::PandaState::FaultType::INTERRUPT_RATE_TICK); f++) {
    if (fault_bits.test(f)) {
      faults.set(i, cereal::PandaState::FaultType(f));
      i++; </s> remove     if (spoofing_started) {
      pandaState.ignition_line = 1;
    }
 </s> add   // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node
  if (pandaState.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) {
    panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
  } </s> remove     // Write to rtc once per minute when no ignition present
    if ((panda->has_rtc) && !ignition && (no_ignition_cnt % 120 == 1)) {
      // Write time to RTC if it looks reasonable
      setenv("TZ","UTC",1);
      struct tm sys_time = util::get_time();

      if (util::time_valid(sys_time)) {
        struct tm rtc_time = panda->get_rtc();
        double seconds = difftime(mktime(&rtc_time), mktime(&sys_time));

        if (std::abs(seconds) > 1.1) {
          panda->set_rtc(sys_time);
          LOGW("Updating panda RTC. dt = %.2f System: %s RTC: %s",
               seconds, get_time_str(sys_time).c_str(), get_time_str(rtc_time).c_str());
        }
      }
    }

 </s> add 
  } else {
    ps.setVoltage(pandaState.voltage);
    ps.setCurrent(pandaState.current);
  }

  uint16_t fan_speed_rpm = panda->get_fan_speed();
  ps.setUsbPowerMode(cereal::PeripheralState::UsbPowerMode(pandaState.usb_power_mode));
  ps.setFanSpeedRpm(fan_speed_rpm);

  pm->send("peripheralState", msg);
}

void panda_state_thread(PubMaster *pm, Panda * peripheral_panda, Panda *panda, bool spoofing_started) {
  Params params;
  bool ignition_last = false;

  LOGD("start panda state thread");

  // run at 2hz
  while (!do_exit && panda->connected) {
    send_peripheral_state(pm, peripheral_panda);
    ignition = send_panda_state(pm, panda, spoofing_started);
      // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
      if (!ignition && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) {
        panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT);
      }
  } else {
    ps.setVoltage(pandaState.voltage);
    ps.setCurrent(pandaState.current);
  }

  uint16_t fan_speed_rpm = panda->get_fan_speed();
  ps.setUsbPowerMode(cereal::PeripheralState::UsbPowerMode(pandaState.usb_power_mode));
  ps.setFanSpeedRpm(fan_speed_rpm);

  pm->send("peripheralState", msg);
}

void panda_state_thread(PubMaster *pm, Panda * peripheral_panda, Panda *panda, bool spoofing_started) {
  Params params;
  bool ignition_last = false;

  LOGD("start panda state thread");

  // run at 2hz
  while (!do_exit && panda->connected) {
    send_peripheral_state(pm, peripheral_panda);
    ignition = send_panda_state(pm, panda, spoofing_started);
  
      // clear VIN, CarParams, and set new safety on car start
      if (ignition && !ignition_last) {
        params.clearAll(CLEAR_ON_IGNITION_ON);
  
keep keep keep keep replace keep keep keep keep keep
 Split pandaState into peripheralState and pandaState (#22385)

* publish peripheralState from boardd

* refactor consumers

* rename thread

* peripheralState has panda type too

* add to process replay

* fix device build

* properly remove hardware unsupported alert

* latest peripheralState

* remove pandaState from thermal_monitor

* put that back

* add back harness check

* fix cloudlog

* needs pandaState

* Update selfdrive/thermald/tests/test_power_monitoring.py

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>

* dont conflate

* Update selfdrive/thermald/tests/test_power_monitoring.py

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>

* pigeon is peripheral

* cleanup

* less global

* comment

* move rtc to peripheral_control_thread

* better diff?

* whitespace

* get msg

* bump cereal

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> 
selfdrive/boardd/boardd.cc