#include <cstdint>
#include "timing.h"
namespace
{
unsigned constexpr MAX_TIMING_POINTS = 8;
unsigned constexpr MAX_VACUUM_POINTS = 8;
unsigned constexpr TimingScale = TIMING_SCALE;
#pragma pack(push, 1)
typedef union
{
struct
{
int16_t val;
int16_t result;
};
uint32_t u32;
} dataPoint;
#pragma pack(pop)
// points in RPM, degrees
dataPoint const timing_curve[MAX_TIMING_POINTS] = {
{500, 3 * TimingScale},
{750, 0 * TimingScale},
{1000, 0 * TimingScale},
{1500, 12 * TimingScale},
{2500, 18 * TimingScale},
{3500, 22 * TimingScale},
{4500, 22 * TimingScale},
{6000, 15 * TimingScale}};
// points in mB of vacuum, degrees : initial points ordered
dataPoint const vacuum_curve[MAX_VACUUM_POINTS] = {
{0, 0 * TimingScale},
{166, 2 * TimingScale},
{225, 6 * TimingScale},
{300, 10 * TimingScale},
{700, 10 * TimingScale},
{700, 10 * TimingScale},
{-1, -1}, // filler
{-1, -1} // filler
};
// basic timing
const int baseTiming = 7 * TimingScale;
/// @brief Lookup a point using linear interpolation
/// @param point value to lookup
/// @param curve data point list
/// @param size number of data points in list
/// @return degrees * TIMING_SCALE
int lookup(int point, const dataPoint curve[], int size)
{
// check lower bounds
if (point < curve[0].val)
return curve[0].result;
// check upper bounds
// find the upper boundary by looking for non -1 points
int upper = size - 1;
while (curve[upper].result <= 0)
upper--;
if (point >= curve[upper].val)
return curve[upper].result;
for (int pt = 1; pt <= upper; pt++)
{
if ((point >= curve[pt - 1].val) && (point < curve[pt].val))
{
// how far along axis ?
int offset = point - curve[pt - 1].val;
int range1 = curve[pt].val - curve[pt - 1].val;
int range2 = curve[pt].result - curve[pt - 1].result;
return ((offset * range2) / range1) + curve[pt - 1].result;
}
}
return 0; // give up.
}
};
extern "C"
{
int timing(int rpm, int vacuumMb)
{
int angle = lookup(rpm, timing_curve, sizeof(timing_curve) / sizeof(dataPoint));
angle += lookup(vacuumMb, vacuum_curve, sizeof(vacuum_curve) / sizeof(dataPoint));
angle += baseTiming;
return angle;
}
}