2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* @file injector_central.cpp
|
|
|
|
* @brief Utility methods related to fuel injection.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @date Sep 8, 2013
|
2017-01-03 03:05:22 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2017
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// todo: rename this file
|
|
|
|
#include "main.h"
|
|
|
|
|
|
|
|
#if EFI_ENGINE_CONTROL || defined(__DOXYGEN__)
|
|
|
|
|
|
|
|
#include "injector_central.h"
|
|
|
|
#include "io_pins.h"
|
|
|
|
#include "signal_executor.h"
|
|
|
|
#include "main_trigger_callback.h"
|
|
|
|
#include "engine_configuration.h"
|
|
|
|
#include "pin_repository.h"
|
|
|
|
#include "efiGpio.h"
|
|
|
|
|
|
|
|
EXTERN_ENGINE
|
|
|
|
;
|
|
|
|
|
2016-03-14 20:01:43 -07:00
|
|
|
static Logging * logger;
|
2016-01-11 14:01:33 -08:00
|
|
|
static bool isRunningBench = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-09-15 11:02:45 -07:00
|
|
|
static int is_injector_enabled[INJECTION_PIN_COUNT];
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2016-01-11 14:01:33 -08:00
|
|
|
bool isRunningBenchTest(void) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return isRunningBench;
|
|
|
|
}
|
|
|
|
|
|
|
|
void assertCylinderId(int cylinderId, const char *msg) {
|
|
|
|
int isValid = cylinderId >= 1 && cylinderId <= engineConfiguration->specs.cylindersCount;
|
|
|
|
if (!isValid) {
|
|
|
|
// we are here only in case of a fatal issue - at this point it is fine to make some blocking i-o
|
|
|
|
//scheduleSimpleMsg(&logger, "cid=", cylinderId);
|
|
|
|
print("ERROR [%s] cid=%d\r\n", msg, cylinderId);
|
|
|
|
efiAssertVoid(false, "Cylinder ID");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param cylinderId - from 1 to NUMBER_OF_CYLINDERS
|
|
|
|
*/
|
|
|
|
int isInjectorEnabled(int cylinderId) {
|
|
|
|
assertCylinderId(cylinderId, "isInjectorEnabled");
|
|
|
|
return is_injector_enabled[cylinderId - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printStatus(void) {
|
|
|
|
for (int id = 1; id <= engineConfiguration->specs.cylindersCount; id++) {
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "injector_%d_%d", isInjectorEnabled(id));
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setInjectorEnabled(int id, int value) {
|
|
|
|
efiAssertVoid(id >= 0 && id < engineConfiguration->specs.cylindersCount, "injector id");
|
|
|
|
is_injector_enabled[id] = value;
|
|
|
|
printStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void runBench(brain_pin_e brainPin, OutputPin *output, float delayMs, float onTimeMs, float offTimeMs,
|
|
|
|
int count) {
|
2016-07-07 17:02:39 -07:00
|
|
|
int delaySt = delayMs < 1 ? 1 : MS2ST(delayMs);
|
|
|
|
int onTimeSt = onTimeMs < 1 ? 1 : MS2ST(onTimeMs);
|
|
|
|
int offTimeSt = offTimeMs < 1 ? 1 : MS2ST(offTimeMs);
|
2015-07-10 06:01:56 -07:00
|
|
|
if (delaySt < 0) {
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "Invalid delay %f", delayMs);
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (onTimeSt <= 0) {
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "Invalid onTime %f", onTimeMs);
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (offTimeSt <= 0) {
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "Invalid offTime %f", offTimeMs);
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "Running bench: ON_TIME=%f ms OFF_TIME=%fms Counter=%d", onTimeMs, offTimeMs, count);
|
|
|
|
scheduleMsg(logger, "output on %s", hwPortname(brainPin));
|
2015-07-10 06:01:56 -07:00
|
|
|
|
|
|
|
if (delaySt != 0) {
|
|
|
|
chThdSleep(delaySt);
|
|
|
|
}
|
|
|
|
|
|
|
|
isRunningBench = true;
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
output->setValue(true);
|
|
|
|
chThdSleep(onTimeSt);
|
|
|
|
output->setValue(false);
|
|
|
|
chThdSleep(offTimeSt);
|
|
|
|
}
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "Done!");
|
2015-07-10 06:01:56 -07:00
|
|
|
isRunningBench = false;
|
|
|
|
}
|
|
|
|
|
2016-01-11 14:01:33 -08:00
|
|
|
static volatile bool needToRunBench = false;
|
2015-07-10 06:01:56 -07:00
|
|
|
static float onTime;
|
|
|
|
static float offTime;
|
|
|
|
static float delayMs;
|
|
|
|
static int count;
|
|
|
|
static brain_pin_e brainPin;
|
|
|
|
static OutputPin* pinX;
|
|
|
|
|
|
|
|
static void pinbench(const char *delayStr, const char *onTimeStr, const char *offTimeStr, const char *countStr,
|
|
|
|
OutputPin* pinParam, brain_pin_e brainPinParam) {
|
|
|
|
delayMs = atoff(delayStr);
|
|
|
|
onTime = atoff(onTimeStr);
|
|
|
|
offTime = atoff(offTimeStr);
|
|
|
|
count = atoi(countStr);
|
|
|
|
|
|
|
|
brainPin = brainPinParam;
|
|
|
|
pinX = pinParam;
|
|
|
|
needToRunBench = true;
|
|
|
|
}
|
|
|
|
|
2016-03-14 21:01:37 -07:00
|
|
|
static void doRunFuel(int humanIndex, const char *delayStr, const char * onTimeStr, const char *offTimeStr,
|
|
|
|
const char *countStr) {
|
|
|
|
if (humanIndex < 1 || humanIndex > engineConfiguration->specs.cylindersCount) {
|
|
|
|
scheduleMsg(logger, "Invalid index: %d", humanIndex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
brain_pin_e b = boardConfiguration->injectionPins[humanIndex - 1];
|
|
|
|
pinbench(delayStr, onTimeStr, offTimeStr, countStr, &enginePins.injectors[humanIndex - 1], b);
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* delay 100, cylinder #2, 5ms ON, 1000ms OFF, repeat 2 times
|
|
|
|
* fuelbench2 100 2 5 1000 2
|
|
|
|
*/
|
|
|
|
static void fuelbench2(const char *delayStr, const char *indexStr, const char * onTimeStr, const char *offTimeStr,
|
|
|
|
const char *countStr) {
|
|
|
|
int index = atoi(indexStr);
|
2016-03-14 21:01:37 -07:00
|
|
|
doRunFuel(index, delayStr, onTimeStr, offTimeStr, countStr);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void fanBench(void) {
|
|
|
|
pinbench("0", "3000", "100", "1", &enginePins.fanRelay, boardConfiguration->fanPin);
|
|
|
|
}
|
|
|
|
|
|
|
|
void milBench(void) {
|
2017-01-14 10:06:21 -08:00
|
|
|
pinbench("0", "500", "500", "16", &enginePins.checkEnginePin, boardConfiguration->malfunctionIndicatorPin);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2016-01-07 18:02:35 -08:00
|
|
|
void fuelPumpBenchExt(const char *durationMs) {
|
|
|
|
pinbench("0", durationMs, "100", "1", &enginePins.fuelPumpRelay, boardConfiguration->fuelPumpPin);
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void fuelPumpBench(void) {
|
2016-01-07 18:02:35 -08:00
|
|
|
fuelPumpBenchExt("3000");
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// fuelbench 5 1000 2
|
|
|
|
static void fuelbench(const char * onTimeStr, const char *offTimeStr, const char *countStr) {
|
|
|
|
fuelbench2("0", "1", onTimeStr, offTimeStr, countStr);
|
|
|
|
}
|
|
|
|
|
2016-03-14 21:01:37 -07:00
|
|
|
static void doRunSpark(int humanIndex, const char *delayStr, const char * onTimeStr, const char *offTimeStr,
|
|
|
|
const char *countStr) {
|
|
|
|
if (humanIndex < 1 || humanIndex > engineConfiguration->specs.cylindersCount) {
|
|
|
|
scheduleMsg(logger, "Invalid index: %d", humanIndex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
brain_pin_e b = boardConfiguration->ignitionPins[humanIndex - 1];
|
|
|
|
pinbench(delayStr, onTimeStr, offTimeStr, countStr, &enginePins.coils[humanIndex - 1], b);
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
/**
|
|
|
|
* sparkbench2 0 1 5 1000 2
|
|
|
|
*/
|
|
|
|
static void sparkbench2(const char *delayStr, const char *indexStr, const char * onTimeStr, const char *offTimeStr,
|
|
|
|
const char *countStr) {
|
|
|
|
int index = atoi(indexStr);
|
2016-03-14 21:01:37 -07:00
|
|
|
doRunSpark(index, delayStr, onTimeStr, offTimeStr, countStr);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sparkbench 5 400 2
|
|
|
|
* 5 ms ON, 400 ms OFF, two times
|
|
|
|
*/
|
|
|
|
static void sparkbench(const char * onTimeStr, const char *offTimeStr, const char *countStr) {
|
|
|
|
sparkbench2("0", "1", onTimeStr, offTimeStr, countStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static THD_WORKING_AREA(benchThreadStack, UTILITY_THREAD_STACK_SIZE);
|
|
|
|
|
|
|
|
static msg_t benchThread(int param) {
|
|
|
|
(void) param;
|
|
|
|
chRegSetThreadName("BenchThread");
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
while (!needToRunBench) {
|
|
|
|
chThdSleepMilliseconds(200);
|
|
|
|
}
|
|
|
|
needToRunBench = false;
|
|
|
|
runBench(brainPin, pinX, delayMs, onTime, offTime, count);
|
|
|
|
}
|
|
|
|
#if defined __GNUC__
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-09-14 16:03:00 -07:00
|
|
|
static void unregister(brain_pin_e currentPin, OutputPin *output) {
|
2015-07-10 06:01:56 -07:00
|
|
|
if (currentPin == GPIO_UNASSIGNED)
|
|
|
|
return;
|
2016-03-14 20:01:43 -07:00
|
|
|
scheduleMsg(logger, "unregistering %s", hwPortname(currentPin));
|
2015-07-10 06:01:56 -07:00
|
|
|
unmarkPin(currentPin);
|
|
|
|
output->unregister();
|
|
|
|
}
|
|
|
|
|
2016-09-14 16:03:00 -07:00
|
|
|
void unregisterOutput(brain_pin_e oldPin, brain_pin_e newPin, OutputPin *output) {
|
|
|
|
if (oldPin != newPin) {
|
|
|
|
unregister(oldPin, output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 06:01:56 -07:00
|
|
|
void stopIgnitionPins(void) {
|
|
|
|
for (int i = 0; i < IGNITION_PIN_COUNT; i++) {
|
2016-09-13 21:03:14 -07:00
|
|
|
NamedOutputPin *output = &enginePins.coils[i];
|
2016-09-14 16:03:00 -07:00
|
|
|
unregisterOutput(activeConfiguration.bc.ignitionPins[i],
|
|
|
|
engineConfiguration->bc.ignitionPins[i], output);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void stopInjectionPins(void) {
|
|
|
|
for (int i = 0; i < INJECTION_PIN_COUNT; i++) {
|
|
|
|
NamedOutputPin *output = &enginePins.injectors[i];
|
2016-09-14 16:03:00 -07:00
|
|
|
unregisterOutput(activeConfiguration.bc.injectionPins[i],
|
|
|
|
engineConfiguration->bc.injectionPins[i], output);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void startIgnitionPins(void) {
|
|
|
|
for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
|
|
|
NamedOutputPin *output = &enginePins.coils[i];
|
2016-04-26 09:01:47 -07:00
|
|
|
// todo: we need to check if mode has changed
|
2015-07-10 06:01:56 -07:00
|
|
|
if (boardConfiguration->ignitionPins[i] != activeConfiguration.bc.ignitionPins[i]) {
|
2017-04-21 15:11:36 -07:00
|
|
|
output->initPin(output->name, boardConfiguration->ignitionPins[i],
|
2015-07-10 06:01:56 -07:00
|
|
|
&boardConfiguration->ignitionPinMode);
|
|
|
|
}
|
|
|
|
}
|
2016-04-26 09:01:47 -07:00
|
|
|
// todo: we need to check if mode has changed
|
|
|
|
if (engineConfiguration->dizzySparkOutputPin != activeConfiguration.dizzySparkOutputPin) {
|
2017-04-21 15:11:36 -07:00
|
|
|
enginePins.dizzyOutput.initPin("dizzy tach", engineConfiguration->dizzySparkOutputPin,
|
2016-04-26 09:01:47 -07:00
|
|
|
&engineConfiguration->dizzySparkOutputPinMode);
|
|
|
|
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void startInjectionPins(void) {
|
|
|
|
// todo: should we move this code closer to the injection logic?
|
|
|
|
for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
|
|
|
NamedOutputPin *output = &enginePins.injectors[i];
|
2016-04-26 09:01:47 -07:00
|
|
|
// todo: we need to check if mode has changed
|
2015-07-10 06:01:56 -07:00
|
|
|
if (engineConfiguration->bc.injectionPins[i] != activeConfiguration.bc.injectionPins[i]) {
|
|
|
|
|
2017-04-21 15:11:36 -07:00
|
|
|
output->initPin(output->name, boardConfiguration->injectionPins[i],
|
2015-07-10 06:01:56 -07:00
|
|
|
&boardConfiguration->injectionPinMode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-14 20:01:43 -07:00
|
|
|
void runIoTest(int subsystem, int index) {
|
|
|
|
scheduleMsg(logger, "IO test subsystem=%d index=%d", subsystem, index);
|
|
|
|
|
2016-03-14 21:01:37 -07:00
|
|
|
if (subsystem == 0x12) {
|
|
|
|
doRunSpark(index, "300", "4", "400", "3");
|
|
|
|
} else if (subsystem == 0x13) {
|
2016-03-15 10:01:47 -07:00
|
|
|
doRunFuel(index, "300", "4", "400", "3");
|
|
|
|
} else if (subsystem == 0x14) {
|
|
|
|
fuelPumpBench();
|
|
|
|
} else if (subsystem == 0x15) {
|
|
|
|
fanBench();
|
|
|
|
} else if (subsystem == 0x16) {
|
|
|
|
milBench();
|
|
|
|
} else if (subsystem == 0x17) {
|
2016-03-14 21:01:37 -07:00
|
|
|
}
|
2016-03-14 20:01:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void initInjectorCentral(Logging *sharedLogger) {
|
|
|
|
logger = sharedLogger;
|
2015-07-10 06:01:56 -07:00
|
|
|
chThdCreateStatic(benchThreadStack, sizeof(benchThreadStack), NORMALPRIO, (tfunc_t) benchThread, NULL);
|
|
|
|
|
|
|
|
for (int i = 0; i < engineConfiguration->specs.cylindersCount; i++) {
|
|
|
|
is_injector_enabled[i] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
startInjectionPins();
|
|
|
|
startIgnitionPins();
|
|
|
|
|
|
|
|
printStatus();
|
|
|
|
addConsoleActionII("injector", setInjectorEnabled);
|
|
|
|
|
|
|
|
addConsoleAction("fuelpumpbench", fuelPumpBench);
|
2016-01-07 18:02:35 -08:00
|
|
|
addConsoleActionS("fuelpumpbench2", fuelPumpBenchExt);
|
2015-07-10 06:01:56 -07:00
|
|
|
addConsoleAction("fanbench", fanBench);
|
|
|
|
|
|
|
|
addConsoleAction("milbench", milBench);
|
|
|
|
addConsoleActionSSS("fuelbench", fuelbench);
|
|
|
|
addConsoleActionSSS("sparkbench", sparkbench);
|
|
|
|
|
|
|
|
addConsoleActionSSSSS("fuelbench2", fuelbench2);
|
|
|
|
addConsoleActionSSSSS("sparkbench2", sparkbench2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|