|  |  |  | #include "selfdrive/pandad/pandad.h"
 | 
					
						
							|  |  |  | #include "cereal/messaging/messaging.h"
 | 
					
						
							|  |  |  | #include "common/swaglog.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PandaSafety::configureSafetyMode() {
 | 
					
						
							|  |  |  |   bool is_onroad = params_.getBool("IsOnroad");
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (is_onroad && !safety_configured_) {
 | 
					
						
							|  |  |  |     updateMultiplexingMode();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto car_params = fetchCarParams();
 | 
					
						
							|  |  |  |     if (!car_params.empty()) {
 | 
					
						
							|  |  |  |       LOGW("got %lu bytes CarParams", car_params.size());
 | 
					
						
							|  |  |  |       setSafetyMode(car_params);
 | 
					
						
							|  |  |  |       safety_configured_ = true;
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |   } else if (!is_onroad) {
 | 
					
						
							|  |  |  |     initialized_ = false;
 | 
					
						
							|  |  |  |     safety_configured_ = false;
 | 
					
						
							|  |  |  |     log_once_ = false;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PandaSafety::updateMultiplexingMode() {
 | 
					
						
							|  |  |  |   // Initialize to ELM327 without OBD multiplexing for initial fingerprinting
 | 
					
						
							|  |  |  |   if (!initialized_) {
 | 
					
						
							|  |  |  |     prev_obd_multiplexing_ = false;
 | 
					
						
							|  |  |  |     for (int i = 0; i < pandas_.size(); ++i) {
 | 
					
						
							|  |  |  |       pandas_[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, 1U);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     initialized_ = true;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Switch between multiplexing modes based on the OBD multiplexing request
 | 
					
						
							|  |  |  |   bool obd_multiplexing_requested = params_.getBool("ObdMultiplexingEnabled");
 | 
					
						
							|  |  |  |   if (obd_multiplexing_requested != prev_obd_multiplexing_) {
 | 
					
						
							|  |  |  |     for (int i = 0; i < pandas_.size(); ++i) {
 | 
					
						
							|  |  |  |       const uint16_t safety_param = (i > 0 || !obd_multiplexing_requested) ? 1U : 0U;
 | 
					
						
							|  |  |  |       pandas_[i]->set_safety_model(cereal::CarParams::SafetyModel::ELM327, safety_param);
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  |     prev_obd_multiplexing_ = obd_multiplexing_requested;
 | 
					
						
							|  |  |  |     params_.putBool("ObdMultiplexingChanged", true);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string PandaSafety::fetchCarParams() {
 | 
					
						
							|  |  |  |   if (!params_.getBool("FirmwareQueryDone")) {
 | 
					
						
							|  |  |  |     return {};
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!log_once_) {
 | 
					
						
							|  |  |  |     LOGW("Finished FW query, Waiting for params to set safety model");
 | 
					
						
							|  |  |  |     log_once_ = true;
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!params_.getBool("ControlsReady")) {
 | 
					
						
							|  |  |  |     return {};
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  |   return params_.get("CarParams");
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PandaSafety::setSafetyMode(const std::string ¶ms_string) {
 | 
					
						
							|  |  |  |   AlignedBuffer aligned_buf;
 | 
					
						
							|  |  |  |   capnp::FlatArrayMessageReader cmsg(aligned_buf.align(params_string.data(), params_string.size()));
 | 
					
						
							|  |  |  |   cereal::CarParams::Reader car_params = cmsg.getRoot<cereal::CarParams>();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   auto safety_configs = car_params.getSafetyConfigs();
 | 
					
						
							|  |  |  |   uint16_t alternative_experience = car_params.getAlternativeExperience();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (int i = 0; i < pandas_.size(); ++i) {
 | 
					
						
							|  |  |  |     // Default to SILENT safety model if not specified
 | 
					
						
							|  |  |  |     cereal::CarParams::SafetyModel safety_model = cereal::CarParams::SafetyModel::SILENT;
 | 
					
						
							|  |  |  |     uint16_t safety_param = 0U;
 | 
					
						
							|  |  |  |     if (i < safety_configs.size()) {
 | 
					
						
							|  |  |  |       safety_model = safety_configs[i].getSafetyModel();
 | 
					
						
							|  |  |  |       safety_param = safety_configs[i].getSafetyParam();
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LOGW("Panda %d: setting safety model: %d, param: %d, alternative experience: %d", i, (int)safety_model, safety_param, alternative_experience);
 | 
					
						
							|  |  |  |     pandas_[i]->set_alternative_experience(alternative_experience);
 | 
					
						
							|  |  |  |     pandas_[i]->set_safety_model(safety_model, safety_param);
 | 
					
						
							|  |  |  |   }
 | 
					
						
							|  |  |  | }
 |