| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -6,6 +6,7 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "state_machine.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "ADBMS_Abstraction.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "AMS_HighLevel.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "PWM_control.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "TMP1075.h"
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -89,6 +90,138 @@ void sm_update(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.target_state = state.current_state;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_handle_ams_in(const uint8_t *data){  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CAN_timer = HAL_GetTick() + CAN_TIMEOUT;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  switch (data[0]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x00:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state != STATE_INACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(255);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x01:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.target_state == STATE_INACTIVE || state.target_state == STATE_DISCHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_PRECHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      } else if (state.target_state == STATE_ACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_READY;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x02:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state == STATE_READY || state.current_state == STATE_ACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(data[1]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_ACTIVE;        // READY -> ACTIVE
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xF0:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state == STATE_INACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_CHARGING_PRECHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #warning implement this
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xF1:                                    // EEPROM
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xFF:                                    // EMERGENCY SHUTDOWN
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.current_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.target_state = STATE_ERROR;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_precharge_discharge_manager(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_PRECHARGE && state.target_state == STATE_PRECHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = HAL_GetTick() + PRECHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_PRECHARGE && precharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_READY;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_CHARGING_PRECHARGE && state.target_state == STATE_CHARGING_PRECHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = HAL_GetTick() + PRECHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_CHARGING_PRECHARGE && precharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_CHARGING;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_DISCHARGE && state.target_state == STATE_DISCHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    discharge_timer = HAL_GetTick() + DISCHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_DISCHARGE && discharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_INACTIVE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    discharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_calibrate_powerground(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (powerground_calibration_stage != 4 && state.current_state == STATE_READY){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    switch (powerground_calibration_stage) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 0:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        powerground_calibration_timer = HAL_GetTick() + 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        powerground_calibration_stage = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 1:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_timer = HAL_GetTick() + 2000;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 2;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          PWM_powerground_control(100);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 2:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_timer = HAL_GetTick() + 1000;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 3;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 3:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 4;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#warning TODO: add error checking for everything here
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_check_errors(){  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.temperature_error = (error_data.error_sources & (1 << 0) || error_data.error_sources & (1 << 1) || error_data.error_sources & (1 << 4)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.voltage_error = (error_data.error_sources & (1 << 2)|| error_data.error_sources & (1 << 3)|| error_data.error_sources & (1 << 5) || RELAY_BAT_SIDE_VOLTAGE < 30000) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.bms_timeout = (error_data.error_sources & (1 << 7)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.bms_fault = (error_data.error_sources & (1 << 8) || error_data.error_sources & (1 << 10) || error_data.error_sources & (1 << 9)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //SEK_EEPROM_ERR: state.error_type.eeprom_error = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //state.error_type.current_error = (powerground_status > 10 && CURRENT_MEASUREMENT < 500) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.current_sensor_missing = (!CURRENT_MEASUREMENT_ON) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.voltage_missing = (RELAY_BAT_SIDE_VOLTAGE < 1000) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (  state.error_type.current_error == 1 || state.error_type.current_sensor_missing == 1 || //state.error_type.eeprom_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.error_type.state_transition_fail == 1 || state.error_type.temperature_error == 1 || state.error_type.voltage_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.error_type.voltage_missing == 1 || state.error_type.bms_fault == 1 || state.error_type.bms_timeout == 1){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (state.current_state != STATE_INACTIVE && state.current_state != STATE_ERROR)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.current_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_ERROR;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    PWM_powerground_control(255);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_ERROR){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.target_state = STATE_INACTIVE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  sm_set_error_source();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_set_error_source(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.bms_timeout << 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.bms_fault << 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.temperature_error << 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.current_error << 3);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.current_sensor_missing << 4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.voltage_error << 5);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.voltage_missing << 6);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.state_transition_fail << 7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				State sm_update_inactive(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  switch (state.target_state) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case STATE_PRECHARGE:
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -162,6 +295,8 @@ State sm_update_charging(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case STATE_DISCHARGE:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    default:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      //amsConfigBalancing((1 << 7), 0xF);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      //amsStartBalancing(0);e
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return STATE_CHARGING;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -236,135 +371,6 @@ void sm_check_battery_temperature(int8_t *id, int16_t *temp){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_precharge_discharge_manager(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_PRECHARGE && state.target_state == STATE_PRECHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = HAL_GetTick() + PRECHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_PRECHARGE && precharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_READY;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_CHARGING_PRECHARGE && state.target_state == STATE_CHARGING_PRECHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = HAL_GetTick() + PRECHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_CHARGING_PRECHARGE && precharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_CHARGING;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    precharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (state.current_state != STATE_DISCHARGE && state.target_state == STATE_DISCHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    discharge_timer = HAL_GetTick() + DISCHARGE_DURATION;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_DISCHARGE && discharge_timer < HAL_GetTick()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_INACTIVE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    discharge_timer = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_calibrate_powerground(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (powerground_calibration_stage != 4 && state.current_state == STATE_READY){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    switch (powerground_calibration_stage) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 0:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        powerground_calibration_timer = HAL_GetTick() + 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        powerground_calibration_stage = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 1:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_timer = HAL_GetTick() + 2000;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 2;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          PWM_powerground_control(100);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 2:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_timer = HAL_GetTick() + 1000;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 3;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      case 3:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (powerground_calibration_timer < HAL_GetTick()){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          powerground_calibration_stage = 4;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_handle_ams_in(const uint8_t *data){  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CAN_timer = HAL_GetTick() + CAN_TIMEOUT;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  switch (data[0]) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x00:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state != STATE_INACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(255);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x01:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.target_state == STATE_INACTIVE || state.target_state == STATE_DISCHARGE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_PRECHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      } else if (state.target_state == STATE_ACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_READY;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0x02:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state == STATE_READY || state.current_state == STATE_ACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        PWM_powerground_control(data[1]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_ACTIVE;        // READY -> ACTIVE
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xF0:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (state.current_state == STATE_INACTIVE){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.target_state = STATE_CHARGING_PRECHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    #warning implement this
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xF1:                                    // EEPROM
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case 0xFF:                                    // EMERGENCY SHUTDOWN
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.current_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.target_state = STATE_ERROR;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_set_error(ErrorKind error_kind, bool is_errored){}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/*
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				bool sm_is_errored(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return  state.error_type.current_error == 1 || state.error_type.current_sensor_missing == 1 || //state.error_type.eeprom_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          state.error_type.state_transition_fail == 1 || state.error_type.temperature_error == 1 || state.error_type.voltage_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          state.error_type.voltage_missing == 1 || state.error_type.bms_fault == 1 || state.error_type.bms_timeout == 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				*/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#warning TODO: add error checking for everything here
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_check_errors(){  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.temperature_error = (error_data.error_sources & (1 << 0) || error_data.error_sources & (1 << 1) || error_data.error_sources & (1 << 4)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.voltage_error = (error_data.error_sources & (1 << 2)|| error_data.error_sources & (1 << 3)|| error_data.error_sources & (1 << 5) || RELAY_BAT_SIDE_VOLTAGE < 30000) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.bms_timeout = (error_data.error_sources & (1 << 7)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.bms_fault = (error_data.error_sources & (1 << 8) || error_data.error_sources & (1 << 10) || error_data.error_sources & (1 << 9)) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //SEK_EEPROM_ERR: state.error_type.eeprom_error = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  //state.error_type.current_error = (powerground_status > 10 && CURRENT_MEASUREMENT < 500) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.current_sensor_missing = (!CURRENT_MEASUREMENT_ON) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_type.voltage_missing = (RELAY_BAT_SIDE_VOLTAGE < 1000) ? 1 : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (  state.error_type.current_error == 1 || state.error_type.current_sensor_missing == 1 || //state.error_type.eeprom_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.error_type.state_transition_fail == 1 || state.error_type.temperature_error == 1 || state.error_type.voltage_error == 1 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        state.error_type.voltage_missing == 1 || state.error_type.bms_fault == 1 || state.error_type.bms_timeout == 1){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (state.current_state != STATE_INACTIVE && state.current_state != STATE_ERROR)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.current_state = STATE_DISCHARGE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    state.target_state = STATE_ERROR;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    PWM_powerground_control(255);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  } else if (state.current_state == STATE_ERROR){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      state.target_state = STATE_INACTIVE;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  sm_error_source();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				int16_t sm_return_cell_temperature(int id){ return tmp1075_temps[id]; }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				int16_t sm_return_cell_voltage(int id){ return module.cellVoltages[id]; }
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -407,17 +413,4 @@ void sm_test_cycle_states(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.target_state = state.current_state;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void sm_error_source(){
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.bms_timeout << 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.bms_fault << 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.temperature_error << 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.current_error << 3);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.current_sensor_missing << 4);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.voltage_error << 5);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.voltage_missing << 6);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  state.error_source |= (state.error_type.state_transition_fail << 7);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 |