/** @brief Generate the core variables and average them. * * Each raw ADC value is converted to a usable measurement via a variety of * methods chosen at runtime by configured settings. Once in their native units * and therefore closer to maximal use of the available data range they are * all averaged. * * @todo TODO incorporate averaging code, right now its a straight copy. * @todo TODO change the way configuration is done and make sure the most common options are after the first if(). * @todo TODO add actual configuration options to the fixed config blocks for these items. * * @author Fred Cooke */ void generateCoreVars(){ /*&&&&&&&& Calculate and obtain the basic variables with which we will perform the calculations &&&&&&&&*/ /* Pre calculate things used in multiple places */ /* Bound the TPS ADC reading and shift it to start at zero */ unsigned short unboundedTPSADC = ADCBuffers->TPS; if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){ boundedTPSADC = TPSADCRange; }else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){ // force secondary config to be used... TODO remove this boundedTPSADC = unboundedTPSADC - fixedConfigs2.sensorRanges.TPSMinimumADC; }else{ boundedTPSADC = 0; } /* Get BRV from ADC using transfer variables (all installations need this) */ unsigned short localBRV; if(TRUE){ /* If BRV connected */ /// @todo TODO WARNING: HACK!!! Remove ASAP!!! IE, As Soon As Preston (get's a new cpu on the TA card!) #ifdef HOTEL localBRV = (((unsigned long)ADCBuffers->MAT * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum; #else localBRV = (((unsigned long)ADCBuffers->BRV * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum; #endif }else if(FALSE){ /* Configured to be fixed value */ /* Get the preferred BRV figure from configuration settings */ localBRV = fixedConfigs2.sensorPresets.presetBRV; }else{ /* Fail safe if config is broken */ /* Default to normal alternator charging voltage 14.4V */ localBRV = VOLTS(14.4); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(BRV_NOT_CONFIGURED_CODE); } unsigned short localCHT; /* Get CHT from ADC using the transfer table (all installations need this) */ if(TRUE){ /* If CHT connected */ localCHT = CHTTransferTable[ADCBuffers->CHT]; }else if(FALSE){ /* Configured to be read From ADC as dashpot */ /* Transfer the ADC reading to an engine temperature in a reasonable way */ localCHT = (ADCBuffers->CHT * 10) + DEGREES_C(0); /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */ }else if(FALSE){ /* Configured to be fixed value */ /* Get the preferred CHT figure from configuration settings */ localCHT = fixedConfigs2.sensorPresets.presetCHT; }else{ /* Fail safe if config is broken */ /* Default to normal running temperature of 85C/358K */ localCHT = DEGREES_C(85); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(CHT_NOT_CONFIGURED_CODE); } unsigned short localIAT; /* Get IAT from ADC using the transfer table (all installations need this) */ if(TRUE){ /* If IAT connected */ /* using false here causes iat to default to room temp, useful with heatsoaked OEM sensors like the Volvo's... */ localIAT = IATTransferTable[ADCBuffers->IAT]; }else if(FALSE){ /* Configured to be read From ADC as dashpot */ /* Transfer the ADC reading to an air temperature in a reasonable way */ localIAT = (ADCBuffers->IAT * 10) + 27315; /* 0 ADC = 0C = 273.15K = 27315, 1023 ADC = 102.3C = 375.45K = 37545 */ }else if(FALSE){ /* Configured to be fixed value */ /* Get the preferred IAT figure from configuration settings */ localIAT = fixedConfigs2.sensorPresets.presetIAT; }else{ /* Fail safe if config is broken */ /* Default to room temperature (20C/293K) TODO poor choice, fix. */ localIAT = DEGREES_C(20); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(IAT_NOT_CONFIGURED_CODE); } unsigned short localMAT; /* Determine the MAT reading for future calculations */ if(TRUE){ /* If MAT sensor is connected */ /* Get MAT from ADC using same transfer table as IAT (too much space to waste on having two) */ localMAT = IATTransferTable[ADCBuffers->MAT]; }else if(FALSE){ /* Configured to be fixed value */ /* Get the preferred MAT figure from configuration settings */ localMAT = fixedConfigs2.sensorPresets.presetMAT; }else{ /* Fail safe if config is broken */ /* If not, default to same value as IAT */ localMAT = localIAT; /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(MAT_NOT_CONFIGURED_CODE); } unsigned short localMAP; unsigned short localIAP; /* Determine the MAP pressure to use for future calculations */ if(TRUE){ /* If MAP sensor is connected */ /* get MAP from ADC using transfer variables */ localMAP = (((unsigned long)ADCBuffers->MAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum; if(TRUE){ /* If Intercooler boost sensor connected */ /* Get IAP from ADC using the same transfer variables as they both need to read the same range */ localIAP = (((unsigned long)ADCBuffers->IAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum; } }else if(FALSE){ /* Configured for MAP to imitate TPS signal */ /* Get MAP from TPS via conversion */ localMAP = (((unsigned long)boundedTPSADC * TPSMAPRange) / TPSADCRange) + fixedConfigs2.sensorRanges.TPSClosedMAP; }else if(FALSE){ /* Configured for dash potentiometer on ADC */ /* Get MAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */ localMAP = ADCBuffers->MAP << 6; if(TRUE){ /* If Intercooler boost sensor enabled */ /* Get IAP from ADC via conversion to internal kPa figure where 1023ADC = 655kPa */ localIAP = ADCBuffers->IAP << 6; } }else if(FALSE){ /* Configured for fixed MAP from config */ /* Get the preferred MAP figure from configuration settings */ localMAP = fixedConfigs2.sensorPresets.presetMAP; }else{ /* Fail safe if config is broken */ /* Default to zero to nulify all other calcs and effectively cut fuel */ localMAP = 0; /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(MAP_NOT_CONFIGURED_CODE); // or maybe queue it? } /* Determine MAF variable if required */ unsigned short localMAF = 0; // Default to zero as it is not required for anything except main PW calcs optionally if(TRUE){ localMAF = MAFTransferTable[ADCBuffers->MAF]; } unsigned short localAAP; /* Determine the Atmospheric pressure to use for future calculations */ if(TRUE){ /* Configured for second sensor to read AAP */ /* get AAP from ADC using separate vars to allow 115kPa sensor etc to be used */ localAAP = (((unsigned long)ADCBuffers->AAP * fixedConfigs2.sensorRanges.AAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.AAPMinimum; }else if(FALSE){ /* Configured for dash potentiometer on ADC */ /* Get AAP from ADC via conversion to internal kPa figure where 1023ADC = 102.3kPa */ localAAP = ADCBuffers->AAP * 10; }else if(FALSE){ /* Configured for fixed AAP from config */ /* Get the preferred AAP figure from configuration settings */ localAAP = fixedConfigs2.sensorPresets.presetAAP; }else{ /* Fail safe if config is broken */ /* Default to sea level */ localAAP = KPA(100); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(AAP_NOT_CONFIGURED_CODE); // or maybe queue it? } unsigned short localEGO; /* Get main Lambda reading */ if(TRUE){ /* If WBO2-1 is connected */ /* Get EGO from ADCs using transfer variables */ localEGO = (((unsigned long)ADCBuffers->EGO * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum; }else if(FALSE){ /* Configured for fixed EGO from config */ /* Get the preferred EGO figure from configuration settings */ localEGO = fixedConfigs2.sensorPresets.presetEGO; }else{ /* Default value if not connected incase other things are misconfigured */ /* Default to stoichiometric */ localEGO = LAMBDA(1.0); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(EGO_NOT_CONFIGURED_CODE); // or maybe queue it? } unsigned short localEGO2; /* Get second Lambda reading */ if(TRUE){ /* If WBO2-2 is connected */ /* Get EGO2 from ADCs using same transfer variables as EGO */ localEGO2 = (((unsigned long)ADCBuffers->EGO2 * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum; }else if(FALSE){ /* Configured for fixed EGO2 from config */ /* Get the preferred EGO2 figure from configuration settings */ localEGO2 = fixedConfigs2.sensorPresets.presetEGO2; }else{ /* Default value if not connected incase other things are misconfigured */ /* Default to stoichiometric */ localEGO2 = LAMBDA(1.0); /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(EGO2_NOT_CONFIGURED_CODE); // or maybe queue it? } unsigned short localTPS; /* Get TPS percentage */ if(TRUE){ /* If TPS is connected */ /* Get TPS from ADC no need to add TPS min as we know it is zero by definition */ localTPS = ((unsigned long)boundedTPSADC * PERCENT(100)) / TPSADCRange; }else if(FALSE){ /* Configured for TPS to imitate MAP signal */ /* Get TPS from MAP via conversion */ /* Box MAP signal down */ if(localTPS > fixedConfigs2.sensorRanges.TPSOpenMAP){ /* Greater than ~95kPa */ localTPS = PERCENT(100); }else if(localTPS < fixedConfigs2.sensorRanges.TPSClosedMAP){ /* Less than ~30kPa */ localTPS = 0; }else{ /* Scale MAP range to TPS range */ localTPS = localMAP - fixedConfigs2.sensorRanges.TPSClosedMAP; } // get TPS from MAP no need to add TPS min as we know it is zero by definition localTPS = ((unsigned long)localTPS * PERCENT(100)) / (fixedConfigs2.sensorRanges.TPSOpenMAP - fixedConfigs2.sensorRanges.TPSClosedMAP); }else if(FALSE){ /* Configured for dash potentiometer on ADC */ /* Get TPS from ADC as shown : 1023 ADC = 100%, 0 ADC = 0% */ localTPS = ((unsigned long)ADCBuffers->TPS * PERCENT(100)) / ADC_DIVISIONS; }else if(FALSE){ /* Configured for fixed TPS from config */ /* Get the preferred TPS figure from configuration settings */ localTPS = fixedConfigs2.sensorPresets.presetTPS; }else{ /* Fail safe if config is broken */ /* Default to 50% to not trigger any WOT or CT conditions */ localTPS = PERCENT(50); // TODO YAGNI? /* If anyone is listening, let them know something is wrong */ sendErrorIfClear(TPS_NOT_CONFIGURED_CODE); // or maybe queue it? } /* Get RPM by locking out ISRs for a second and grabbing the Tooth logging data */ //atomic start // copy rpm data //atomic end // Calculate RPM and delta RPM and delta delta RPM from data recorded if(*ticksPerDegree != 0){ CoreVars->RPM = (unsigned short)(degreeTicksPerMinute / *ticksPerDegree); }else{ CoreVars->RPM = 0; } CoreVars->DRPM = *ticksPerDegree; // unsigned short localDRPM = 0; // unsigned short localDDRPM = 0; /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Average the variables as per the configuration &&&&&&&&&&&&&&&&&&&&&&&&&&*/ /* Strictly speaking only the primary variables need to be averaged. After that, the derived ones are */ /* already averaged in a way. However, there may be some advantage to some short term averaging on the */ /* derived ones also, so it is something to look into later. */ /// @todo TODO average the generated values here // newVal var word ' the value from the ADC // smoothed var word ' a nicely smoothed result // // if newval > smoothed then // smoothed = smoothed + (newval - smoothed)/alpha // else // smoothed = smoothed - (smoothed - newval)/alpha // endif // from : http://www.tigoe.net/pcomp/code/category/code/arduinowiring/41 // for now just copy them in. CoreVars->IAT = localIAT; CoreVars->CHT = localCHT; CoreVars->TPS = localTPS; CoreVars->EGO = localEGO; CoreVars->BRV = localBRV; CoreVars->MAP = localMAP; CoreVars->AAP = localAAP; CoreVars->MAT = localMAT; CoreVars->EGO2 = localEGO2; CoreVars->IAP = localIAP; CoreVars->MAF = localMAF; // CoreVars->DRPM = localDRPM; // CoreVars->DDRPM = localDDRPM; // CoreVars->DTPS = localDTPS; // later... unsigned short i; for(i=0;i<sizeof(CoreVar);i++){ // TODO /* Perform averaging on all primary variables as per the configuration array */ // get old value(s) // process new and old to produce result based on config array value */ // assign result to old value holder } // TODO /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ }
/** * Calculate and obtain the core variables. Each raw ADC value is converted to a * usable measurement via a variety of methods. They are then stored in a struct * and used as input to the next phase. */ void generateCoreVars(){ // Battery Reference Voltage unsigned short localBRV; if(!(fixedConfigs2.sensorSources.BRV)){ localBRV = (((unsigned long)ADCBuffers->BRV * fixedConfigs2.sensorRanges.BRVRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.BRVMinimum; }else if(fixedConfigs2.sensorSources.BRV == SOURCE_PRESET){ localBRV = fixedConfigs2.sensorPresets.presetBRV; }else if(fixedConfigs2.sensorSources.BRV == SOURCE_LINEAR){ localBRV = (ADCBuffers->BRV * 14) + VOLTS(7.2); // 0 ADC = 7.2V, 1023 ADC = 21.522C }else{ // Default to normal alternator charging voltage 14.4V localBRV = VOLTS(14.4); } // Coolant/Head Temperature unsigned short localCHT; if(!(fixedConfigs2.sensorSources.CHT)){ localCHT = CHTTransferTable[ADCBuffers->CHT]; }else if(fixedConfigs2.sensorSources.CHT == SOURCE_PRESET){ localCHT = fixedConfigs2.sensorPresets.presetCHT; }else if(fixedConfigs2.sensorSources.CHT == SOURCE_LINEAR){ localCHT = (ADCBuffers->CHT * 10) + DEGREES_C(0); // 0 ADC = 0C, 1023 ADC = 102.3C }else{ // Default to slightly cold and therefore rich: 65C localCHT = DEGREES_C(65); } // Inlet Air Temperature unsigned short localIAT; if(!(fixedConfigs2.sensorSources.IAT)){ localIAT = IATTransferTable[ADCBuffers->IAT]; }else if(fixedConfigs2.sensorSources.IAT == SOURCE_PRESET){ localIAT = fixedConfigs2.sensorPresets.presetIAT; }else if(fixedConfigs2.sensorSources.IAT == SOURCE_LINEAR){ localIAT = (ADCBuffers->IAT * 10) + DEGREES_C(0); // 0 ADC = 0C, 1023 ADC = 102.3C }else{ // Default to room temperature localIAT = DEGREES_C(20); } // Throttle Position Sensor /* Bound the TPS ADC reading and shift it to start at zero */ unsigned short unboundedTPSADC = ADCBuffers->TPS; unsigned short boundedTPSADC; if(fixedConfigs2.sensorRanges.TPSMaximumADC > fixedConfigs2.sensorRanges.TPSMinimumADC){ if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){ boundedTPSADC = TPSADCRange; }else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){ boundedTPSADC = unboundedTPSADC - fixedConfigs2.sensorRanges.TPSMinimumADC; } else{ boundedTPSADC = 0; } }else{ // Reverse slope! if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMinimumADC){ boundedTPSADC = 0; }else if(unboundedTPSADC > fixedConfigs2.sensorRanges.TPSMaximumADC){ boundedTPSADC = fixedConfigs2.sensorRanges.TPSMinimumADC - unboundedTPSADC; }else{ boundedTPSADC = TPSADCRange; } } /* Get TPS from ADC no need to add TPS min as we know it is zero by definition */ unsigned short localTPS = ((unsigned long)boundedTPSADC * PERCENT(100)) / TPSADCRange; // TODO fail safe mode, only if on the ADC rails AND configured to do so // Default to a low value that will get you home if you are in Alpha-N mode /* Get RPM by locking out ISRs for a second and grabbing the Tooth logging data */ //atomic start // copy rpm data //atomic end // Calculate RPM and delta RPM and delta delta RPM from data recorded if(*ticksPerDegree != 0){ CoreVars->RPM = (unsigned short)(degreeTicksPerMinute / *ticksPerDegree); }else{ CoreVars->RPM = 0; } CoreVars->DRPM = *ticksPerDegree; // unsigned short localDRPM = 0; // unsigned short localDDRPM = 0; // TODO This might get done somewhere else, separation of concerns, etc /*&&&&&&&&&&&&&&&&&&&&&&&&&&&& Average the variables as per the configuration &&&&&&&&&&&&&&&&&&&&&&&&&&*/ /* Strictly speaking only the primary variables need to be averaged. After that, the derived ones are */ /* already averaged in a way. However, there may be some advantage to some short term averaging on the */ /* derived ones also, so it is something to look into later. */ /// @todo TODO average the generated values here // newVal var word ' the value from the ADC // smoothed var word ' a nicely smoothed result // // if newval > smoothed then // smoothed = smoothed + (newval - smoothed)/alpha // else // smoothed = smoothed - (smoothed - newval)/alpha // endif // from : http://www.tigoe.net/pcomp/code/category/code/arduinowiring/41 // for now just copy them in. CoreVars->BRV = localBRV; CoreVars->CHT = localCHT; CoreVars->IAT = localIAT; CoreVars->TPS = localTPS; CoreVars->EGO = (((unsigned long)ADCBuffers->EGO * fixedConfigs2.sensorRanges.EGORange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.EGOMinimum; CoreVars->MAP = (((unsigned long)ADCBuffers->MAP * fixedConfigs2.sensorRanges.MAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.MAPMinimum; CoreVars->AAP = (((unsigned long)ADCBuffers->AAP * fixedConfigs2.sensorRanges.AAPRange) / ADC_DIVISIONS) + fixedConfigs2.sensorRanges.AAPMinimum; CoreVars->MAT = IATTransferTable[ADCBuffers->MAT]; // Not actually used, feed raw values for now TODO migrate these to a SpecialVars struct or similar not included in default datalog CoreVars->EGO2 = ADCBuffers->EGO2; CoreVars->IAP = ADCBuffers->IAP; CoreVars->MAF = MAFTransferTable[ADCBuffers->MAF]; // CoreVars->DRPM = localDRPM; // CoreVars->DDRPM = localDDRPM; // CoreVars->DTPS = localDTPS; }