FSIO refactoring (#1861)
* better fsio tests * condense operators * minor parser cleanup too * comments, too!
This commit is contained in:
parent
3ded888df3
commit
8cff16e797
|
@ -86,6 +86,11 @@ void LEElement::init(le_action_e action, float fValue) {
|
|||
this->fValue = fValue;
|
||||
}
|
||||
|
||||
void LEElement::init(le_action_e action, bool bValue) {
|
||||
this->action = action;
|
||||
this->fValue = bValue ? 1 : 0;
|
||||
}
|
||||
|
||||
LECalculator::LECalculator() {
|
||||
reset();
|
||||
}
|
||||
|
@ -135,6 +140,48 @@ void LECalculator::push(le_action_e action, float value) {
|
|||
}
|
||||
}
|
||||
|
||||
static float doBinaryBoolean(le_action_e action, float lhs, float rhs) {
|
||||
bool v1 = float2bool(lhs);
|
||||
bool v2 = float2bool(rhs);
|
||||
|
||||
switch (action) {
|
||||
case LE_OPERATOR_AND:
|
||||
return v1 && v2;
|
||||
case LE_OPERATOR_OR:
|
||||
return v1 || v2;
|
||||
default:
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
static float doBinaryNumeric(le_action_e action, float v1, float v2) {
|
||||
// Process based on the action type
|
||||
switch (action) {
|
||||
case LE_OPERATOR_ADDITION:
|
||||
return v1 + v2;
|
||||
case LE_OPERATOR_SUBTRACTION:
|
||||
return v1 - v2;
|
||||
case LE_OPERATOR_MULTIPLICATION:
|
||||
return v1 * v2;
|
||||
case LE_OPERATOR_DIVISION:
|
||||
return v1 / v2;
|
||||
case LE_OPERATOR_LESS:
|
||||
return v1 < v2;
|
||||
case LE_OPERATOR_MORE:
|
||||
return v1 > v2;
|
||||
case LE_OPERATOR_LESS_OR_EQUAL:
|
||||
return v1 <= v2;
|
||||
case LE_OPERATOR_MORE_OR_EQUAL:
|
||||
return v1 >= v2;
|
||||
case LE_METHOD_MIN:
|
||||
return minF(v1, v2);
|
||||
case LE_METHOD_MAX:
|
||||
return maxF(v1, v2);
|
||||
default:
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true in case of error, false otherwise
|
||||
*/
|
||||
|
@ -143,93 +190,50 @@ bool LECalculator::processElement(LEElement *element DECLARE_ENGINE_PARAMETER_SU
|
|||
efiAssert(CUSTOM_ERR_ASSERT, getCurrentRemainingStack() > 64, "FSIO logic", false);
|
||||
#endif
|
||||
switch (element->action) {
|
||||
|
||||
// Literal values
|
||||
case LE_NUMERIC_VALUE:
|
||||
push(element->action, element->fValue);
|
||||
break;
|
||||
case LE_OPERATOR_AND: {
|
||||
float v1 = pop(LE_OPERATOR_AND);
|
||||
float v2 = pop(LE_OPERATOR_AND);
|
||||
|
||||
push(element->action, float2bool(v1) && float2bool(v2));
|
||||
}
|
||||
case LE_BOOLEAN_VALUE:
|
||||
push(element->action, element->fValue != 0);
|
||||
break;
|
||||
// Boolean input binary operators
|
||||
case LE_OPERATOR_AND:
|
||||
case LE_OPERATOR_OR: {
|
||||
float v1 = pop(LE_OPERATOR_OR);
|
||||
float v2 = pop(LE_OPERATOR_OR);
|
||||
|
||||
push(element->action, float2bool(v1) || float2bool(v2));
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_LESS: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_LESS);
|
||||
float v1 = pop(LE_OPERATOR_LESS);
|
||||
auto result = doBinaryBoolean(element->action, v1, v2);
|
||||
|
||||
push(element->action, v1 < v2);
|
||||
push(element->action, result);
|
||||
}
|
||||
break;
|
||||
// Numeric input binary operators
|
||||
case LE_OPERATOR_ADDITION:
|
||||
case LE_OPERATOR_SUBTRACTION:
|
||||
case LE_OPERATOR_MULTIPLICATION:
|
||||
case LE_OPERATOR_DIVISION:
|
||||
case LE_OPERATOR_LESS:
|
||||
case LE_OPERATOR_MORE:
|
||||
case LE_OPERATOR_LESS_OR_EQUAL:
|
||||
case LE_OPERATOR_MORE_OR_EQUAL:
|
||||
case LE_METHOD_MIN:
|
||||
case LE_METHOD_MAX: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(element->action);
|
||||
float v1 = pop(element->action);
|
||||
|
||||
auto result = doBinaryNumeric(element->action, v1, v2);
|
||||
|
||||
push(element->action, result);
|
||||
}
|
||||
break;
|
||||
// Boolean input unary operator
|
||||
case LE_OPERATOR_NOT: {
|
||||
float v = pop(LE_OPERATOR_NOT);
|
||||
push(element->action, !float2bool(v));
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_MORE: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE);
|
||||
float v1 = pop(LE_OPERATOR_MORE);
|
||||
|
||||
push(element->action, v1 > v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_ADDITION: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE);
|
||||
float v1 = pop(LE_OPERATOR_MORE);
|
||||
|
||||
push(element->action, v1 + v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_SUBTRACTION: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE);
|
||||
float v1 = pop(LE_OPERATOR_MORE);
|
||||
|
||||
push(element->action, v1 - v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_MULTIPLICATION: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE);
|
||||
float v1 = pop(LE_OPERATOR_MORE);
|
||||
|
||||
push(element->action, v1 * v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_DIVISION: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE);
|
||||
float v1 = pop(LE_OPERATOR_MORE);
|
||||
|
||||
push(element->action, v1 / v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_LESS_OR_EQUAL: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_LESS_OR_EQUAL);
|
||||
float v1 = pop(LE_OPERATOR_LESS_OR_EQUAL);
|
||||
|
||||
push(element->action, v1 <= v2);
|
||||
}
|
||||
break;
|
||||
case LE_OPERATOR_MORE_OR_EQUAL: {
|
||||
// elements on stack are in reverse order
|
||||
float v2 = pop(LE_OPERATOR_MORE_OR_EQUAL);
|
||||
float v1 = pop(LE_OPERATOR_MORE_OR_EQUAL);
|
||||
|
||||
push(element->action, v1 >= v2);
|
||||
}
|
||||
break;
|
||||
case LE_METHOD_IF: {
|
||||
// elements on stack are in reverse order
|
||||
float vFalse = pop(LE_METHOD_IF);
|
||||
|
@ -238,18 +242,6 @@ bool LECalculator::processElement(LEElement *element DECLARE_ENGINE_PARAMETER_SU
|
|||
push(element->action, vCond != 0 ? vTrue : vFalse);
|
||||
}
|
||||
break;
|
||||
case LE_METHOD_MAX: {
|
||||
float v2 = pop(LE_METHOD_MAX);
|
||||
float v1 = pop(LE_METHOD_MAX);
|
||||
push(element->action, maxF(v1, v2));
|
||||
}
|
||||
break;
|
||||
case LE_METHOD_MIN: {
|
||||
float v2 = pop(LE_METHOD_MIN);
|
||||
float v1 = pop(LE_METHOD_MIN);
|
||||
push(element->action, minF(v1, v2));
|
||||
}
|
||||
break;
|
||||
case LE_METHOD_FSIO_SETTING: {
|
||||
float humanIndex = pop(LE_METHOD_FSIO_SETTING);
|
||||
int index = (int) humanIndex - 1;
|
||||
|
@ -282,6 +274,7 @@ bool LECalculator::processElement(LEElement *element DECLARE_ENGINE_PARAMETER_SU
|
|||
break;
|
||||
case LE_METHOD_FSIO_DIGITAL_INPUT:
|
||||
// todo: implement code for digital input!!!
|
||||
return true;
|
||||
case LE_METHOD_FSIO_ANALOG_INPUT:
|
||||
{
|
||||
int index = clampF(0, pop(LE_METHOD_FSIO_ANALOG_INPUT), FSIO_ANALOG_INPUT_COUNT - 1);
|
||||
|
@ -370,6 +363,13 @@ bool isNumeric(const char* line) {
|
|||
return line[0] >= '0' && line[0] <= '9';
|
||||
}
|
||||
|
||||
bool isBoolean(const char* line) {
|
||||
bool isTrue = 0 == strcmp(line, "true");
|
||||
bool isFalse = 0 == strcmp(line, "false");
|
||||
|
||||
return isTrue || isFalse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return pointer at the position after the consumed token, null if no token consumed
|
||||
*/
|
||||
|
@ -406,27 +406,28 @@ le_action_e parseAction(const char * line) {
|
|||
static char parsingBuffer[64];
|
||||
|
||||
LEElement *LEElementPool::parseExpression(const char * line) {
|
||||
|
||||
LEElement *first = nullptr;
|
||||
LEElement *last = nullptr;
|
||||
|
||||
while (true) {
|
||||
line = getNextToken(line, parsingBuffer, sizeof(parsingBuffer));
|
||||
|
||||
if (line == nullptr) {
|
||||
if (!line) {
|
||||
/**
|
||||
* No more tokens in this line
|
||||
* No more tokens in this line, parsing complete!
|
||||
*/
|
||||
return first;
|
||||
}
|
||||
|
||||
LEElement *n = next();
|
||||
if (n == nullptr) {
|
||||
return first;
|
||||
if (!n) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isNumeric(parsingBuffer)) {
|
||||
n->init(LE_NUMERIC_VALUE, atoff(parsingBuffer));
|
||||
} else if (isBoolean(parsingBuffer)) {
|
||||
n->init(LE_BOOLEAN_VALUE, parsingBuffer[0] == 't');
|
||||
} else {
|
||||
le_action_e action = parseAction(parsingBuffer);
|
||||
if (action == LE_UNDEFINED) {
|
||||
|
@ -439,15 +440,18 @@ LEElement *LEElementPool::parseExpression(const char * line) {
|
|||
n->init(action);
|
||||
}
|
||||
|
||||
if (first == nullptr) {
|
||||
// If this is the first time through, set the first element.
|
||||
if (!first) {
|
||||
first = n;
|
||||
last = n;
|
||||
} else {
|
||||
last->next = n;
|
||||
last = last->next;
|
||||
}
|
||||
|
||||
// If not the first, link the list
|
||||
if (last) {
|
||||
last->next = n;
|
||||
}
|
||||
|
||||
last = n;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
#endif /* EFI_FSIO */
|
||||
|
|
|
@ -16,6 +16,7 @@ typedef enum {
|
|||
|
||||
LE_UNDEFINED = 0 ,
|
||||
LE_NUMERIC_VALUE = 1,
|
||||
LE_BOOLEAN_VALUE = 126,
|
||||
LE_OPERATOR_LESS = 2,
|
||||
LE_OPERATOR_MORE = 3,
|
||||
LE_OPERATOR_LESS_OR_EQUAL = 4,
|
||||
|
@ -66,9 +67,10 @@ class LEElement {
|
|||
public:
|
||||
LEElement();
|
||||
void clear();
|
||||
// void init(le_action_e action, int iValue);
|
||||
|
||||
void init(le_action_e action);
|
||||
void init(le_action_e action, float fValue);
|
||||
void init(le_action_e action, float value);
|
||||
void init(le_action_e action, bool value);
|
||||
|
||||
le_action_e action;
|
||||
float fValue;
|
||||
|
|
|
@ -40,7 +40,7 @@ float getEngineValue(le_action_e action DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
|||
}
|
||||
}
|
||||
|
||||
static void testParsing(void) {
|
||||
TEST(fsio, testParsing) {
|
||||
char buffer[64];
|
||||
|
||||
ASSERT_TRUE(strEqualCaseInsensitive("hello", "HELlo"));
|
||||
|
@ -95,7 +95,7 @@ static void testExpression2(float selfValue, const char *line, float expected, E
|
|||
|
||||
EXPAND_Engine;
|
||||
|
||||
ASSERT_EQ(expected, c.getValue2(selfValue, element PASS_ENGINE_PARAMETER_SUFFIX)) << line;
|
||||
ASSERT_NEAR(expected, c.getValue2(selfValue, element PASS_ENGINE_PARAMETER_SUFFIX), EPS4D) << line;
|
||||
}
|
||||
|
||||
static void testExpression2(float selfValue, const char *line, float expected, const std::unordered_map<SensorType, float>& sensorVals = {}) {
|
||||
|
@ -107,10 +107,6 @@ static void testExpression(const char *line, float expectedValue, const std::uno
|
|||
testExpression2(0, line, expectedValue, sensorVals);
|
||||
}
|
||||
|
||||
TEST(fsio, testIfFunction) {
|
||||
testExpression("1 22 33 if", 22);
|
||||
}
|
||||
|
||||
TEST(fsio, testHysteresisSelf) {
|
||||
WITH_ENGINE_TEST_HELPER(FORD_INLINE_6_1995);
|
||||
|
||||
|
@ -144,8 +140,58 @@ TEST(fsio, testHysteresisSelf) {
|
|||
ASSERT_EQ(1, selfValue);
|
||||
}
|
||||
|
||||
TEST(fsio, testLiterals) {
|
||||
// Constants - single token
|
||||
testExpression("123", 123.0f);
|
||||
testExpression("true", 1);
|
||||
testExpression("false", 0);
|
||||
}
|
||||
|
||||
TEST(fsio, mathOperators) {
|
||||
// Test basic operations
|
||||
testExpression("123 456 +", 579);
|
||||
testExpression("123 456 -", -333);
|
||||
testExpression("123 456 *", 56088);
|
||||
testExpression("123 456 /", 0.269737f);
|
||||
}
|
||||
|
||||
TEST(fsio, comparisonOperators) {
|
||||
// Comparison operators
|
||||
testExpression("123 456 >", 0);
|
||||
testExpression("123 456 >=", 0);
|
||||
testExpression("123 456 <", 1);
|
||||
testExpression("123 456 <=", 1);
|
||||
testExpression("123 456 min", 123);
|
||||
testExpression("123 456 max", 456);
|
||||
}
|
||||
|
||||
TEST(fsio, booleanOperators) {
|
||||
// Boolean operators
|
||||
testExpression("true true and", 1);
|
||||
testExpression("true false and", 0);
|
||||
testExpression("true false or", 1);
|
||||
testExpression("false false or", 0);
|
||||
// (both ways to write and/or)
|
||||
testExpression("true true &", 1);
|
||||
testExpression("true false &", 0);
|
||||
testExpression("true false |", 1);
|
||||
testExpression("false false |", 0);
|
||||
|
||||
// not operator
|
||||
testExpression("true not", 0);
|
||||
testExpression("false not", 1);
|
||||
}
|
||||
|
||||
TEST(fsio, extraOperators) {
|
||||
// Self operator
|
||||
testExpression2(123, "self 1 +", 124);
|
||||
|
||||
// ternary operator
|
||||
testExpression("1 22 33 if", 22);
|
||||
testExpression("0 22 33 if", 33);
|
||||
}
|
||||
|
||||
TEST(fsio, testLogicExpressions) {
|
||||
testParsing();
|
||||
{
|
||||
|
||||
WITH_ENGINE_TEST_HELPER(FORD_INLINE_6_1995);
|
||||
|
@ -153,13 +199,13 @@ TEST(fsio, testLogicExpressions) {
|
|||
LECalculator c;
|
||||
|
||||
LEElement value1;
|
||||
value1.init(LE_NUMERIC_VALUE, 123.0);
|
||||
value1.init(LE_NUMERIC_VALUE, 123.0f);
|
||||
c.add(&value1);
|
||||
|
||||
assertEqualsM("123", 123.0, c.getValue(0 PASS_ENGINE_PARAMETER_SUFFIX));
|
||||
|
||||
LEElement value2;
|
||||
value2.init(LE_NUMERIC_VALUE, 321.0);
|
||||
value2.init(LE_NUMERIC_VALUE, 321.0f);
|
||||
c.add(&value2);
|
||||
|
||||
LEElement value3;
|
||||
|
@ -180,7 +226,7 @@ TEST(fsio, testLogicExpressions) {
|
|||
e->init(LE_METHOD_TIME_SINCE_BOOT);
|
||||
|
||||
e = pool.next();
|
||||
e->init(LE_NUMERIC_VALUE, 4);
|
||||
e->init(LE_NUMERIC_VALUE, 4.0f);
|
||||
|
||||
e = pool.next();
|
||||
e->init(LE_OPERATOR_LESS);
|
||||
|
@ -189,7 +235,7 @@ TEST(fsio, testLogicExpressions) {
|
|||
e->init(LE_METHOD_RPM);
|
||||
|
||||
e = pool.next();
|
||||
e->init(LE_NUMERIC_VALUE, 0);
|
||||
e->init(LE_NUMERIC_VALUE, 0.0f);
|
||||
|
||||
e = pool.next();
|
||||
e->init(LE_OPERATOR_MORE);
|
||||
|
@ -217,11 +263,6 @@ TEST(fsio, testLogicExpressions) {
|
|||
testExpression("coolant 90 >", 1, sensorVals);
|
||||
testExpression("fan not coolant 90 > and", 1, sensorVals);
|
||||
|
||||
testExpression("100 200 1 if", 200);
|
||||
testExpression("10 99 max", 99);
|
||||
|
||||
testExpression2(123, "10 self max", 123);
|
||||
|
||||
testExpression("fan NOT coolant 90 > AND fan coolant 85 > AND OR", 1, sensorVals);
|
||||
|
||||
{
|
||||
|
@ -238,12 +279,6 @@ TEST(fsio, testLogicExpressions) {
|
|||
ASSERT_EQ(0, c.calcLogValue[0]);
|
||||
}
|
||||
|
||||
|
||||
testExpression("0 1 &", 0);
|
||||
testExpression("0 1 |", 1);
|
||||
|
||||
testExpression("0 1 >", 0);
|
||||
|
||||
{
|
||||
WITH_ENGINE_TEST_HELPER_SENS(FORD_INLINE_6_1995, sensorVals);
|
||||
engineConfiguration->fanOnTemperature = 0;
|
||||
|
|
Loading…
Reference in New Issue