tableLookup.c

Go to the documentation of this file.
00001 /*      tableLookup.c
00002 
00003         Copyright 2008 Fred Cooke
00004 
00005         This file is part of the FreeEMS project.
00006 
00007         FreeEMS software is free software: you can redistribute it and/or modify
00008         it under the terms of the GNU General Public License as published by
00009         the Free Software Foundation, either version 3 of the License, or
00010         (at your option) any later version.
00011 
00012         FreeEMS software is distributed in the hope that it will be useful,
00013         but WITHOUT ANY WARRANTY; without even the implied warranty of
00014         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015         GNU General Public License for more details.
00016 
00017         You should have received a copy of the GNU General Public License
00018         along with any FreeEMS software.  If not, see <http://www.gnu.org/licenses/>.
00019 
00020         We ask that if you make any changes to this file you send them upstream to us at admin@diyefi.org
00021 
00022         Thank you for choosing FreeEMS to run your engine! */
00023 
00024 #define TABLELOOKUP_C
00025 #include "inc/freeEMS.h"
00026 #include "inc/commsISRs.h"
00027 #include "inc/tableLookup.h"
00028 
00029 
00030 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00031 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00032 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ******* ******* ******* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00033 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ******* WARNING ******* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00034 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ******* ******* ******* &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00035 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00036 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00037 /*&&&&&&&&&&&&&&&&&&&&                                                               &&&&&&&&&&&&&&&&&&&*/
00038 /*&&&&&&&&&&&&&&&&&&&& These routines rely on the fact that there are no ISRs trying &&&&&&&&&&&&&&&&&&&*/
00039 /*&&&&&&&&&&&&&&&&&&&& to access the small tables and other live settings in the ram &&&&&&&&&&&&&&&&&&&*/
00040 /*&&&&&&&&&&&&&&&&&&&& window as specified by the RPAGE value. If they are then bad  &&&&&&&&&&&&&&&&&&&*/
00041 /*&&&&&&&&&&&&&&&&&&&& values WILL be occasionally read from random parts of the big &&&&&&&&&&&&&&&&&&&*/
00042 /*&&&&&&&&&&&&&&&&&&&& tables instead of the correct place. If that occurs it WILL   &&&&&&&&&&&&&&&&&&&*/
00043 /*&&&&&&&&&&&&&&&&&&&& cause unpredictable and VERY hard to find bugs!!              &&&&&&&&&&&&&&&&&&&*/
00044 /*&&&&&&&&&&&&&&&&&&&&                                                               &&&&&&&&&&&&&&&&&&&*/
00045 /*&&&&&&&&&&&&&&&&&&&&  *******  *******  YOU HAVE BEEN WARNED!!!  *******  *******  &&&&&&&&&&&&&&&&&&&*/
00046 /*&&&&&&&&&&&&&&&&&&&&                                                               &&&&&&&&&&&&&&&&&&&*/
00047 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00048 /*&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/
00049 
00050 
00051 /* Yet to be implemented :
00052 
00053 unsigned char lookup8Bit3dUC(
00054 unsigned short lookup16Bit2dUS(
00055 unsigned char lookup8Bit2dUC(
00056 signed short lookup16Bit3dSS(
00057 signed short lookup16Bit3dSS(
00058 signed char lookup8Bit3D( */
00059 
00060 
00061 /* Take a table with two movable axis sets and two axis lengths,
00062  * loop to find which pairs of axis values and indexs we are between,
00063  * interpolate two pairs down to two values,
00064  * interpolate two values down to one value.
00065  *
00066  * Warning : This function relies on the axis values being a sorted list from low to high. If this is not the case behaviour is undefined and could include memory corruption and engine damage.
00067  *
00068  * To reduce the table size from 19x24 to something smaller, simply reduce the RPMLength and LoadLength fields to lower values. Increasing the size of either axis is not currently possible.
00069  *
00070  * Given that the axis lists are in order, a data point outside the table will give the value adjacent to it, and one outside one of the four corners will give the corner value. This is a clean and reasonable behaviour in my opinion.
00071  *
00072  * Reminder : X/RPM is horizontal, Y/Load is vertical
00073  *
00074  * Save the page value to a variable, change the page value, read the table, change the page back and return the value */
00075 unsigned short lookupPagedMainTableCellValue(mainTable *Table, unsigned short realRPM, unsigned short realLoad, unsigned char RPageValue){
00076 
00077         /* Save the RPAGE value for restoration and switch pages. */
00078         unsigned char oldRPage = RPAGE;
00079         RPAGE = RPageValue;
00080 
00081         /* Find the bounding axis values and indices for RPM */
00082         unsigned char lowRPMIndex = 0;
00083         unsigned char highRPMIndex = Table->RPMLength - 1;
00084         /* If never set in the loop, low value will equal high value and will be on the edge of the map */
00085         unsigned short lowRPMValue = Table->RPM[0];
00086         unsigned short highRPMValue = Table->RPM[Table->RPMLength -1];
00087 
00088         unsigned char RPMIndex;
00089         for(RPMIndex=0;RPMIndex<Table->RPMLength;RPMIndex++){
00090                 if(Table->RPM[RPMIndex] < realRPM){
00091                         lowRPMValue = Table->RPM[RPMIndex];
00092                         lowRPMIndex = RPMIndex;
00093                 }else if(Table->RPM[RPMIndex] > realRPM){
00094                         highRPMValue = Table->RPM[RPMIndex];
00095                         highRPMIndex = RPMIndex;
00096                         break;
00097                 }else if(Table->RPM[RPMIndex] == realRPM){
00098                         lowRPMValue = Table->RPM[RPMIndex];
00099                         highRPMValue = Table->RPM[RPMIndex];
00100                         lowRPMIndex = RPMIndex;
00101                         highRPMIndex = RPMIndex;
00102                         break;
00103                 }
00104         }
00105 
00106 
00107         /* Find the bounding cell values and indices for Load */
00108         unsigned char lowLoadIndex = 0;
00109         unsigned char highLoadIndex = Table->LoadLength -1;
00110         /* If never set in the loop, low value will equal high value and will be on the edge of the map */
00111         unsigned short lowLoadValue = Table->Load[0];
00112         unsigned short highLoadValue = Table->Load[Table->LoadLength -1];
00113 
00114         unsigned char LoadIndex;
00115         for(LoadIndex=0;LoadIndex<Table->LoadLength;LoadIndex++){
00116                 if(Table->Load[LoadIndex] < realLoad){
00117                         lowLoadValue = Table->Load[LoadIndex];
00118                         lowLoadIndex = LoadIndex;
00119                 }else if(Table->Load[LoadIndex] > realLoad){
00120                         highLoadValue = Table->Load[LoadIndex];
00121                         highLoadIndex = LoadIndex;
00122                         break;
00123                 }else if(Table->Load[LoadIndex] == realLoad){
00124                         lowLoadValue = Table->Load[LoadIndex];
00125                         highLoadValue = Table->Load[LoadIndex];
00126                         lowLoadIndex = LoadIndex;
00127                         highLoadIndex = LoadIndex;
00128                         break;
00129                 }
00130         }
00131 
00132 
00133         /* Obtain the four corners surrounding the spot of interest */
00134         unsigned short lowRPMLowLoad = Table->Table[(Table->LoadLength * lowRPMIndex) + lowLoadIndex];
00135         unsigned short lowRPMHighLoad = Table->Table[(Table->LoadLength * lowRPMIndex) + highLoadIndex];
00136         unsigned short highRPMLowLoad = Table->Table[(Table->LoadLength * highRPMIndex) + lowLoadIndex];
00137         unsigned short highRPMHighLoad = Table->Table[(Table->LoadLength * highRPMIndex) + highLoadIndex];
00138 
00139 
00140         /* Restore the ram page before doing the math */
00141         RPAGE = oldRPage;
00142 
00143 
00144         /* Find the two side values to interpolate between by interpolation */
00145         unsigned short lowRPMIntLoad = lowRPMLowLoad + (((signed long)((signed long)lowRPMHighLoad - lowRPMLowLoad) * (realLoad - lowLoadValue))/ (highLoadValue - lowLoadValue));
00146         unsigned short highRPMIntLoad = highRPMLowLoad + (((signed long)((signed long)highRPMHighLoad - highRPMLowLoad) * (realLoad - lowLoadValue))/ (highLoadValue - lowLoadValue));
00147 
00148 
00149         /* Interpolate between the two side values and return the result */
00150         return lowRPMIntLoad + (((signed long)((signed long)highRPMIntLoad - lowRPMIntLoad) * (realRPM - lowRPMValue))/ (highRPMValue - lowRPMValue));
00151 }
00152 
00153 
00154 unsigned short lookupTwoDTableUS(twoDTableUS * Table, unsigned short Value){
00155 
00156         /* Find the bounding axis indices, axis values and lookup values */
00157         unsigned char lowIndex = 0;
00158         unsigned char highIndex = 15;
00159         /* If never set in the loop, low value will equal high value and will be on the edge of the map */
00160         unsigned short lowAxisValue = Table->Axis[0];
00161         unsigned short highAxisValue = Table->Axis[15];
00162         unsigned short lowLookupValue = Table->Values[0];
00163         unsigned short highLookupValue = Table->Values[15];
00164 
00165         unsigned char Index;
00166         for(Index=0;Index<16;Index++){
00167                 if(Table->Axis[Index] < Value){
00168                         lowIndex = Index;
00169                         lowAxisValue = Table->Axis[Index];
00170                         lowLookupValue = Table->Values[Index];
00171                 }else if(Table->Axis[Index] > Value){
00172                         highIndex = Index;
00173                         highAxisValue = Table->Axis[Index];
00174                         highLookupValue = Table->Values[Index];
00175                         break;
00176                 }else if(Table->Axis[Index] == Value){
00177                         return Table->Values[Index]; // If right on, just return the value
00178                 }
00179         }
00180 
00181 
00182         /* Interpolate and return the value */
00183         return lowLookupValue + (((signed long)((signed long)highLookupValue - lowLookupValue) * (Value - lowAxisValue))/ (highAxisValue - lowAxisValue));
00184 }
00185 
00186 
00187 /* Returns 0 on success and error code otherwise */
00188 unsigned short setAxisValue(unsigned short index, unsigned short value, unsigned short axis[], unsigned short length, unsigned short errorBase){
00189         if(index >= length){
00190                 return errorBase + invalidAxisIndex;
00191         }else{
00192                 if(index > 0){
00193                         /* Ensure value isn't lower than the one below */
00194                         if(axis[index - 1] > value){
00195                                 return errorBase + invalidAxisOrder;
00196                         }
00197                 }
00198                 if(index < (length -1)){
00199                         /* Ensure value isn't higher than the one above */
00200                         if(value > axis[index + 1]){
00201                                 return errorBase + invalidAxisOrder;
00202                         }
00203                 }
00204         }
00205 
00206         /* If we got this far all is well, set the value */
00207         axis[index] = value;
00208         return 0;
00209 }
00210 
00211 
00212 unsigned short setPagedMainTableCellValue(unsigned char RPageValue, mainTable* Table, unsigned short RPMIndex, unsigned short LoadIndex, unsigned short cellValue){
00213         unsigned char oldRPage = RPAGE;
00214         unsigned short errorID = 0;
00215         RPAGE = RPageValue;
00216         if(RPMIndex < Table->RPMLength){
00217                 if(LoadIndex < Table->LoadLength){
00218                         Table->Table[(Table->LoadLength * RPMIndex) + LoadIndex] = cellValue;
00219                 }else{
00220                         errorID = invalidMainTableLoadIndex;
00221                 }
00222         }else{
00223                 errorID = invalidMainTableRPMIndex;
00224         }
00225         RPAGE = oldRPage;
00226         return errorID;
00227 }
00228 
00229 
00230 unsigned short setPagedMainTableRPMValue(unsigned char RPageValue, mainTable* Table, unsigned short RPMIndex, unsigned short RPMValue){
00231         unsigned char oldRPage = RPAGE;
00232         RPAGE = RPageValue;
00233         unsigned short errorID = setAxisValue(RPMIndex, RPMValue, Table->RPM, Table->RPMLength, errorBaseMainTableRPM);
00234         RPAGE = oldRPage;
00235         return errorID;
00236 }
00237 
00238 
00239 unsigned short setPagedMainTableLoadValue(unsigned char RPageValue, mainTable* Table, unsigned short LoadIndex, unsigned short LoadValue){
00240         unsigned char oldRPage = RPAGE;
00241         RPAGE = RPageValue;
00242         unsigned short errorID = setAxisValue(LoadIndex, LoadValue, Table->Load, Table->LoadLength, errorBaseMainTableLoad);
00243         RPAGE = oldRPage;
00244         return errorID;
00245 }
00246 
00247 
00248 unsigned short setPagedTwoDTableCellValue(unsigned char RPageValue, twoDTableUS* Table, unsigned short cellIndex, unsigned short cellValue){
00249         if(cellIndex > 15){
00250                 return invalidTwoDTableIndex;
00251         }else{
00252                 unsigned char oldRPage = RPAGE;
00253                 RPAGE = RPageValue;
00254                 Table->Values[cellIndex] = cellValue;
00255                 RPAGE = oldRPage;
00256                 return 0;
00257         }
00258 }
00259 
00260 
00261 unsigned short setPagedTwoDTableAxisValue(unsigned char RPageValue, twoDTableUS* Table, unsigned short axisIndex, unsigned short axisValue){
00262         unsigned char oldRPage = RPAGE;
00263         RPAGE = RPageValue;
00264         unsigned short errorID = setAxisValue(axisIndex, axisValue, Table->Axis, 16, errorBaseTwoDTableAxis);
00265         RPAGE = oldRPage;
00266         return errorID;
00267 }
00268 
00269 
00270 /* Check that the configuration of the table is valid. Assumes pages are correctly set. */
00271 unsigned short validateMainTable(mainTable* Table){
00272         /* If required and only if required extend this to take r and f pages and check */
00273         /* any main table, not just a freshly received untrusted ones in linear space   */
00274 
00275         if(Table->RPMLength > MAINTABLE_MAX_RPM_LENGTH){
00276                 return invalidMainTableRPMLength;
00277         }else if(Table->LoadLength > MAINTABLE_MAX_LOAD_LENGTH){
00278                 return invalidMainTableLoadLength;
00279         }else if((Table->RPMLength * Table->LoadLength) > MAINTABLE_MAX_MAIN_LENGTH){
00280                 return invalidMainTableMainLength;
00281         }else{
00282                 /* Check the order of the RPM axis */
00283                 unsigned char i;
00284                 for(i=0;i<(Table->RPMLength - 1);i++){
00285                         if(Table->RPM[i] > Table->RPM[i+1]){
00286                                 return invalidMainTableRPMOrder;
00287                         }
00288                 }
00289                 /* Check the order of the Load axis */
00290                 unsigned char j;
00291                 for(j=0;j<(Table->LoadLength - 1);j++){
00292                         if(Table->Load[j] > Table->Load[j+1]){
00293                                 return invalidMainTableLoadOrder;
00294                         }
00295                 }
00296                 /* If we made it this far all is well */
00297                 return 0;
00298         }
00299 }
00300 
00301 
00302 /* Check that the configuration of the table is valid */
00303 unsigned short validateTwoDTable(twoDTableUS* Table){
00304         /* Check the order of the axis */
00305         unsigned char i;
00306         for(i=0;i<(TWODTABLEUS_LENGTH - 1);i++){
00307                 if(Table->Axis[i] > Table->Axis[i+1]){
00308                         return invalidTwoDTableAxisOrder;
00309                 }
00310         }
00311         return 0;
00312 }

Generated on Mon Dec 22 21:29:19 2008 for freeems by  doxygen 1.5.2