Subversion Repositories libIgnTiming

Rev

Rev 6 | Rev 8 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <cstdint>
  2. #include <assert.h>
  3. #include "libIgnTiming/timing.h"
  4. #if defined __cplusplus
  5. extern "C"
  6. {
  7. #endif
  8.  
  9.     namespace
  10.     {
  11.  
  12.         unsigned constexpr INTERP_SCALE = 256;
  13.  
  14.         int constexpr TimingScale = TIMING_SCALE;
  15.         int16_t constexpr NO_DATA = -1;
  16.  
  17.         int16_t MAX_ADVANCE = 50 * TIMING_SCALE;
  18.         int16_t MIN_ADVANCE = 7 * TIMING_SCALE;
  19.  
  20.         int8_t timingAdjust = 0; // in TIMING_SCALE
  21.         // array of column headings
  22.         int16_t rpmMap[MAX_RPM_POINTS] = {400, 750, 1000, 1500, 2500, 3500, 4500, 6000};
  23.         // column of row values - in 1000-pressure
  24.         int16_t vacuumMap[MAX_VACUUM_POINTS] = {0, 166, 225, 300, 700, 1000, NO_DATA, NO_DATA};
  25.         uint8_t mapping[MAX_VACUUM_POINTS][MAX_RPM_POINTS] = {
  26.             /* Table in degrees. */
  27.             /* row for 0mb = centrifugal only */
  28.             {12, 7, 7, 19, 25, 29, 29, 22},
  29.             /* row for 166 mB*/
  30.             {12, 7, 7, 21, 27, 31, 31, 24},
  31.             /*   row for 225 mB */
  32.             {12, 7, 7, 25, 31, 35, 35, 28},
  33.             /* row for 300 mB*/
  34.             {12, 7, 7, 29, 35, 39, 39, 33},
  35.             /* row for 700 mB*/
  36.             {12, 7, 7, 29, 35, 39, 39, 33},
  37.             /* row for 1000 mB - used when pressure drops off the scale */
  38.             {7, 7, 7, 7, 7, 7, 7, 7},
  39.             /* unused */
  40.             {0, 0, 0, 0, 0, 0, 0, 0},
  41.             /* unused */
  42.             {0, 0, 0, 0, 0, 0, 0, 0},
  43.             /* unused */
  44.  
  45.         };
  46.  
  47.     }
  48.  
  49.     uint8_t getTimingAdjust() { return timingAdjust; };
  50.  
  51.     void setTimingAdjust(int8_t adjust) { timingAdjust = adjust; }
  52.  
  53.     int16_t getRpmMap(unsigned int i)
  54.     {
  55.         if (i >= 0 && i < MAX_RPM_POINTS)
  56.             return rpmMap[i];
  57.         else
  58.             return 0;
  59.     }
  60.  
  61.     void setRpmMap(unsigned int i, uint16_t val)
  62.     {
  63.         if (i >= 0 && i < MAX_RPM_POINTS)
  64.             rpmMap[i] = val;
  65.     }
  66.  
  67.     uint16_t getVacuumMap(unsigned int i)
  68.     {
  69.         if (i >= 0 && i < MAX_VACUUM_POINTS)
  70.             return vacuumMap[i];
  71.         else
  72.             return 0;
  73.     }
  74.  
  75.     void setVacuumMap(unsigned int i, uint16_t val)
  76.     {
  77.         if (i >= 0 && i < MAX_VACUUM_POINTS)
  78.             vacuumMap[i] = val;
  79.     }
  80.  
  81.     void setTiming(unsigned int vacuumIndex, unsigned int rpmIndex, uint8_t value)
  82.     {
  83.         if (vacuumIndex < 0 && vacuumIndex >= MAX_VACUUM_POINTS)
  84.             return;
  85.         if (rpmIndex < 0 && rpmIndex >= MAX_RPM_POINTS)
  86.             return;
  87.         mapping[vacuumIndex][rpmIndex] = value;
  88.     }
  89.  
  90.     uint8_t getTiming(unsigned int vacuumIndex, unsigned int rpmIndex)
  91.     {
  92.         if (vacuumIndex < 0 && vacuumIndex >= MAX_VACUUM_POINTS)
  93.             return 0;
  94.         if (rpmIndex < 0 && rpmIndex >= MAX_RPM_POINTS)
  95.             return 0;
  96.         return mapping[vacuumIndex][rpmIndex];
  97.     }
  98.  
  99.     int lookup(int point, int16_t const curve[], int size, int16_t *frac)
  100.     {
  101.         // check lower bounds
  102.         if (point < curve[0])
  103.         {
  104.             *frac = 0;
  105.             return 0;
  106.         }
  107.         // check upper bounds
  108.         // find the upper boundary by looking for non -1 points
  109.         int upper = size - 1;
  110.         while (curve[upper] == NO_DATA)
  111.             upper--;
  112.  
  113.         if (point >= curve[upper])
  114.         {
  115.             *frac = 0;
  116.             return upper;
  117.         }
  118.         for (int pt = 1; pt <= upper; pt++)
  119.         {
  120.             if ((point >= curve[pt - 1]) && (point < curve[pt]))
  121.             {
  122.  
  123.                 int range1 = curve[pt] - curve[pt - 1];
  124.  
  125.                 if (range1 == 0)
  126.                 {
  127.                     *frac = 0;
  128.                     return pt - 1;
  129.                 }
  130.  
  131.                 // how far along axis ?
  132.                 int offset = point - curve[pt - 1];
  133.  
  134.                 int range2 = INTERP_SCALE;
  135.  
  136.                 *frac = ((offset * range2) / range1);
  137.                 return pt - 1;
  138.             }
  139.         }
  140.         *frac = 0;
  141.         return -1; // give up.
  142.     };
  143.  
  144.     extern "C"
  145.     {
  146.  
  147.         int mapTiming(int rpm, int vacuumMb)
  148.         {
  149.             int angle = 0;
  150.             /* lookup the interpolated RPM point */
  151.             int16_t rpm_frac = 0;
  152.             int rpm_index = lookup(rpm, rpmMap, MAX_RPM_POINTS, &rpm_frac);
  153.             if (rpm_index == NO_DATA)
  154.                 return timingAdjust + MIN_ADVANCE;
  155.  
  156.             /* lookup the interpolated vacuum point */
  157.             int16_t vacuum_frac = 0;
  158.             int vacuum_index = lookup(vacuumMb, vacuumMap, MAX_VACUUM_POINTS, &vacuum_frac);
  159.             /* if there is a problem, bail out */
  160.             if (vacuum_index == NO_DATA)
  161.                 return timingAdjust + MIN_ADVANCE;
  162.  
  163.             /* perform a bilinear mapping */
  164.             int top_advance;
  165.             // we now have a position between two points in X and Y
  166.             if (rpm_frac == 0)
  167.                 top_advance = mapping[vacuum_index][rpm_index] * INTERP_SCALE;
  168.             // if fractional part then interpolate points off the map
  169.             else
  170.                 top_advance = mapping[vacuum_index][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index][rpm_index + 1] * rpm_frac;
  171.  
  172.             int bottom_advance;
  173.             // if no fractional part, then the top and bottom advance point is the same
  174.             if (vacuum_frac == 0)
  175.             {
  176.                 angle = top_advance * TimingScale / INTERP_SCALE;
  177.             }
  178.             else
  179.             {
  180.                 bottom_advance = mapping[vacuum_index + 1][rpm_index] * (INTERP_SCALE - rpm_frac) + mapping[vacuum_index + 1][rpm_index + 1] * rpm_frac;
  181.                 /* interpolate down Y axis this time */
  182.                 int advance = top_advance * (INTERP_SCALE - vacuum_frac) + bottom_advance * vacuum_frac;
  183.                 /* point is scaled by two multiplications */
  184.                 angle = advance * TimingScale / (INTERP_SCALE * INTERP_SCALE);
  185.             }
  186.  
  187.             if (angle < MIN_ADVANCE)
  188.                 angle = MIN_ADVANCE;
  189.             if (angle > MAX_ADVANCE)
  190.                 angle = MAX_ADVANCE;
  191.  
  192.             return angle + timingAdjust;
  193.         }
  194.     }
  195. #if defined __cplusplus
  196. }
  197. #endif
  198.