@ -40,6 +40,7 @@ std::atomic<bool> ignition(false);
ExitHandler do_exit ;
std : : string get_time_str ( const struct tm & time ) {
char s [ 30 ] = { ' \0 ' } ;
std : : strftime ( s , std : : size ( s ) , " %Y-%m-%d %H:%M:%S " , & time ) ;
@ -143,7 +144,7 @@ Panda *usb_connect() {
// power on charging, only the first time. Panda can also change mode and it causes a brief disconneciton
# ifndef __x86_64__
static std : : once_flag connected_once ;
std : : call_once ( connected_once , & Panda : : set_usb_power_mode , panda , cereal : : Panda State : : UsbPowerMode : : CDP ) ;
std : : call_once ( connected_once , & Panda : : set_usb_power_mode , panda , cereal : : Peripheral State : : UsbPowerMode : : CDP ) ;
# endif
if ( panda - > has_rtc ) {
@ -234,6 +235,13 @@ void can_recv_thread(Panda *panda) {
}
}
void send_empty_peripheral_state ( PubMaster * pm ) {
MessageBuilder msg ;
auto peripheralState = msg . initEvent ( ) . initPeripheralState ( ) ;
peripheralState . setPandaType ( cereal : : PandaState : : PandaType : : UNKNOWN ) ;
pm - > send ( " peripheralState " , msg ) ;
}
void send_empty_panda_state ( PubMaster * pm ) {
MessageBuilder msg ;
auto pandaState = msg . initEvent ( ) . initPandaState ( ) ;
@ -241,14 +249,7 @@ void send_empty_panda_state(PubMaster *pm) {
pm - > send ( " pandaState " , msg ) ;
}
void panda_state_thread ( PubMaster * pm , Panda * panda , bool spoofing_started ) {
LOGD ( " start panda state thread " ) ;
uint32_t no_ignition_cnt = 0 ;
bool ignition_last = false ;
Params params = Params ( ) ;
// run at 2hz
while ( ! do_exit & & panda - > connected ) {
bool send_panda_state ( PubMaster * pm , Panda * panda , bool spoofing_started ) {
health_t pandaState = panda - > get_state ( ) ;
if ( spoofing_started ) {
@ -260,13 +261,7 @@ void panda_state_thread(PubMaster *pm, Panda *panda, bool spoofing_started) {
panda - > set_safety_model ( cereal : : CarParams : : SafetyModel : : NO_OUTPUT ) ;
}
ignition = ( ( pandaState . ignition_line ! = 0 ) | | ( pandaState . ignition_can ! = 0 ) ) ;
if ( ignition ) {
no_ignition_cnt = 0 ;
} else {
no_ignition_cnt + = 1 ;
}
bool ignition = ( ( pandaState . ignition_line ! = 0 ) | | ( pandaState . ignition_can ! = 0 ) ) ;
# ifndef __x86_64__
bool power_save_desired = ! ignition ;
@ -280,41 +275,6 @@ void panda_state_thread(PubMaster *pm, Panda *panda, bool spoofing_started) {
}
# endif
// clear VIN, CarParams, and set new safety on car start
if ( ignition & & ! ignition_last ) {
params . clearAll ( CLEAR_ON_IGNITION_ON ) ;
if ( ! safety_setter_thread_running ) {
safety_setter_thread_running = true ;
std : : thread ( safety_setter_thread , panda ) . detach ( ) ;
} else {
LOGW ( " Safety setter thread already running " ) ;
}
} 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 ;
auto evt = msg . initEvent ( ) ;
@ -322,34 +282,17 @@ void panda_state_thread(PubMaster *pm, Panda *panda, bool spoofing_started) {
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 ) ;
}
ps . setIgnitionLine ( pandaState . ignition_line ) ;
ps . setIgnitionCan ( pandaState . ignition_can ) ;
ps . setControlsAllowed ( pandaState . controls_allowed ) ;
ps . setGasInterceptorDetected ( pandaState . gas_interceptor_detected ) ;
ps . setHasGps ( true ) ;
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 . setUsbPowerMode ( cereal : : PandaState : : UsbPowerMode ( pandaState . usb_power_mode ) ) ;
ps . setSafetyModel ( cereal : : CarParams : : SafetyModel ( pandaState . safety_model ) ) ;
ps . setSafetyParam ( pandaState . safety_param ) ;
ps . setFanSpeedRpm ( fan_speed_rpm ) ;
ps . setFaultStatus ( cereal : : PandaState : : FaultStatus ( pandaState . fault_status ) ) ;
ps . setPowerSaveEnabled ( ( bool ) ( pandaState . power_save_enabled ) ) ;
ps . setHeartbeatLost ( ( bool ) ( pandaState . heartbeat_lost ) ) ;
@ -368,13 +311,76 @@ void panda_state_thread(PubMaster *pm, Panda *panda, bool spoofing_started) {
}
}
pm - > send ( " pandaState " , msg ) ;
return ignition ;
}
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 ) ;
}
} 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 ) ;
if ( ! safety_setter_thread_running ) {
safety_setter_thread_running = true ;
std : : thread ( safety_setter_thread , panda ) . detach ( ) ;
} else {
LOGW ( " Safety setter thread already running " ) ;
}
} else if ( ! ignition & & ignition_last ) {
params . clearAll ( CLEAR_ON_IGNITION_OFF ) ;
}
ignition_last = ignition ;
panda - > send_heartbeat ( ) ;
util : : sleep_for ( 500 ) ;
}
}
void hardware_control_thread ( Panda * panda ) {
LOGD ( " start hardware control thread " ) ;
void peripheral_control_thread ( Panda * panda ) {
LOGD ( " start peripheral control thread " ) ;
SubMaster sm ( { " deviceState " , " driverCameraState " } ) ;
uint64_t last_front_frame_t = 0 ;
@ -395,10 +401,10 @@ void hardware_control_thread(Panda *panda) {
bool charging_disabled = sm [ " deviceState " ] . getDeviceState ( ) . getChargingDisabled ( ) ;
if ( charging_disabled ! = prev_charging_disabled ) {
if ( charging_disabled ) {
panda - > set_usb_power_mode ( cereal : : Panda State : : UsbPowerMode : : CLIENT ) ;
panda - > set_usb_power_mode ( cereal : : Peripheral State : : UsbPowerMode : : CLIENT ) ;
LOGW ( " TURN OFF CHARGING! \n " ) ;
} else {
panda - > set_usb_power_mode ( cereal : : Panda State : : UsbPowerMode : : CDP ) ;
panda - > set_usb_power_mode ( cereal : : Peripheral State : : UsbPowerMode : : CDP ) ;
LOGW ( " TURN ON CHARGING! \n " ) ;
}
prev_charging_disabled = charging_disabled ;
@ -444,6 +450,23 @@ void hardware_control_thread(Panda *panda) {
prev_ir_pwr = ir_pwr ;
}
// Write to rtc once per minute when no ignition present
if ( ( panda - > has_rtc ) & & ! 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 ( ) ) ;
}
}
}
}
}
@ -538,14 +561,16 @@ int main() {
LOG ( " set affinity returns %d " , err ) ;
LOGW ( " attempting to connect " ) ;
PubMaster pm ( { " pandaState " } ) ;
PubMaster pm ( { " pandaState " , " peripheralState " } ) ;
while ( ! do_exit ) {
Panda * panda = usb_connect ( ) ;
Panda * peripheral_panda = panda ;
// Send empty pandaState and try again
if ( panda = = nullptr ) {
// Send empty pandaState & peripheralState and try again
if ( panda = = nullptr | | peripheral_panda = = nullptr ) {
send_empty_panda_state ( & pm ) ;
send_empty_peripheral_state ( & pm ) ;
util : : sleep_for ( 500 ) ;
continue ;
}
@ -553,11 +578,12 @@ int main() {
LOGW ( " connected to board " ) ;
std : : vector < std : : thread > threads ;
threads . emplace_back ( panda_state_thread , & pm , panda , getenv ( " STARTED " ) ! = nullptr ) ;
threads . emplace_back ( panda_state_thread , & pm , peripheral_panda , panda , getenv ( " STARTED " ) ! = nullptr ) ;
threads . emplace_back ( peripheral_control_thread , peripheral_panda ) ;
threads . emplace_back ( pigeon_thread , peripheral_panda ) ;
threads . emplace_back ( can_send_thread , panda , getenv ( " FAKESEND " ) ! = nullptr ) ;
threads . emplace_back ( can_recv_thread , panda ) ;
threads . emplace_back ( hardware_control_thread , panda ) ;
threads . emplace_back ( pigeon_thread , panda ) ;
for ( auto & t : threads ) t . join ( ) ;