|  |  | @ -39,6 +39,7 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | using namespace std::chrono_literals; |  |  |  | using namespace std::chrono_literals; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | std::atomic<bool> ignition(false); |  |  |  | std::atomic<bool> ignition(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | std::atomic<bool> pigeon_active(false); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | ExitHandler do_exit; |  |  |  | ExitHandler do_exit; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -268,16 +269,16 @@ bool send_panda_state(PubMaster *pm, Panda *panda, bool spoofing_started) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); |  |  |  |     panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   bool ignition = ((pandaState.ignition_line != 0) || (pandaState.ignition_can != 0)); |  |  |  |   bool ignition_local = ((pandaState.ignition_line != 0) || (pandaState.ignition_can != 0)); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #ifndef __x86_64__ |  |  |  | #ifndef __x86_64__ | 
			
		
	
		
		
			
				
					
					|  |  |  |   bool power_save_desired = !ignition; |  |  |  |   bool power_save_desired = !ignition_local && !pigeon_active; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   if (pandaState.power_save_enabled != power_save_desired) { |  |  |  |   if (pandaState.power_save_enabled != power_save_desired) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     panda->set_power_saving(power_save_desired); |  |  |  |     panda->set_power_saving(power_save_desired); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect
 |  |  |  |   // 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))) { |  |  |  |   if (!ignition_local && (pandaState.safety_model != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); |  |  |  |     panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | #endif |  |  |  | #endif | 
			
		
	
	
		
		
			
				
					|  |  | @ -320,7 +321,7 @@ bool send_panda_state(PubMaster *pm, Panda *panda, bool spoofing_started) { | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   pm->send("pandaStates", msg); |  |  |  |   pm->send("pandaStates", msg); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   return ignition; |  |  |  |   return ignition_local; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | void send_peripheral_state(PubMaster *pm, Panda *panda) { |  |  |  | void send_peripheral_state(PubMaster *pm, Panda *panda) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -498,10 +499,11 @@ void pigeon_thread(Panda *panda) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   while (!do_exit && panda->connected) { |  |  |  |   while (!do_exit && panda->connected) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     bool need_reset = false; |  |  |  |     bool need_reset = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     bool ignition_local = ignition; | 
			
		
	
		
		
			
				
					
					|  |  |  |     std::string recv = pigeon->receive(); |  |  |  |     std::string recv = pigeon->receive(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Parse message header
 |  |  |  |     // Parse message header
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (ignition && recv.length() >= 3) { |  |  |  |     if (ignition_local && recv.length() >= 3) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       if (recv[0] == (char)ublox::PREAMBLE1 && recv[1] == (char)ublox::PREAMBLE2) { |  |  |  |       if (recv[0] == (char)ublox::PREAMBLE1 && recv[1] == (char)ublox::PREAMBLE2) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         const char msg_cls = recv[2]; |  |  |  |         const char msg_cls = recv[2]; | 
			
		
	
		
		
			
				
					
					|  |  |  |         uint64_t t = nanos_since_boot(); |  |  |  |         uint64_t t = nanos_since_boot(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -514,7 +516,7 @@ void pigeon_thread(Panda *panda) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Check based on message frequency
 |  |  |  |     // Check based on message frequency
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     for (const auto& [msg_cls, max_dt] : cls_max_dt) { |  |  |  |     for (const auto& [msg_cls, max_dt] : cls_max_dt) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       int64_t dt = (int64_t)nanos_since_boot() - (int64_t)last_recv_time[msg_cls]; |  |  |  |       int64_t dt = (int64_t)nanos_since_boot() - (int64_t)last_recv_time[msg_cls]; | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (ignition_last && ignition && dt > max_dt) { |  |  |  |       if (ignition_last && ignition_local && dt > max_dt) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         LOGD("ublox receive timeout, msg class: 0x%02x, dt %llu", msg_cls, dt); |  |  |  |         LOGD("ublox receive timeout, msg class: 0x%02x, dt %llu", msg_cls, dt); | 
			
		
	
		
		
			
				
					
					|  |  |  |         // TODO: turn on reset after verification of logs
 |  |  |  |         // TODO: turn on reset after verification of logs
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // need_reset = true;
 |  |  |  |         // need_reset = true;
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -522,7 +524,7 @@ void pigeon_thread(Panda *panda) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // Check based on null bytes
 |  |  |  |     // Check based on null bytes
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (ignition && recv.length() > 0 && recv[0] == (char)0x00) { |  |  |  |     if (ignition_local && recv.length() > 0 && recv[0] == (char)0x00) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       need_reset = true; |  |  |  |       need_reset = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |       LOGW("received invalid ublox message while onroad, resetting panda GPS"); |  |  |  |       LOGW("received invalid ublox message while onroad, resetting panda GPS"); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -533,7 +535,8 @@ void pigeon_thread(Panda *panda) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // init pigeon on rising ignition edge
 |  |  |  |     // init pigeon on rising ignition edge
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // since it was turned off in low power mode
 |  |  |  |     // since it was turned off in low power mode
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if((ignition && !ignition_last) || need_reset) { |  |  |  |     if((ignition_local && !ignition_last) || need_reset) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       pigeon_active = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |       pigeon->init(); |  |  |  |       pigeon->init(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       // Set receive times to current time
 |  |  |  |       // Set receive times to current time
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -541,14 +544,15 @@ void pigeon_thread(Panda *panda) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       for (const auto& [msg_cls, dt] : cls_max_dt) { |  |  |  |       for (const auto& [msg_cls, dt] : cls_max_dt) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         last_recv_time[msg_cls] = t; |  |  |  |         last_recv_time[msg_cls] = t; | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (!ignition && ignition_last) { |  |  |  |     } else if (!ignition_local && ignition_last) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       // power off on falling edge of ignition
 |  |  |  |       // power off on falling edge of ignition
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       LOGD("powering off pigeon\n"); |  |  |  |       LOGD("powering off pigeon\n"); | 
			
		
	
		
		
			
				
					
					|  |  |  |       pigeon->stop(); |  |  |  |       pigeon->stop(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       pigeon->set_power(false); |  |  |  |       pigeon->set_power(false); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       pigeon_active = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     ignition_last = ignition; |  |  |  |     ignition_last = ignition_local; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // 10ms - 100 Hz
 |  |  |  |     // 10ms - 100 Hz
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     util::sleep_for(10); |  |  |  |     util::sleep_for(10); | 
			
		
	
	
		
		
			
				
					|  |  | 
 |