2023-06-25 19:13:53 -07:00
|
|
|
// Note that all functions with an underscore prefix are NOT part
|
|
|
|
// of the public API. They are only here so we can inline them.
|
|
|
|
|
2023-03-05 22:23:17 -08:00
|
|
|
#include "scheduler.h"
|
|
|
|
#include "crankMaths.h"
|
2023-11-23 14:35:43 -08:00
|
|
|
#include "maths.h"
|
|
|
|
#include "timers.h"
|
2023-03-05 22:23:17 -08:00
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
static inline uint16_t calculateInjectorStartAngle(uint16_t pwDegrees, int16_t injChannelDegrees, uint16_t injAngle)
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2023-06-25 19:13:53 -07:00
|
|
|
// 0<=injAngle<=720°
|
|
|
|
// 0<=injChannelDegrees<=720°
|
|
|
|
// 0<pwDegrees<=??? (could be many crank rotations in the worst case!)
|
|
|
|
// 45<=CRANK_ANGLE_MAX_INJ<=720
|
|
|
|
// (CRANK_ANGLE_MAX_INJ can be as small as 360/nCylinders. E.g. 45° for 8 cylinder)
|
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
uint16_t startAngle = (uint16_t)injAngle + (uint16_t)injChannelDegrees;
|
2023-06-25 19:13:53 -07:00
|
|
|
// Avoid underflow
|
2023-11-05 14:10:08 -08:00
|
|
|
while (startAngle<pwDegrees) { startAngle = startAngle + (uint16_t)CRANK_ANGLE_MAX_INJ; }
|
2024-03-20 17:37:45 -07:00
|
|
|
// Guaranteed to be >=0.
|
2023-06-25 19:13:53 -07:00
|
|
|
startAngle = startAngle - pwDegrees;
|
|
|
|
// Clamp to 0<=startAngle<=CRANK_ANGLE_MAX_INJ
|
2023-11-05 14:10:08 -08:00
|
|
|
while (startAngle>(uint16_t)CRANK_ANGLE_MAX_INJ) { startAngle = startAngle - (uint16_t)CRANK_ANGLE_MAX_INJ; }
|
2023-06-25 19:13:53 -07:00
|
|
|
|
|
|
|
return startAngle;
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
static inline uint32_t _calculateInjectorTimeout(const FuelSchedule &schedule, uint16_t openAngle, uint16_t crankAngle) {
|
2023-06-25 19:13:53 -07:00
|
|
|
int16_t delta = openAngle - crankAngle;
|
|
|
|
if (delta<0)
|
|
|
|
{
|
|
|
|
if ((schedule.Status == RUNNING) && (delta>-CRANK_ANGLE_MAX_INJ))
|
|
|
|
{
|
2024-03-20 17:37:45 -07:00
|
|
|
// Guaranteed to be >0
|
2023-06-25 19:13:53 -07:00
|
|
|
delta = delta + CRANK_ANGLE_MAX_INJ;
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
2023-06-25 19:13:53 -07:00
|
|
|
else
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2023-06-25 19:13:53 -07:00
|
|
|
return 0;
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
2023-06-25 19:13:53 -07:00
|
|
|
}
|
2023-03-05 22:23:17 -08:00
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
return angleToTimeMicroSecPerDegree((uint16_t)delta);
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2023-06-25 19:13:53 -07:00
|
|
|
static inline int _adjustToInjChannel(int angle, int channelInjDegrees) {
|
|
|
|
angle = angle - channelInjDegrees;
|
|
|
|
if( angle < 0) { return angle + CRANK_ANGLE_MAX_INJ; }
|
|
|
|
return angle;
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
static inline uint32_t calculateInjectorTimeout(const FuelSchedule &schedule, int channelInjDegrees, int openAngle, int crankAngle)
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2024-04-04 22:31:36 -07:00
|
|
|
if (channelInjDegrees==0) {
|
|
|
|
return _calculateInjectorTimeout(schedule, openAngle, crankAngle);
|
|
|
|
}
|
|
|
|
return _calculateInjectorTimeout(schedule, _adjustToInjChannel(openAngle, channelInjDegrees), _adjustToInjChannel(crankAngle, channelInjDegrees));
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2024-03-20 17:45:10 -07:00
|
|
|
static inline void calculateIgnitionAngle(const uint16_t dwellAngle, const uint16_t channelIgnDegrees, int8_t advance, int *pEndAngle, int *pStartAngle)
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2023-11-05 14:10:08 -08:00
|
|
|
*pEndAngle = (int16_t)(channelIgnDegrees==0U ? (uint16_t)CRANK_ANGLE_MAX_IGN : channelIgnDegrees) - (int16_t)advance;
|
2023-06-25 19:13:53 -07:00
|
|
|
if(*pEndAngle > CRANK_ANGLE_MAX_IGN) {*pEndAngle -= CRANK_ANGLE_MAX_IGN;}
|
|
|
|
*pStartAngle = *pEndAngle - dwellAngle;
|
|
|
|
if(*pStartAngle < 0) {*pStartAngle += CRANK_ANGLE_MAX_IGN;}
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2024-03-20 17:45:10 -07:00
|
|
|
static inline void calculateIgnitionTrailingRotary(uint16_t dwellAngle, int rotarySplitDegrees, int leadIgnitionAngle, int *pEndAngle, int *pStartAngle)
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2023-06-25 19:13:53 -07:00
|
|
|
*pEndAngle = leadIgnitionAngle + rotarySplitDegrees;
|
|
|
|
*pStartAngle = *pEndAngle - dwellAngle;
|
|
|
|
if(*pStartAngle > CRANK_ANGLE_MAX_IGN) {*pStartAngle -= CRANK_ANGLE_MAX_IGN;}
|
|
|
|
if(*pStartAngle < 0) {*pStartAngle += CRANK_ANGLE_MAX_IGN;}
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
static inline uint32_t _calculateIgnitionTimeout(const IgnitionSchedule &schedule, int16_t startAngle, int16_t crankAngle) {
|
2023-06-25 19:13:53 -07:00
|
|
|
int16_t delta = startAngle - crankAngle;
|
|
|
|
if (delta<0)
|
|
|
|
{
|
|
|
|
if ((schedule.Status == RUNNING) && (delta>-CRANK_ANGLE_MAX_IGN))
|
|
|
|
{
|
|
|
|
// Msut be >0
|
|
|
|
delta = delta + CRANK_ANGLE_MAX_IGN;
|
|
|
|
}
|
|
|
|
else
|
2023-03-05 22:23:17 -08:00
|
|
|
{
|
2023-06-25 19:13:53 -07:00
|
|
|
return 0;
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
2023-06-25 19:13:53 -07:00
|
|
|
}
|
2023-11-05 14:10:08 -08:00
|
|
|
return angleToTimeMicroSecPerDegree(delta);
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
|
|
|
|
2023-06-25 19:13:53 -07:00
|
|
|
static inline uint16_t _adjustToIgnChannel(int angle, int channelInjDegrees) {
|
|
|
|
angle = angle - channelInjDegrees;
|
|
|
|
if( angle < 0) { return angle + CRANK_ANGLE_MAX_IGN; }
|
|
|
|
return angle;
|
|
|
|
}
|
2023-03-05 22:23:17 -08:00
|
|
|
|
2023-11-05 14:10:08 -08:00
|
|
|
static inline uint32_t calculateIgnitionTimeout(const IgnitionSchedule &schedule, int startAngle, int channelIgnDegrees, int crankAngle)
|
2023-06-25 19:13:53 -07:00
|
|
|
{
|
|
|
|
if (channelIgnDegrees==0) {
|
|
|
|
return _calculateIgnitionTimeout(schedule, startAngle, crankAngle);
|
|
|
|
}
|
|
|
|
return _calculateIgnitionTimeout(schedule, _adjustToIgnChannel(startAngle, channelIgnDegrees), _adjustToIgnChannel(crankAngle, channelIgnDegrees));
|
2023-03-05 22:23:17 -08:00
|
|
|
}
|
2023-11-23 14:35:43 -08:00
|
|
|
|
|
|
|
#define MIN_CYCLES_FOR_ENDCOMPARE 6
|
|
|
|
|
|
|
|
inline void adjustCrankAngle(IgnitionSchedule &schedule, int endAngle, int crankAngle) {
|
|
|
|
if( (schedule.Status == RUNNING) ) {
|
|
|
|
SET_COMPARE(schedule.compare, schedule.counter + uS_TO_TIMER_COMPARE( angleToTimeMicroSecPerDegree( ignitionLimits( (endAngle - crankAngle) ) ) ) );
|
|
|
|
}
|
|
|
|
else if(currentStatus.startRevolutions > MIN_CYCLES_FOR_ENDCOMPARE) {
|
|
|
|
schedule.endCompare = schedule.counter + uS_TO_TIMER_COMPARE( angleToTimeMicroSecPerDegree( ignitionLimits( (endAngle - crankAngle) ) ) );
|
|
|
|
schedule.endScheduleSetByDecoder = true;
|
|
|
|
}
|
|
|
|
}
|