      } else if (!ignition && ignition_last) {
        params.clearAll(CLEAR_ON_IGNITION_OFF);
      }
  
      // 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());
          }
        }
      }
  
      ignition_last = ignition;
      uint16_t fan_speed_rpm = panda->get_fan_speed();
  
      // build msg
      MessageBuilder msg;
 
</s> remove     uint16_t fan_speed_rpm = panda->get_fan_speed();

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

    auto ps = evt.initPandaState();
    ps.setUptime(pandaState.uptime);

    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);
      }
    } else {
      ps.setVoltage(pandaState.voltage);
      ps.setCurrent(pandaState.current);
    }
 </s> add  </s> remove #endif
 </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); </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++;
      } else if (!ignition && ignition_last) {
        params.clearAll(CLEAR_ON_IGNITION_OFF);
      }
  


















      ignition_last = ignition;
      uint16_t fan_speed_rpm = panda->get_fan_speed();
  
      // build msg
      MessageBuilder msg;
keep keep keep keep replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace replace 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