Subversion Repositories libIgnTiming

Rev

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

Rev Author Line No. Line
2 mjames 1
#include <cstdint>
2
#include <assert.h>
3
#include "libIgnTiming/timing.h"
7 mjames 4
#if defined __cplusplus
5
extern "C"
2 mjames 6
{
7 mjames 7
#endif
2 mjames 8
 
7 mjames 9
    namespace
10
    {
2 mjames 11
 
7 mjames 12
        unsigned constexpr INTERP_SCALE = 256;
2 mjames 13
 
7 mjames 14
        int constexpr TimingScale = TIMING_SCALE;
15
        int16_t constexpr NO_DATA = -1;
6 mjames 16
 
7 mjames 17
        int16_t MAX_ADVANCE = 50 * TIMING_SCALE;
18
        int16_t MIN_ADVANCE = 7 * TIMING_SCALE;
2 mjames 19
 
7 mjames 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 */
2 mjames 44
 
7 mjames 45
        };
6 mjames 46
 
7 mjames 47
    }
6 mjames 48
 
7 mjames 49
    uint8_t getTimingAdjust() { return timingAdjust; };
6 mjames 50
 
7 mjames 51
    void setTimingAdjust(int8_t adjust) { timingAdjust = adjust; }
6 mjames 52
 
7 mjames 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
    }
6 mjames 60
 
7 mjames 61
    void setRpmMap(unsigned int i, uint16_t val)
62
    {
63
        if (i >= 0 && i < MAX_RPM_POINTS)
64
            rpmMap[i] = val;
65
    }
6 mjames 66
 
7 mjames 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
    }
6 mjames 74
 
7 mjames 75
    void setVacuumMap(unsigned int i, uint16_t val)
76
    {
77
        if (i >= 0 && i < MAX_VACUUM_POINTS)
78
            vacuumMap[i] = val;
79
    }
6 mjames 80
 
7 mjames 81
    void setTiming(unsigned int vacuumIndex, unsigned int rpmIndex, uint8_t value)
2 mjames 82
    {
7 mjames 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;
2 mjames 88
    }
89
 
7 mjames 90
    uint8_t getTiming(unsigned int vacuumIndex, unsigned int rpmIndex)
2 mjames 91
    {
7 mjames 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];
2 mjames 97
    }
7 mjames 98
 
99
    int lookup(int point, int16_t const curve[], int size, int16_t *frac)
2 mjames 100
    {
7 mjames 101
        // check lower bounds
102
        if (point < curve[0])
2 mjames 103
        {
7 mjames 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--;
2 mjames 112
 
7 mjames 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
            {
2 mjames 122
 
7 mjames 123
                int range1 = curve[pt] - curve[pt - 1];
2 mjames 124
 
7 mjames 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
            }
2 mjames 139
        }
7 mjames 140
        *frac = 0;
141
        return -1; // give up.
142
    };
2 mjames 143
 
7 mjames 144
    extern "C"
2 mjames 145
    {
146
 
7 mjames 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;
2 mjames 155
 
7 mjames 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;
2 mjames 162
 
7 mjames 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;
2 mjames 193
        }
194
    }
7 mjames 195
#if defined __cplusplus
2 mjames 196
}
7 mjames 197
#endif