FreeCalypso > hg > fc-magnetite
view src/cs/drivers/drv_app/lcc/lcc_handle_message.c @ 632:d968a3216ba0
new tangomdm build target
TCS211/Magnetite built for target leonardo runs just fine on the Tango-based
Caramel board, but a more proper tangomdm build target is preferable in order
to better market these Tango modems to prospective commercial customers. The
only differences are in GPIO and MCSI config:
* MCSI is enabled in the tangomdm build config.
* GPIO 1 is loudspeaker amplifier control on Leonardo, but on Tango platforms
it can be used for anything. On Caramel boards this GPIO should be
configured as an output driving high.
* GPIO 2 needs to be configured as Calypso input on Leonardo, but on Tango
platforms it can be used for anything. On Caramel boards this GPIO should be
configured as an output, either high or low is OK.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 04 Jan 2020 19:27:41 +0000 |
parents | 945cf7f506b2 |
children |
line wrap: on
line source
/****************************************************************************** * Power Task (pwr) * Design and coding by Svend Kristian Lindholm, skl@ti.com * * PWR Message Processing * * $Id: pwr_handle_message.c 1.3 Wed, 20 Aug 2003 15:17:25 +0200 skl $ * ******************************************************************************/ #include <string.h> #include "lcc/lcc.h" #include "lcc/lcc_api.h" #include "lcc/lcc_trace.h" #include "lcc/lcc_task.h" #include "lcc/lcc_tm_i.h" #include "lcc/lcc_cfg_i.h" #include "lcc/lcc_cfg.h" #include "lcc/lcc_modulate.h" #include "rv/rv_defined_swe.h" #include "ffs/ffs.h" #include "etm/etm_env.h" #include "abb/abb.h" /****************************************************************************** * Function prototypes ******************************************************************************/ void ttr(unsigned trmask, char *format, ...); void str(unsigned mask, char *string); void *pwr_malloc(int size); T_RVM_RETURN pwr_task_init(void); UINT32 pwr_timer_elapsed(UINT32 time_begin, UINT32 current_timer); void build_name(const char *ch_pre, char *cfg_id , UINT8 index, const char * ch_post, char * name); void pwr_modulate_init(void); void pwr_modulate_on(void); int pwr_capacity(uint16 Vbat); void pwr_check_timers(); void pwr_stop_timers(); T_RVM_RETURN pwr_start_timer(UINT32 *timer_begin); T_RVM_RETURN pwr_stop_timer(UINT32 *timer_begin); T_RVM_RETURN pwr_check_files(void); T_RVM_RETURN pwr_read_files(void); T_RVM_RETURN pwr_read_chg_files(void); T_RVM_RETURN pwr_read_cal_files(void); void pwr_send_msg(uint32 msg_id ,T_RVF_ADDR_ID src_addr_id, T_RVF_ADDR_ID dest_addr_id); void mmi_send_msg(struct mmi_info_ind_s *event); void start_q401_charge(void); void start_q402_charge(void); void start_pre_charge(void); void stop_q401_charge(void); void stop_q402_charge(void); void stop_pre_charge(void); void charger_unplug_house_keeping(void); void cv_charging_house_keeping(void); void end_charging_house_keeping(void); int check_chg_unplug(void); #if (TEST_PWR_MMI_INTERFACE == 1) #include "lcc/pwr_mmi_api.c" #endif extern T_PWR_CTRL_BLOCK *pwr_ctrl; extern T_PWR_CFG_BLOCK *pwr_cfg; /****************************************************************************** * Functions ******************************************************************************/ void build_name(const char *ch_pre, char *cfg_id, UINT8 index, const char * ch_post, char * name) { char tmp[2]; strcpy(name, ch_pre); tmp[0] = *cfg_id; tmp[1] = 0; // null-termination of strings! strcpy(&(name[index]), tmp); strcat(name, ch_post); ttw(ttr(TTrInit, "build_name: '%s'" NL, name)); } T_RVM_RETURN pwr_task_init() { // Perform battery initialization of the pwr task by // reading battery id and FFS configuration files T_FFS_SIZE error; ttw(ttr(TTrInit, "pwr_task_init(%d)" NL, 0)); // Check configuration and calibration files if ((error = pwr_check_files()) < 0) return error; // Read configuration files if ((error = pwr_read_files()) < 0) return error; ttw(ttr(TTrInit, "pwr_task_init(%d)" NL, 0xFF)); return RV_OK; } int pwr_chg_start(int Tbat) { int capacity; // Tbat is the temperature measured in Celsius // Check start conditions for charging - it is assumed that a charger is plugged // This check is used in state SUP // Charging start will _not_ be performed if ... // 1) Battery temperature is outside limits (measurement) // 2) Charger identity is unknown ttw(ttr(TTrCharge, "pwr_chg_start(%d)" NL, 0)); // 1) // Battery temperature is outside limits (measurement) // FIXME: Check also low temperatures // if ((Tbat < pwr_cfg->temp.tbat_min) || (Tbat > pwr_cfg->temp.tbat_max)) { if ((Tbat > pwr_cfg->temp.tbat_max)) { ttw(ttr(TTrCharge, "pwr_chg_start(%d) Tbat=(%d)" NL, 0xFF, Tbat)); return FALSE; } // 2) // Charger identity unknown if ((pwr_ctrl->flag_chg_unknown == 1) && (pwr_ctrl->flag_mmi_registered == 1)) { ttw(ttr(TTrCharge, "pwr_chg_start(%d) Chg unknown=(%d)" NL, 0xFF, Tbat)); pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_UNKNOWN_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); // Send only once pwr_ctrl->flag_bat_unknown = 0; return FALSE; } ttw(ttr(TTrCharge, "pwr_chg_start(%d)" NL, 0xFF)); return TRUE; } int pwr_chg_stop(int Tbat, int Vbat) { // Check stop conditions for charging // I.e. // - temperature (RF+Battery) thresholds // - battery voltage thresholds // - regulation loop gain (duty cycle) // // This check is used regularly in state CCI, LCI, CCV and LCV // Charging will be stopped if ... // 1) Battery temperature is outside limits // 2) Battery voltage is equal to - or above - charging stop battery voltage // Nickel checks: // 3) The RF temperature versus battery temperature rise is above threshold (Possible?) // // Lithium checks: // 4) The regulation parameter k is below configured threshold limit // Returns TRUE if the charging algorithm should be stopped // Returns FALSE if the charging algorithm should be continued ttw(ttr(TTrCharge, "pwr_chg_stop(%d)" NL, 0)); // 1) // Battery temperature is outside limits // FIXME: Check also low temperatures if (Tbat > pwr_cfg->temp.tbat_max) { ttw(ttr(TTrCharge, "pwr_chg_stop(%d) Tbat=(%d)" NL, 0xFF, Tbat)); if (pwr_ctrl->flag_mmi_registered == 1) { pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_FAILED_IND; pwr_ctrl->mmi_ptr->cause = BATTERY_TEMPERATURE_HIGH; mmi_send_msg(pwr_ctrl->mmi_ptr); } return TRUE; } // 2) // Battery voltage is equal to - or above - charging stop battery voltage if ((Vbat > pwr_cfg->bat.chg_stop_thr)) { ttw(ttr(TTrCharge, "pwr_chg_stop(%d) Vbat=(%d)" NL, 0xFF, Vbat)); ttw(ttr(TTrCharge, "pwr_cfg->bat.chg_stop_thr=%d" NL, 0xFF, pwr_cfg->bat.chg_stop_thr)); return TRUE; } #if 0 #ifndef PWR_FFS_CFG pwr_cfg->common.rise_thr = PWR_RISE_THR ; #endif // 3) // The RF temperature versus battery temperature rise is above threshold (Possible?) // Did the battery temperature rise more than the RF temperature rise - stop for Nickel charging! // Only for Nickel batteries // FIXME: How big time difference should there be between the deltas? Configurable? if ((pwr_cfg->data.dTbat - pwr_cfg->data.dT_rf > pwr_cfg->common.rise_thr) == TRUE) { ttw(ttr(TTrCharge, "pwr_chg_stop(%d) d(Tbat-Trf)=(%d)" NL, 0xFF, pwr_cfg->data.dTbat - pwr_cfg->data.dT_rf)); return TRUE; } #endif // 4) FIXME: Remove states in this part of the function // Regulation parameter k is below the configured limit if ((pwr_cfg->bat.type == LITHIUM) && ((pwr_ctrl->state == LCV) || (pwr_ctrl->state == CCV)) && (pwr_cfg->data.k < pwr_cfg->bat.chg_ctrl_thr)) { ttw(ttr(TTrCharge, "k=%d < %d" NL, pwr_cfg->data.k, pwr_cfg->bat.chg_ctrl_thr)); return TRUE; } ttw(ttr(TTrCharge, "pwr_chg_stop(%d)" NL, 0xFF)); return FALSE; } int pwr_chg_ci_cv_transition(int Vbat) { // Check CI -> CV condition for charging // Only for Lithium batteries // Returns TRUE if CI-> CV transition should be made // Returns FALSE if CI-> CV transition should NOT be made ttw(ttr(TTrCharge, "pwr_chg_ci_cv_transition(%d)" NL, 0)); // 1) Check CV charging start threshold if ((Vbat > pwr_cfg->bat.chg_start_thr)) { ttw(ttr(TTrCharge, "pwr_chg_ci_cv_transition(%d) Vbat=(%d)" NL, 0xFF, Vbat)); return TRUE; } ttw(ttr(TTrCharge, "pwr_chg_ci_cv_transition(%d)" NL, 0xFF)); return FALSE; } int pwr_capacity(uint16 Vbat) { // Calculate the capacity, C(T,V), of the battery based on // - Battery Voltage Measurement // - Battery Temperature Measurement // - Configuration Parameters // Returns a value in the interval 0..100 [%] uint8 i; uint8 cap; ttw(ttr(TTrEventLow,"pwr_capacity (Vbat=%d)" NL, Vbat)); cap = 100; // 100% for (i=0;i<=9;i++) { if (Vbat < pwr_cfg->temp.cap[i] ) { cap -= 10; // Count down 10% for each index ttw(ttr(TTrEventLow,"Trying cap=%d" NL, cap)); } else { // FIXME: Interpolate ... instead of truncate ttw(ttr(TTrEventLow,"capacity=%d" NL, cap)); return cap; } } ttw(ttr(TTrEventLow,"pwr_capacity (%d)" NL, 0xFF)); return 0; // Couldn't lookup capacity } int8 pwr_temp_lookup(uint16 ADC, uint8 i_meas) { // temperature = f(ADC, I_meas) // f(x) is table-lized using ETM command 'pww 4 ...' int i; int temp; #define MAX_TEMP_SIZE 9 i = 0; temp = -20; // FIXME: Always using the second current - should also use the first... while (ADC < pwr_cfg->temp.v2t_2[i] && i < MAX_TEMP_SIZE) { ttw(ttr(TTrEventLow,"ADC=%d < pwr_cfg->temp.v2t_2[%d]=0x%x" NL, ADC,i, pwr_cfg->temp.v2t_2[i])); ttw(ttr(TTrEventLow,"temp=%d" NL, temp)); i++; temp += 10; } if (i == MAX_TEMP_SIZE) { // No temperature found - return NULL value (0xFF) ttr(TTrWarning, "Temperature lookup failed %d" NL, ADC); return 0xFF; } if (i != 0) { // Interpolate if (pwr_cfg->temp.v2t_2[i-1] == 0xFFFF) temp += 10*(ADC - pwr_cfg->temp.v2t_2[i])/(pwr_cfg->temp.v2t_2[i] - 1024); else temp += 10*(ADC - pwr_cfg->temp.v2t_2[i])/(pwr_cfg->temp.v2t_2[i] - pwr_cfg->temp.v2t_2[i-1]); ttw(ttr(TTrEventLow,"Interpolated temp=%d" NL, temp)); } return ((int8)temp); } enum { Vbat = 0, Vchg = 1, Ichg = 2, Vbt2 = 3, Type = 4, Tbat = 5, T_rf = 6, Tc_x = 7, Tc_y = 8, State= 9 } adc_index_e; // The driving element of the LCC task - the ADC measurements T_RV_RET process_spi_adc_indication (T_PWR_REQ *request) { struct pwr_adc_ind_s *ind; int error, i, index; int8 temp; UINT32 timer; UINT16 status; // Result of charger plug - unplug - polled ind = (struct pwr_adc_ind_s*)request; ttw(ttr(TTrEventLow,"State=%d" NL, ind->data[State])); // Basic trace - not for CAL switch (pwr_ctrl->state) { case PRE : ttw(ttr(TTrEventLow,"Vbat=%d" NL, ADC_to_mV(ind->data[Vbat]))); ttw(ttr(TTrEventLow,"Vchg=%d" NL, ADC_to_mV(ind->data[Vchg]))); ttw(ttr(TTrEventLow,"Ichg=%d" NL, ind->data[Ichg])); break; case INI : case SUP : case CCI : case LCI : case CCV : case LCV : ttw(ttr(TTrEventLow,"Vbat=%d" NL, ADC_to_mV(ind->data[Vbat]))); ttw(ttr(TTrEventLow,"Vbat_adc=%d" NL, ind->data[Vbat])); #if (USE_Q402_CHG_CIRCUIT == 1) // Vchg Scaling factor for Q402 circuit pwr_cfg->data.Vchg = 5*ADC_to_mV(ind->data[Vchg])/4; ttw(ttr(TTrEventLow,"Vchg=%d" NL, pwr_cfg->data.Vchg)); #else pwr_cfg->data.Vchg = ADC_to_mV(ind->data[Vchg]); ttw(ttr(TTrEventLow,"Vchg=%d" NL, pwr_cfg->data.Vchg)); #endif ttw(ttr(TTrEventLow,"Ichg=%d" NL, ind->data[Ichg])); ttw(ttr(TTrEventLow,"Type=%d" NL, ind->data[Type])); ttw(ttr(TTrEventLow,"Tbat=%d" NL, ind->data[Tbat])); ttw(ttr(TTrEventLow,"T_rf=%d" NL, ind->data[T_rf])); ttw(ttr(TTrEventLow,"Vbt2=%d" NL, ADC_to_mV(ind->data[Vbt2]))); break; } // Updates variables in 'service' mode - not for CAL, PRE & INI switch (pwr_ctrl->state) { case SUP : case CCI : case LCI : case CCV : case LCV : index = pwr_ctrl->index % CONSECUTIVE_CHG_UNPLUGS; ttw(ttr(TTrEventLow,"Using index: (%d)" NL, index)); pwr_ctrl->index++; // Get current nucleus time timer = rvf_get_tick_count(); // T0 timer expired? pwr_ctrl->time_elapsed_T0 = pwr_timer_elapsed(pwr_ctrl->time_begin_T0, timer); ttw(ttr(TTrTimerLow,"T0: %d ms elapsed " NL, pwr_ctrl->time_elapsed_T0)); // Compare T0 with configured sampling rate if (pwr_ctrl->time_elapsed_T0 > pwr_cfg->common.sampling) { ttw(ttr(TTrTimer, "T0 Reset: elapsed (%d)" NL, pwr_ctrl->time_elapsed_T0)); pwr_ctrl->time_begin_T0 = timer; ttr(TTrAll,"Vbat_avg=%d" NL, ADC_to_mV(pwr_cfg->data.Vbat_avg)); } pwr_cfg->data.Vbat = ind->data[Vbat]; pwr_cfg->data.Vbat_avg = (ind->data[Vbat] + pwr_cfg->common.alfa1 * pwr_cfg->data.Vbat_avg)/(pwr_cfg->common.alfa1 + 1); pwr_cfg->data.Vbat_avg_mV = ADC_to_mV(pwr_cfg->data.Vbat_avg); ttw(ttr(TTrEventLow,"Vbat_avg=%d" NL, pwr_cfg->data.Vbat_avg_mV)); pwr_cfg->data.Tbat = ind->data[Tbat]; pwr_cfg->data.Tbat_avg = (ind->data[Tbat] + pwr_cfg->common.alfa2 * pwr_cfg->data.Tbat_avg)/(pwr_cfg->common.alfa2 + 1); ttw(ttr(TTrEventLow,"Tbat_avg=%d" NL, pwr_cfg->data.Tbat_avg)); temp = pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01); ttw(ttr(TTrEventLow,"temp=%d" NL, temp)); pwr_cfg->data.T_rf_avg = ind->data[T_rf]; pwr_cfg->data.T_rf_avg = (ind->data[T_rf] + pwr_cfg->common.alfa3 * pwr_cfg->data.T_rf_avg)/(pwr_cfg->common.alfa3 + 1); ttw(ttr(TTrEventLow,"T_rf_avg=%d" NL, pwr_cfg->data.T_rf_avg)); pwr_cfg->data.Ichg = ind->data[Ichg]; break; } // 'Main' switch ttw(ttr(TTrEventLow,"state=%d" NL, pwr_ctrl->state)); switch (pwr_ctrl->state) { case CAL : // Read calibration files // Decide if SW precharge should be started (state PRE) or if a normal configuration scheme should be inititated (state INI) error = pwr_read_cal_files(); if (error >= 0) { // Save measurements - also initial values for averaging pwr_cfg->data.Vbat_avg = pwr_cfg->data.Vbat = ind->data[Vbat]; pwr_cfg->data.Vbat_avg_mV = ADC_to_mV(pwr_cfg->data.Vbat_avg); ttw(ttr(TTrEventLow,"Vbat=%d" NL, ADC_to_mV(ind->data[Vbat]))); ttw(ttr(TTrEventLow,"Vchg=%d" NL, ADC_to_mV(ind->data[Vchg]))); // Charger was already inserted? status = ind->data[State]; if (status & CHGPRES) { // Charger plugged caused a wakeup pwr_ctrl->flag_chg_plugged = 1; pwr_ctrl->flag_chg_prev_plugged = 1; ttw(ttr(TTrInitLow,"Polled - charger plugged (%d)" NL, status)); } // Check Pre-charge - immediately change state to PRE if ((pwr_cfg->data.Vbat_avg_mV < VBAT_PRECHG_START) && (pwr_ctrl->flag_chg_plugged == 1)) { ttw(ttr(TTrInitLow,"precharge (%d)" NL, ADC_to_mV(ind->data[Vbat]))); // Charger interrupts (plug/unplug) are already masked off - in case it was a linear charger pwr_ctrl->state = PRE; } else { pwr_ctrl->state = INI; } } break; case PRE : // Start fast charge immediately after 3.2V boot // Enter INI state - in order to read FFS configuration files - when Vbat reaches 3.6V // Hardcoding moving average to PRECHG_AVG_WINDOW_SIZE since we haven't read any configuration pwr_cfg->data.Vbat = ind->data[Vbat]; pwr_cfg->data.Vbat_avg = (ind->data[Vbat] + PRECHG_AVG_WINDOW_SIZE * pwr_cfg->data.Vbat_avg)/(PRECHG_AVG_WINDOW_SIZE + 1); pwr_cfg->data.Vbat_avg_mV = ADC_to_mV(pwr_cfg->data.Vbat_avg); if (pwr_cfg->data.Vbat_avg_mV > VBAT_PRECHG_STOP) { ttw(ttr(TTrInitLow,"state PRE (%d > VBAT_PRECHG_STOP)" NL, pwr_cfg->data.Vbat_avg_mV)); pwr_ctrl->state = INI; pwr_ctrl->flag_prechg_started = 0; stop_pre_charge(); } else { ttw(ttr(TTrInitLow,"state PRE (%d < VBAT_PRECHG_STOP)" NL, pwr_cfg->data.Vbat_avg_mV)); // Start fast charging NOW if (pwr_ctrl->flag_prechg_started == 0) { pwr_ctrl->flag_prechg_started = 1; start_pre_charge(); } } break; case INI : // Charger was already inserted? status = ind->data[State]; pwr_ctrl->chg_unplug_vec[index] = (status & CHGPRES); if (status & CHGPRES) { // Charger plugged caused a wakeup pwr_ctrl->flag_chg_plugged = 1; pwr_ctrl->flag_chg_prev_plugged = 1; ttw(ttr(TTrInitLow,"Polled - charger plugged (%d)" NL, status)); } if (pwr_ctrl->flag_ini_virgo == 0) { // Perform some very basic initialization /* Precharge (C/20) is switched OFF since it was finished in state PRE */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0002); // Enable battery type identification // Switch on battery type identification (TYPEN) // NOTE: Battery type identification is ALWAYS done with 10uA (TYPEN) ttw(ttr(TTrInitLow,"Enable type ident (%d)" NL, 0x00)); ABB_Write_Register_on_page(PAGE0, BCICTL1, THERMAL_SENSOR_30uA | TYPEN); pwr_ctrl->flag_ini_virgo = 1; } // Don't read battery files before we know which battery id to use // We will ignore the first BATTERY_TYPE_SLIP measurements of battery id if ((pwr_ctrl->count_bat_type == BATTERY_TYPE_SLIP)) { error = pwr_task_init(); // Change state pwr_ctrl->state = SUP; // Readout /pwr/common.cfg ttw(ttr(TTrInitLow,"common.cfg: pins: %d" NL, pwr_cfg->common.pins)); ttw(ttr(TTrInitLow,"chg_dedic %d" NL, pwr_cfg->common.chg_dedic)); ttw(ttr(TTrInitLow,"sampling %d" NL, pwr_cfg->common.sampling)); ttw(ttr(TTrInitLow,"mod_cycle %d" NL, pwr_cfg->common.mod_cycle)); ttw(ttr(TTrInitLow,"alfa1 %d" NL, pwr_cfg->common.alfa1)); ttw(ttr(TTrInitLow,"alfa2 %d" NL, pwr_cfg->common.alfa2)); ttw(ttr(TTrInitLow,"alfa3 %d" NL, pwr_cfg->common.alfa3)); ttw(ttr(TTrInitLow,"rise_thr %d" NL, pwr_cfg->common.rise_thr)); // Readout /pwr/bat/bat.cfg ttw(ttr(TTrInitLow,"bat.cfg: type: %d" NL, pwr_cfg->bat.type)); ttw(ttr(TTrInitLow,"rf_temp: %d" NL, pwr_cfg->bat.rf_temp)); ttw(ttr(TTrInitLow,"id_low: %d" NL, pwr_cfg->bat.id_low)); ttw(ttr(TTrInitLow,"id_high: %d" NL, pwr_cfg->bat.id_high)); ttw(ttr(TTrInitLow,"cbat: %d" NL, pwr_cfg->bat.cbat)); ttw(ttr(TTrInitLow,"ratio: %d" NL, pwr_cfg->bat.ratio)); ttw(ttr(TTrInitLow,"T1: %d" NL, pwr_cfg->bat.T1)); ttw(ttr(TTrInitLow,"T2: %d" NL, pwr_cfg->bat.T2)); ttw(ttr(TTrInitLow,"T3: %d" NL, pwr_cfg->bat.T3)); ttw(ttr(TTrInitLow,"chg_start_thr: %d" NL, pwr_cfg->bat.chg_start_thr)); ttw(ttr(TTrInitLow,"chg_stop_thr: %d" NL, pwr_cfg->bat.chg_stop_thr)); ttw(ttr(TTrInitLow,"chg_ctrl_thr: %d" NL, pwr_cfg->bat.chg_ctrl_thr)); ttw(ttr(TTrInitLow,"chg_again_thr: %d" NL, pwr_cfg->bat.chg_again_thr)); // Readout /pwr/bat/temp<N>.cfg ttw(ttr(TTrInitLow,"sizeof(temp): %d" NL, sizeof(pwr_cfg->temp))); ttw(ttr(TTrInitLow,"sizeof(T_PWR_BAT_TEMP_CFG_BLOCK): %d" NL, sizeof(T_PWR_BAT_TEMP_CFG_BLOCK))); ttw(ttr(TTrInitLow,"temp.cfg: tbat_min: %d" NL, pwr_cfg->temp.tbat_min)); ttw(ttr(TTrInitLow,"tbat_max: %d" NL, pwr_cfg->temp.tbat_max)); ttw(ttr(TTrInitLow,"i_meas1: %d" NL, pwr_cfg->temp.i_meas1)); for (i=0;i<=8;i++) { ttw(ttr(TTrInitLow,"v2t_1[]: %d" NL, pwr_cfg->temp.v2t_1[i])); } ttw(ttr(TTrInitLow,"i_meas2: %d" NL, pwr_cfg->temp.i_meas2)); for (i=0;i<=8;i++) { ttw(ttr(TTrInitLow,"v2t_2[]: %d" NL, pwr_cfg->temp.v2t_2[i])); } for (i=0;i<=9;i++) { ttw(ttr(TTrInitLow,"cap[]: %d" NL, pwr_cfg->temp.cap[i])); } ttw(ttr(TTrInitLow,"a0: %d" NL, pwr_cfg->temp.a0)); ttw(ttr(TTrInitLow,"a1: %d" NL, pwr_cfg->temp.a1)); ttw(ttr(TTrInitLow,"a2: %d" NL, pwr_cfg->temp.a2)); // Readout /mmi/pwr/bsie.cfg ttw(ttr(TTrInitLow,"mmi repetition: %d" NL, pwr_cfg->mmi.repetition)); // Initialize battery temperature - must not be made in the virgo part since Tbat=0 pwr_cfg->data.Tbat_avg = ind->data[Tbat]; // Setup thermal sensor - don't re-enable TYPEN if (pwr_cfg->temp.i_meas2 == 50) { ttw(ttr(TTrInitLow,"ABB set i_current: %d" NL, pwr_cfg->temp.i_meas2)); ABB_Write_Register_on_page(PAGE0, BCICTL1, THERMAL_SENSOR_50uA); } else if (pwr_cfg->temp.i_meas2 == 30) { ttw(ttr(TTrInitLow,"ABB set i_current: %d" NL, pwr_cfg->temp.i_meas2)); ABB_Write_Register_on_page(PAGE0, BCICTL1, THERMAL_SENSOR_30uA); } else { // Default 30uA ttw(ttr(TTrInitLow,"ABB set i_current default: %d" NL, pwr_cfg->temp.i_meas2)); ABB_Write_Register_on_page(PAGE0, BCICTL1, THERMAL_SENSOR_30uA); } } else { // Compare battery id with values found in FFS // First value(s) are NOT to be trusted pwr_ctrl->count_bat_type++; pwr_cfg->data.bat_id = ind->data[Type]; } break; case SUP : // Charger inserted?? Poll!! // Reason: 100Hz interrupts will occur if an unregulated charger is inserted & charger interrupts are enabled // This will cause an immediate crash! status = ind->data[State]; pwr_ctrl->chg_unplug_vec[index] = (status & CHGPRES); if (status & CHGPRES) { // Charger is plugged - continue ttw(ttr(TTrEventLow,"Polled - chg plugged (%d)" NL, status)); pwr_ctrl->flag_chg_plugged = 1; pwr_ctrl->capacity = pwr_capacity(pwr_cfg->data.Vbat_avg_mV); } else { pwr_ctrl->flag_chg_plugged = 0; } if (pwr_ctrl->flag_mmi_registered == 1) { // If the charger is plugged and no charging is initiated this message will be repeated until charging has started // Charger plugged if ((pwr_ctrl->flag_chg_plugged == 1) && (pwr_ctrl->flag_chg_prev_plugged == 0)) { pwr_ctrl->flag_chg_prev_plugged = 1; pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_PLUG_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } // Charger unplugged if ((pwr_ctrl->flag_chg_plugged == 0) && (pwr_ctrl->flag_chg_prev_plugged == 1)) { pwr_ctrl->flag_chg_prev_plugged = 0; pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_UNPLUG_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } if (pwr_ctrl->flag_bat_unknown == 1) { // Battery unknown - inform the MMI pwr_ctrl->mmi_ptr->header.msg_id = MMI_BAT_UNKNOWN_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); // Send only once pwr_ctrl->flag_bat_unknown = 0; } } pwr_check_timers(); // If charger is plugged AND charger configuration is not read AND capacity is below configured limit - charger id Vchg(Load=0) must be measured if ((pwr_ctrl->flag_chg_plugged == 1) && (pwr_ctrl->flag_chg_cfg_read == 0) && (pwr_ctrl->capacity < pwr_cfg->bat.chg_again_thr) ) { // Measurement loop - Take the 2nd Vchg(0) measurements if (pwr_ctrl->count_chg_type == CHARGER_TYPE_SLIP) { if (pwr_cfg->data.Vchg > CHARGER_TYPE_OUT_OF_BOUND_LOW) pwr_cfg->data.chg_id = pwr_cfg->data.Vchg; else { // Out of bound!! ttr(TTrWarning, "Charger id out of bound! %d" NL, pwr_cfg->data.Vchg); pwr_cfg->data.chg_id = CHARGER_TYPE_TYPICAL; } ttw(ttr(TTrEventLow,"Using chg id=%d" NL, pwr_cfg->data.chg_id)); error = pwr_read_chg_files(); pwr_ctrl->flag_chg_cfg_read = 1; // Initialize the circular buffer with charger plugs for (i=0;i<= CONSECUTIVE_CHG_UNPLUGS-1 ;i++) pwr_ctrl->chg_unplug_vec[i] = CHGPRES; if (pwr_chg_start(pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01)) == TRUE ) { if (pwr_cfg->chg.type == CI) { pwr_ctrl->state = CCI; // Enable charger plug/unplug interrupts for a CI charger ABB_Write_Register_on_page(PAGE0, ITMASK, ALL_IT_UMSK); } else { if (pwr_cfg->chg.type == UNREGULATED) pwr_ctrl->state = LCI; else { ttr(TTrWarning, "Unknown charger type! %d" NL, pwr_cfg->chg.type); pwr_ctrl->state = LCI; } } #if (USE_Q401_CHG_CIRCUIT == 1) start_q401_charge(); #endif #if (USE_Q402_CHG_CIRCUIT == 1) start_q402_charge(); #endif // Stop the mmi info repetition timer pwr_stop_timer(&pwr_ctrl->time_begin_mmi_rep); } } else { pwr_ctrl->count_chg_type++; ttw(ttr(TTrEventLow,"count_chg_type=%d" NL, pwr_ctrl->count_chg_type)); } } break; case CCI : pwr_check_timers(); // We are in the middle of a CI charging process - check stop criterias // if ( pwr_chg_stop(pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01), pwr_cfg->data.Vbat_avg_mV) == FALSE) { // Continue to charge - change state? if ((pwr_cfg->bat.type == LITHIUM) && (pwr_chg_ci_cv_transition(pwr_cfg->data.Vbat_avg_mV)== TRUE)) { // Change state to CCV // Calculate k value // Start T2 timer // Start DC timer // Start T4 timer based on k value // Modulation ON pwr_ctrl->state = CCV; cv_charging_house_keeping(); } } else { // Change state pwr_ctrl->state = SUP; end_charging_house_keeping(); } break; case LCI : // Poll ABB for charger unplug - Linear - unregulated chargers ONLY status = ind->data[State]; pwr_ctrl->chg_unplug_vec[index] = (status & CHGPRES); if (status & CHGPRES) { // Charger is still plugged - continue ttw(ttr(TTrEventLow,"Polled - chg plugged (%d)" NL, status)); } else { if (check_chg_unplug() == 1) { // Charger is not plugged anymore - stop!! ttw(ttr(TTrEventLow,"Verdict - chg not plugged (%d)" NL, status)); // Change state pwr_ctrl->state = SUP; charger_unplug_house_keeping(); pwr_free(request); return; } else { // False alarm - don't set flags ttw(ttr(TTrEventLow,"Polled - chg not plugged - FALSE alarm? (%d)" NL, status)); #if (USE_Q401_CHG_CIRCUIT == 1) if ((ind->data[Ichg] == 0) && (pwr_cfg->data.Vchg > 0)) { // Charging current has disappeared due to a fast unplug??? Bug in IOTA ABB? pwr_ctrl->state = SUP; charger_unplug_house_keeping(); pwr_free(request); return; } #endif #if (USE_Q402_CHG_CIRCUIT == 1) // FIXME: Really no false alarm code for Q402?? #endif } } pwr_check_timers(); // We are in the middle of a CI charging process - check stop criterias if ( pwr_chg_stop(pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01), pwr_cfg->data.Vbat_avg_mV) == FALSE) { // Continue to charge - change state? if ((pwr_cfg->bat.type == LITHIUM) && (pwr_chg_ci_cv_transition(pwr_cfg->data.Vbat_avg_mV)== TRUE)) { // Change state to LCV // Calculate k value // Start T2 timer // Start DC timer // Start T4 timer based on k value // Modulation ON pwr_ctrl->state = LCV; cv_charging_house_keeping(); } } else { // Change state pwr_ctrl->state = SUP; end_charging_house_keeping(); } break; case CCV : pwr_check_timers(); // We are in the middle of a CV charging process - check stop criterias if (pwr_chg_stop(pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01), pwr_cfg->data.Vbat_avg_mV) == FALSE) { // EMPTY - waiting for T4 and DC timeouts OR T2 timeout } else { // Change state pwr_ctrl->state = SUP; end_charging_house_keeping(); } break; case LCV : // Poll ABB for charger unplug - Linear - unregulated chargers ONLY status = ind->data[State]; pwr_ctrl->chg_unplug_vec[index] = (status & CHGPRES); if (status & CHGPRES) { // Charger is still plugged - continue ttw(ttr(TTrEventLow,"Polled - chg plugged (%d)" NL, status)); } else { #if (USE_Q401_CHG_CIRCUIT == 1) // Charger is not plugged anymore - stop!! ttw(ttr(TTrEventLow,"Verdict - chg not plugged (%d)" NL, status)); // Change state pwr_ctrl->state = SUP; charger_unplug_house_keeping(); pwr_free(request); return; #endif #if (USE_Q402_CHG_CIRCUIT == 1) if (check_chg_unplug() == 1) { // Charger is not plugged anymore - stop!! ttw(ttr(TTrEventLow,"Verdict - chg not plugged (%d)" NL, status)); // Change state pwr_ctrl->state = SUP; charger_unplug_house_keeping(); pwr_free(request); return; } #endif } pwr_check_timers(); // We are in the middle of a CV charging process - check stop criterias if (pwr_chg_stop(pwr_temp_lookup(pwr_cfg->data.Tbat_avg, 0x01), pwr_cfg->data.Vbat_avg_mV) == FALSE) { // EMPTY - waiting for T4 and DC timeouts OR T2 timeout } else { // Change state pwr_ctrl->state = SUP; end_charging_house_keeping(); } break; default : { // Exception Handling - Unknown State ttr(TTrFatal, "process_spi_adc_indication: Unknown State: %d" NL, pwr_ctrl->state); } } pwr_free(request); return RV_OK; } T_RV_RET process_abb_chg_unplugged_ind (T_PWR_REQ *request) { charger_unplug_house_keeping(); // Disable charger interrupts - they where enabled when the CI charger was connected ABB_Write_Register_on_page(PAGE0, ITMASK, CHARGER_IT_MSK); // A charger can be unplugged in any state switch (pwr_ctrl->state) { case SUP : case CCI : case CCV : // Change state - T3 is running pwr_ctrl->state = SUP; break; default : { // Exception Handling - Unknown State ttr(TTrFatal, "process_abb_chg_unplugged_ind: Unknown State: %d" NL, pwr_ctrl->state); } } pwr_free(request); return RV_OK; } void pwr_send_msg(uint32 msg_id, T_RVF_ADDR_ID src_addr_id, T_RVF_ADDR_ID dest_addr_id) { struct pwr_req_s *msg; if ((msg = pwr_malloc(sizeof(struct pwr_req_s))) == NULL) { return; } msg->header.msg_id = msg_id; msg->header.src_addr_id = src_addr_id; msg->header.dest_addr_id = dest_addr_id; msg->header.callback_func = NULL; if (rvf_send_msg(dest_addr_id, msg) != RV_OK) { ttr(TTrFatal, "PWR FATAL: Send failed! %d" NL, 0xFF); } } void mmi_send_msg(struct mmi_info_ind_s *event) { ttw(ttr(TTrInit,"mmi_send_msg(%d)" NL, 0)); if (pwr_ctrl->rpath.callback_func) { ttw(ttr(TTrInit,"Using callback (0x%x)" NL, pwr_ctrl->rpath.callback_func)); (pwr_ctrl->rpath.callback_func) (event); } else { if (pwr_ctrl->rpath.addr_id) { // TESTME rvf_send_msg(pwr_ctrl->rpath.addr_id, event); } else { ttr(TTrFatal,"PWR FATAL: mmi_send_msg(%d) No return path" NL, 0xFF); return; } } ttw(ttr(TTrInit,"mmi_send_msg(%d)" NL, 0xFF)); } void start_pre_charge(void) { ttw(ttr(TTrInitLow,"start_pre_charge" NL, 0x00)); #if (USE_Q401_CHG_CIRCUIT == 1) /* Program the DAC with the constant current value */ // Value is hardcoded!! No configuration exist for state PRE ABB_Write_Register_on_page(PAGE0, CHGREG, ICHG_PRECHG); /* Enable the charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003); #endif #if (USE_Q402_CHG_CIRCUIT == 1) pwr_modulate_init(); #endif ttw(ttr(TTrInitLow,"start_pre_charge" NL, 0xFF)); } void start_q401_charge(void) { ttw(ttr(TTrInitLow,"start_q401_charge" NL, 0x00)); if (pwr_ctrl->flag_mmi_registered == 1) { pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_START_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } /* Program the DAC with the constant current value taken from /pwr/chg/chg<N>.cfg */ ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_cfg->chg.ichg_max); /* Enable the CI charger */ ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003); /* If not already started - start the overall charger timer T1 */ if (pwr_ctrl->time_begin_T1 == 0) { pwr_start_timer(&pwr_ctrl->time_begin_T1); ttw(ttr(TTrTimerLow,"T1 started(%d)" NL, 0)); } ttw(ttr(TTrInitLow,"start_q401_charge" NL, 0xFF)); } void start_q402_charge(void) { ttw(ttr(TTrInitLow,"start_q402_charge(%d)" NL, 0x00)); if (pwr_ctrl->flag_mmi_registered == 1) { pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_START_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } // Needed if we want Ichg measurements - else they are disabled!! ABB_Write_Register_on_page(PAGE0, CHGREG, pwr_cfg->chg.ichg_max); ABB_Write_Register_on_page(PAGE0, BCICTL2, 0x0003); pwr_modulate_init(); /* If not already started - start the overall charger timer T1 */ if (pwr_ctrl->time_begin_T1 == 0) { pwr_start_timer(&pwr_ctrl->time_begin_T1); ttw(ttr(TTrTimerLow,"T1 started(%d)" NL, 0)); } ttw(ttr(TTrInitLow,"start_q402_charge(%d)" NL, 0xFF)); } void stop_q401_charge(void) { ttw(ttr(TTrInitLow,"stop_q401_charge(%d)" NL, 0x00)); if (pwr_ctrl->flag_mmi_registered == 1) { pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_STOP_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); ttw(ttr(TTrInitLow,"stop_q401_charge(%d)" NL, 0xFF)); } void stop_q402_charge(void) { ttw(ttr(TTrInitLow,"stop_q402_charge(%d)" NL, 0x00)); if (pwr_ctrl->flag_mmi_registered == 1) { pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_STOP_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); } ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); pwr_modulate_off(); ttw(ttr(TTrInitLow,"stop_q402_charge(%d)" NL, 0xFF)); } void stop_pre_charge(void) { ABB_Write_Register_on_page(PAGE0, BCICTL2, 0); } int check_chg_unplug() { int i; #if (USE_Q401_CHG_CIRCUIT == 1) // Check that the latest values of charger status confirm that we have a charger unplug // Search through the vector - charger is only assumed unplugged when ALL CONSECUTIVE_CHG_UNPLUGS elements are 0 // Returns 1 (TRUE) if the charger is assumed unplugged // Returns 0 (FALSE) if the charger is assumed plugged // Assume that the charger unplug was true if the battery voltage is sufficiently high if (pwr_cfg->data.Vbat_avg_mV < VBAT_PRECHG_STOP) { for (i=0;i<= CONSECUTIVE_CHG_UNPLUGS-1 ;i++) { ttw(ttr(TTrTimerLow,"chg_unplug_vec(%d)" NL, pwr_ctrl->chg_unplug_vec[i])); if (pwr_ctrl->chg_unplug_vec[i] != 0) return 0; } } return 1; #endif #if (USE_Q402_CHG_CIRCUIT == 1) // Assume that the charger unplug was true if BOTH the charger voltage & charger current // are below configurable Vchg & Ichg threshold values if ((pwr_cfg->data.Vchg < VCHG_Q402_THR) && (pwr_cfg->data.Ichg < ICHG_Q402_THR)) { ttw(ttr(TTrInitLow,"check_chg_unplug: Vchg=(%d)" NL, pwr_cfg->data.Vchg)); ttw(ttr(TTrInitLow,"check_chg_unplug: Ichg=(%d)" NL, pwr_cfg->data.Ichg)); return 1; } return 0; #endif } void charger_unplug_house_keeping(void) { // Flag the charger unplug pwr_ctrl->flag_chg_plugged = 0; pwr_ctrl->flag_chg_prev_plugged = 0; // Read charger configuration next time charger is inserted pwr_ctrl->flag_chg_cfg_read = 0; // We must have more charger id measurements if the charger is re-connected pwr_ctrl->count_chg_type = 0; if (pwr_ctrl->flag_mmi_registered == 1) { // Send charger unplug to the MMI pwr_ctrl->mmi_ptr->header.msg_id = MMI_CHG_UNPLUG_IND; mmi_send_msg(pwr_ctrl->mmi_ptr); // Re-start the mmi info repetition timer pwr_start_timer(&pwr_ctrl->time_begin_mmi_rep); } // if T1 or T2 is running (which mean we have NOT had a normal charging stop) if ((pwr_ctrl->time_begin_T1 != 0) || (pwr_ctrl->time_begin_T2 != 0)) { // Start T3 timer if not already started if (pwr_ctrl->time_begin_T3 == 0) { pwr_start_timer(&pwr_ctrl->time_begin_T3); ttw(ttr(TTrTimerLow,"T3 started(%d)" NL, 0)); } // Switch of charging circuit #if (USE_Q401_CHG_CIRCUIT == 1) stop_q401_charge(); #endif #if (USE_Q402_CHG_CIRCUIT == 1) stop_q402_charge(); #endif } } void cv_charging_house_keeping(void) { // Calculate k value // Start DC timer // Start T4 timer based on k value // Modulation ON ttw(ttr(TTrTimerLow,"Vbat_avg, chg_start_thr, chg_stop_thr (%d), (%d), (%d)" NL, pwr_cfg->data.Vbat_avg_mV, pwr_cfg->bat.chg_start_thr, pwr_cfg->bat.chg_stop_thr)); if ((pwr_cfg->data.Vbat_avg_mV - pwr_cfg->bat.chg_start_thr) <= 0) { // Assign k to max value if Vbat_avg value is below start value pwr_cfg->data.k = PWR_MAX_K; } else { pwr_cfg->data.k = (255 * (pwr_cfg->bat.chg_stop_thr - pwr_cfg->data.Vbat_avg_mV) / (pwr_cfg->bat.chg_stop_thr - pwr_cfg->bat.chg_start_thr)); if (pwr_cfg->data.k <= PWR_MIN_K) pwr_cfg->data.k = PWR_MIN_K; } pwr_start_timer(&pwr_ctrl->time_begin_T2); ttw(ttr(TTrTimerLow,"T2 started(%d)" NL, 0)); ttw(ttr(TTrTimerLow, "k=%d" NL, pwr_cfg->data.k)); pwr_cfg->data.T4 = pwr_cfg->data.k * pwr_cfg->common.mod_cycle/255; ttw(ttr(TTrTimerLow,"T4 timer (%d)" NL, pwr_cfg->data.T4)); ttw(ttr(TTrTimerLow,"DC started(%d)" NL, 0)); pwr_start_timer(&pwr_ctrl->time_begin_mod_cycle); ttw(ttr(TTrTimerLow,"T4 started(%d)" NL, 0)); pwr_start_timer(&pwr_ctrl->time_begin_T4); pwr_modulate_on(); } void end_charging_house_keeping(void) { // Stop & reset timers pwr_stop_timers(); // Stop charging #if (USE_Q401_CHG_CIRCUIT == 1) stop_q401_charge(); #endif #if (USE_Q402_CHG_CIRCUIT == 1) stop_q402_charge(); #endif // Start the mmi info repetition timer if (pwr_ctrl->flag_mmi_registered == 1) pwr_start_timer(&pwr_ctrl->time_begin_mmi_rep); // Read charger configuration next time charger is inserted pwr_ctrl->flag_chg_cfg_read = 0; } #if (TEST_PWR_MMI_INTERFACE == 1) // Callback function used for testing MMI reporting static void mmi_test_cb_function(void *ptr) { T_PWR_MMI_INFO_IND_EVENT *event; event = (T_PWR_MMI_INFO_IND_EVENT *)ptr; ttw(ttr(TTrInit, "mmi_test_cb_function (%d)" NL, 0)); ttw(ttr(TTrInit, "MMI event: (%d)" NL, event->header.msg_id)); ttw(ttr(TTrInit, "mmi_test_cb_function (%d)" NL, 0xFF)); } #endif