2014-10-03 12:05:03 -07:00
|
|
|
/**
|
2014-12-27 13:03:38 -08:00
|
|
|
* @file fsio_core.cpp
|
|
|
|
* @brief core FSUI handling logic
|
2014-10-09 00:02:51 -07:00
|
|
|
*
|
|
|
|
* Here we parse and evaluate logical expressions in
|
|
|
|
* http://en.wikipedia.org/wiki/Reverse_Polish_notation
|
|
|
|
*
|
|
|
|
* Once the expressions are parsed on startup (that's a heavy operation),
|
|
|
|
* evaluating those is relatively efficient.
|
|
|
|
*
|
2014-10-03 12:05:03 -07:00
|
|
|
*
|
|
|
|
* @date Oct 3, 2014
|
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2014
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "main.h"
|
2014-12-24 10:05:36 -08:00
|
|
|
|
2014-12-27 12:03:41 -08:00
|
|
|
#if EFI_FSIO || defined(__DOXYGEN__)
|
2014-12-24 10:05:36 -08:00
|
|
|
|
2014-12-27 13:03:38 -08:00
|
|
|
#include "fsio_core.h"
|
|
|
|
#include "fsio_impl.h"
|
2014-10-03 12:05:03 -07:00
|
|
|
|
2014-10-04 15:03:07 -07:00
|
|
|
LENameOrdinalPair * LE_FIRST = NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* the main point of these static fields is that their constructor would register
|
|
|
|
* them in the magic list of operator name/ordinal pairs
|
|
|
|
*/
|
|
|
|
static LENameOrdinalPair leAnd(LE_OPERATOR_AND, "and");
|
2014-12-10 07:03:10 -08:00
|
|
|
static LENameOrdinalPair leAnd2(LE_OPERATOR_AND, "&");
|
2014-10-04 15:03:07 -07:00
|
|
|
static LENameOrdinalPair leOr(LE_OPERATOR_OR, "or");
|
2014-12-10 07:03:10 -08:00
|
|
|
static LENameOrdinalPair leOr2(LE_OPERATOR_OR, "|");
|
2014-11-17 12:03:37 -08:00
|
|
|
static LENameOrdinalPair leNot(LE_OPERATOR_NOT, "not");
|
|
|
|
|
2014-11-18 18:05:41 -08:00
|
|
|
static LENameOrdinalPair leAdd(LE_OPERATOR_ADDITION, "+");
|
|
|
|
static LENameOrdinalPair leSub(LE_OPERATOR_SUBSTRACTION, "-");
|
|
|
|
static LENameOrdinalPair leMul(LE_OPERATOR_MULTIPLICATION, "*");
|
|
|
|
static LENameOrdinalPair leDiv(LE_OPERATOR_DIVISION, "/");
|
|
|
|
|
2014-10-04 15:03:07 -07:00
|
|
|
static LENameOrdinalPair leMore(LE_OPERATOR_MORE, ">");
|
|
|
|
static LENameOrdinalPair leMoreOrEqual(LE_OPERATOR_MORE_OR_EQUAL, ">=");
|
2014-11-17 12:03:37 -08:00
|
|
|
|
|
|
|
static LENameOrdinalPair leLess(LE_OPERATOR_LESS, "<");
|
|
|
|
static LENameOrdinalPair leLessOrEquals(LE_OPERATOR_LESS_OR_EQUAL, "<=");
|
2014-10-05 07:03:00 -07:00
|
|
|
|
2014-12-04 17:03:09 -08:00
|
|
|
static LENameOrdinalPair leMax(LE_METHOD_MAX, "max");
|
|
|
|
static LENameOrdinalPair leMin(LE_METHOD_MIN, "min");
|
2014-12-04 18:03:12 -08:00
|
|
|
static LENameOrdinalPair leIf(LE_METHOD_IF, "if");
|
2014-12-04 17:03:09 -08:00
|
|
|
|
2014-10-04 15:03:07 -07:00
|
|
|
LENameOrdinalPair::LENameOrdinalPair(le_action_e action, const char *name) {
|
|
|
|
this->action = action;
|
|
|
|
this->name = name;
|
2014-10-05 07:03:00 -07:00
|
|
|
this->next = LE_FIRST;
|
2014-10-04 15:03:07 -07:00
|
|
|
LE_FIRST = this;
|
|
|
|
}
|
|
|
|
|
2014-10-03 12:05:03 -07:00
|
|
|
LEElement::LEElement() {
|
|
|
|
action = LE_UNDEFINED;
|
|
|
|
next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//void LEElement::init(le_action_e action, int iValue) {
|
|
|
|
// this->action = action;
|
|
|
|
// this->iValue = iValue;
|
|
|
|
//}
|
|
|
|
|
|
|
|
void LEElement::init(le_action_e action) {
|
|
|
|
this->action = action;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LEElement::init(le_action_e action, float fValue) {
|
|
|
|
this->action = action;
|
|
|
|
this->fValue = fValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
LECalculator::LECalculator() {
|
2014-10-03 15:03:01 -07:00
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LECalculator::reset() {
|
2014-10-03 12:05:03 -07:00
|
|
|
first = NULL;
|
2014-10-03 15:03:01 -07:00
|
|
|
stack.reset();
|
2014-10-03 12:05:03 -07:00
|
|
|
}
|
|
|
|
|
2014-10-06 02:03:01 -07:00
|
|
|
void LECalculator::reset(LEElement *element) {
|
|
|
|
first = NULL;
|
|
|
|
stack.reset();
|
|
|
|
add(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LECalculator::add(LEElement *element) {
|
|
|
|
if (first == NULL) {
|
|
|
|
first = element;
|
|
|
|
} else {
|
|
|
|
LEElement *last = first;
|
|
|
|
while (last->next != NULL) {
|
|
|
|
last = last->next;
|
|
|
|
}
|
|
|
|
last->next = element;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-03 14:03:00 -07:00
|
|
|
static bool float2bool(float v) {
|
|
|
|
return v != 0;
|
|
|
|
}
|
2014-10-03 12:05:03 -07:00
|
|
|
|
2014-10-07 08:04:35 -07:00
|
|
|
float LECalculator::pop(le_action_e action) {
|
|
|
|
if (stack.size() == 0) {
|
|
|
|
firmwareError("empty stack for %d", action);
|
|
|
|
return NAN;
|
|
|
|
}
|
|
|
|
return stack.pop();
|
|
|
|
}
|
|
|
|
|
2014-10-06 05:03:03 -07:00
|
|
|
void LECalculator::doJob(Engine *engine, LEElement *element) {
|
2014-10-03 14:03:00 -07:00
|
|
|
switch (element->action) {
|
2014-10-03 12:05:03 -07:00
|
|
|
|
2014-10-03 14:03:00 -07:00
|
|
|
case LE_NUMERIC_VALUE:
|
2014-10-03 12:05:03 -07:00
|
|
|
stack.push(element->fValue);
|
2014-10-03 14:03:00 -07:00
|
|
|
break;
|
|
|
|
case LE_OPERATOR_AND: {
|
2014-10-07 08:04:35 -07:00
|
|
|
float v1 = pop(LE_OPERATOR_AND);
|
|
|
|
float v2 = pop(LE_OPERATOR_AND);
|
2014-10-03 14:03:00 -07:00
|
|
|
|
|
|
|
stack.push(float2bool(v1) && float2bool(v2));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LE_OPERATOR_OR: {
|
2014-10-07 08:04:35 -07:00
|
|
|
float v1 = pop(LE_OPERATOR_OR);
|
|
|
|
float v2 = pop(LE_OPERATOR_OR);
|
2014-10-03 14:03:00 -07:00
|
|
|
|
|
|
|
stack.push(float2bool(v1) || float2bool(v2));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LE_OPERATOR_LESS: {
|
2014-10-05 07:03:00 -07:00
|
|
|
// elements on stack are in reverse order
|
2014-10-07 08:04:35 -07:00
|
|
|
float v2 = pop(LE_OPERATOR_LESS);
|
|
|
|
float v1 = pop(LE_OPERATOR_LESS);
|
2014-10-03 14:03:00 -07:00
|
|
|
|
|
|
|
stack.push(v1 < v2);
|
|
|
|
}
|
|
|
|
break;
|
2014-10-05 07:03:00 -07:00
|
|
|
case LE_OPERATOR_NOT: {
|
2014-10-07 08:04:35 -07:00
|
|
|
float v = pop(LE_OPERATOR_NOT);
|
2014-10-05 07:03:00 -07:00
|
|
|
stack.push(!float2bool(v));
|
|
|
|
}
|
|
|
|
break;
|
2014-10-03 14:03:00 -07:00
|
|
|
case LE_OPERATOR_MORE: {
|
2014-10-05 07:03:00 -07:00
|
|
|
// elements on stack are in reverse order
|
2014-10-07 08:04:35 -07:00
|
|
|
float v2 = pop(LE_OPERATOR_MORE);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE);
|
2014-10-03 14:03:00 -07:00
|
|
|
|
|
|
|
stack.push(v1 > v2);
|
2014-11-18 18:05:41 -08:00
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-11-18 18:05:41 -08:00
|
|
|
case LE_OPERATOR_ADDITION: {
|
|
|
|
// elements on stack are in reverse order
|
|
|
|
float v2 = pop(LE_OPERATOR_MORE);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE);
|
|
|
|
|
|
|
|
stack.push(v1 + v2);
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-11-18 18:05:41 -08:00
|
|
|
case LE_OPERATOR_SUBSTRACTION: {
|
|
|
|
// elements on stack are in reverse order
|
|
|
|
float v2 = pop(LE_OPERATOR_MORE);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE);
|
|
|
|
|
|
|
|
stack.push(v1 - v2);
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-11-18 18:05:41 -08:00
|
|
|
case LE_OPERATOR_MULTIPLICATION: {
|
|
|
|
// elements on stack are in reverse order
|
|
|
|
float v2 = pop(LE_OPERATOR_MORE);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE);
|
|
|
|
|
|
|
|
stack.push(v1 * v2);
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-11-18 18:05:41 -08:00
|
|
|
case LE_OPERATOR_DIVISION: {
|
|
|
|
// elements on stack are in reverse order
|
|
|
|
float v2 = pop(LE_OPERATOR_MORE);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE);
|
|
|
|
|
|
|
|
stack.push(v1 / v2);
|
2014-10-03 14:03:00 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LE_OPERATOR_LESS_OR_EQUAL: {
|
2014-10-05 07:03:00 -07:00
|
|
|
// elements on stack are in reverse order
|
2014-10-07 08:04:35 -07:00
|
|
|
float v2 = pop(LE_OPERATOR_LESS_OR_EQUAL);
|
|
|
|
float v1 = pop(LE_OPERATOR_LESS_OR_EQUAL);
|
2014-10-03 12:05:03 -07:00
|
|
|
|
2014-10-03 14:03:00 -07:00
|
|
|
stack.push(v1 <= v2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case LE_OPERATOR_MORE_OR_EQUAL: {
|
2014-10-05 07:03:00 -07:00
|
|
|
// elements on stack are in reverse order
|
2014-10-07 08:04:35 -07:00
|
|
|
float v2 = pop(LE_OPERATOR_MORE_OR_EQUAL);
|
|
|
|
float v1 = pop(LE_OPERATOR_MORE_OR_EQUAL);
|
2014-10-03 14:03:00 -07:00
|
|
|
|
|
|
|
stack.push(v1 >= v2);
|
|
|
|
}
|
|
|
|
break;
|
2014-12-04 18:03:12 -08:00
|
|
|
case LE_METHOD_IF: {
|
|
|
|
// elements on stack are in reverse order
|
|
|
|
float vFalse = pop(LE_METHOD_IF);
|
|
|
|
float vTrue = pop(LE_METHOD_IF);
|
|
|
|
float vCond = pop(LE_METHOD_IF);
|
|
|
|
stack.push(vCond != 0 ? vTrue : vFalse);
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-12-04 17:03:09 -08:00
|
|
|
case LE_METHOD_MAX: {
|
|
|
|
float v2 = pop(LE_METHOD_MAX);
|
|
|
|
float v1 = pop(LE_METHOD_MAX);
|
|
|
|
stack.push(maxF(v1, v2));
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
2014-12-04 17:03:09 -08:00
|
|
|
case LE_METHOD_MIN: {
|
|
|
|
float v2 = pop(LE_METHOD_MIN);
|
|
|
|
float v1 = pop(LE_METHOD_MIN);
|
|
|
|
stack.push(minF(v1, v2));
|
|
|
|
}
|
2014-12-05 19:04:09 -08:00
|
|
|
break;
|
|
|
|
case LE_METHOD_FSIO_SETTING: {
|
|
|
|
float i = pop(LE_METHOD_FSIO_SETTING);
|
|
|
|
int index = (int) i;
|
|
|
|
if (index >= 0 && index < LE_COMMAND_COUNT) {
|
|
|
|
stack.push(engine->engineConfiguration->bc.fsio_setting[index]);
|
|
|
|
} else {
|
|
|
|
stack.push(NAN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2014-10-05 07:03:00 -07:00
|
|
|
case LE_UNDEFINED:
|
2014-12-06 12:04:01 -08:00
|
|
|
firmwareError("FSIO undefined action");
|
2014-10-05 07:03:00 -07:00
|
|
|
break;
|
2014-10-03 14:03:00 -07:00
|
|
|
default:
|
2014-12-05 19:04:09 -08:00
|
|
|
stack.push(getLEValue(engine, &stack, element->action));
|
2014-10-03 14:03:00 -07:00
|
|
|
}
|
|
|
|
}
|
2014-10-03 12:05:03 -07:00
|
|
|
|
2014-10-18 04:03:25 -07:00
|
|
|
float LECalculator::getValue2(LEElement *element, Engine *engine) {
|
|
|
|
reset(element);
|
|
|
|
return getValue(engine);
|
|
|
|
}
|
|
|
|
|
2014-10-06 05:03:03 -07:00
|
|
|
float LECalculator::getValue(Engine *engine) {
|
2014-12-06 12:04:01 -08:00
|
|
|
if (first == NULL) {
|
|
|
|
warning(OBD_PCM_Processor_Fault, "no FSIO code");
|
|
|
|
return NAN;
|
|
|
|
}
|
2014-10-03 14:03:00 -07:00
|
|
|
LEElement *element = first;
|
|
|
|
|
|
|
|
stack.reset();
|
|
|
|
|
|
|
|
while (element != NULL) {
|
2014-10-06 05:03:03 -07:00
|
|
|
doJob(engine, element);
|
2014-10-03 12:05:03 -07:00
|
|
|
element = element->next;
|
|
|
|
}
|
2014-12-06 12:04:01 -08:00
|
|
|
if (stack.size() != 1) {
|
|
|
|
warning(OBD_PCM_Processor_Fault, "unexpected FSIO stack size: %d", stack.size());
|
|
|
|
return NAN;
|
|
|
|
}
|
2014-10-03 12:05:03 -07:00
|
|
|
return stack.pop();
|
|
|
|
}
|
|
|
|
|
2014-11-17 13:03:20 -08:00
|
|
|
LEElementPool::LEElementPool(LEElement *pool, int size) {
|
|
|
|
this->pool = pool;
|
2014-12-06 12:04:01 -08:00
|
|
|
this->capacity = capacity;
|
2014-10-03 15:03:01 -07:00
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LEElementPool::reset() {
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
2014-12-06 12:04:01 -08:00
|
|
|
int LEElementPool::getSize() {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2014-10-03 15:03:01 -07:00
|
|
|
LEElement *LEElementPool::next() {
|
2014-12-06 12:04:01 -08:00
|
|
|
if (index == capacity - 1) {
|
2014-11-18 12:03:13 -08:00
|
|
|
// todo: this should not be a fatal error, just an error
|
2014-10-06 02:03:01 -07:00
|
|
|
firmwareError("LE_ELEMENT_POOL_SIZE overflow");
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-03 15:03:01 -07:00
|
|
|
return &pool[index++];
|
|
|
|
}
|
2014-10-04 08:03:38 -07:00
|
|
|
|
2014-10-04 11:02:53 -07:00
|
|
|
bool isNumeric(const char* line) {
|
|
|
|
return line[0] >= '0' && line[0] <= '9';
|
|
|
|
}
|
|
|
|
|
2014-11-17 12:03:37 -08:00
|
|
|
const char *getNextToken(const char *line, char *buffer) {
|
2014-10-04 08:03:38 -07:00
|
|
|
while (line[0] != 0 && line[0] == ' ') {
|
|
|
|
line++;
|
|
|
|
}
|
|
|
|
if (line[0] == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int tokenLen = indexOf(line, ' ');
|
|
|
|
if (tokenLen == -1) {
|
|
|
|
// no space - the whole remaining line is the token
|
|
|
|
strcpy(buffer, line);
|
|
|
|
return line + strlen(buffer);
|
|
|
|
}
|
|
|
|
strncpy(buffer, line, tokenLen);
|
|
|
|
buffer[tokenLen] = 0;
|
|
|
|
line += tokenLen;
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2014-10-04 11:02:53 -07:00
|
|
|
le_action_e parseAction(const char * line) {
|
2014-10-04 15:03:07 -07:00
|
|
|
LENameOrdinalPair *pair = LE_FIRST;
|
|
|
|
while (pair != NULL) {
|
|
|
|
if (strEqualCaseInsensitive(pair->name, line)) {
|
2014-10-05 07:03:00 -07:00
|
|
|
return pair->action;
|
2014-10-04 15:03:07 -07:00
|
|
|
}
|
|
|
|
pair = pair->next;
|
2014-10-04 11:02:53 -07:00
|
|
|
}
|
|
|
|
return LE_UNDEFINED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char parsingBuffer[64];
|
|
|
|
|
2014-11-18 13:03:12 -08:00
|
|
|
LEElement *LEElementPool::parseExpression(const char * line) {
|
2014-10-04 11:02:53 -07:00
|
|
|
|
|
|
|
LEElement *first = NULL;
|
|
|
|
LEElement *last = NULL;
|
|
|
|
|
|
|
|
while (true) {
|
2014-11-17 12:03:37 -08:00
|
|
|
line = getNextToken(line, parsingBuffer);
|
2014-10-04 11:02:53 -07:00
|
|
|
|
|
|
|
if (line == NULL) {
|
|
|
|
/**
|
|
|
|
* No more tokens in this line
|
|
|
|
*/
|
|
|
|
return first;
|
|
|
|
}
|
|
|
|
|
2014-11-18 13:03:12 -08:00
|
|
|
LEElement *n = next();
|
2014-10-04 11:02:53 -07:00
|
|
|
|
|
|
|
if (isNumeric(parsingBuffer)) {
|
|
|
|
n->init(LE_NUMERIC_VALUE, atoff(parsingBuffer));
|
|
|
|
} else {
|
|
|
|
le_action_e action = parseAction(parsingBuffer);
|
2014-10-05 07:03:00 -07:00
|
|
|
if (action == LE_UNDEFINED) {
|
|
|
|
/**
|
|
|
|
* Cannot recognize token
|
|
|
|
*/
|
|
|
|
warning((obd_code_e) 0, "unrecognized [%s]", parsingBuffer);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-10-04 11:02:53 -07:00
|
|
|
n->init(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first == NULL) {
|
|
|
|
first = n;
|
|
|
|
last = n;
|
|
|
|
} else {
|
|
|
|
last->next = n;
|
|
|
|
last = last->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return first;
|
|
|
|
}
|
2014-11-18 12:03:13 -08:00
|
|
|
|
2014-12-24 10:05:36 -08:00
|
|
|
#endif /* EFI_FSIO */
|