diff --git a/radio/src/dataconstants.h b/radio/src/dataconstants.h index c41c8ee1d..a6439e4ba 100644 --- a/radio/src/dataconstants.h +++ b/radio/src/dataconstants.h @@ -168,7 +168,7 @@ enum CurveType { #define LEN_INPUT_NAME 3 #define LEN_CURVE_NAME 3 #define LEN_FUNCTION_NAME 6 - #define MAX_CURVES 16 + #define MAX_CURVES 16 // TODO next EEPROM check if can be changed to 32 to have all ARM the same #define MAX_CURVE_POINTS 512 #elif defined(PCBTARANIS) #define LEN_MODEL_NAME 12 diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index db05a1583..a5c579193 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -367,7 +367,7 @@ PACK(struct FlightModeData { PACK(struct CurveData { uint8_t type:1; uint8_t smooth:1; - int8_t points:6; // TODO conversion + int8_t points:6; // TODO conversion (?!) (describes number of points - 5) NOBACKUP(char name[LEN_CURVE_NAME]); }); #else diff --git a/radio/src/lua/api_model.cpp b/radio/src/lua/api_model.cpp index 11f32fbf1..a71b03b68 100644 --- a/radio/src/lua/api_model.cpp +++ b/radio/src/lua/api_model.cpp @@ -805,6 +805,9 @@ Get Curve parameters * `key` is point number (zero based) * `value` is x value + Note that functions returns the tables starting with index 0 contrary to LUA's + usual index starting with 1 + @status current Introduced in 2.0.12 */ static int luaModelGetCurve(lua_State *L) @@ -849,6 +852,194 @@ static int luaModelGetCurve(lua_State *L) return 1; } +/*luadoc +@function model.setCurve(curve, params) + +Set Curve parameters + +@param curve (unsigned number) curve number (use 0 for Curve1) + +@param params see model.getCurve return format for table format. setCurve uses standard + lua array indexing and array start at index 1 + +The first and last x value must 0 and 100 and x values must be monotonically increasing + +@retval 0 - Everything okay + 1 - Wrong number of points + 2 - Invalid Curve number + 3 - Cuve does not fit anymore + 4 - point of out of index + 5 - x value not monotonically increasing + 6 - y value not in range [-100;100] + 7 - extra values for y are set + 8 - extra values for x are set + +@status current Introduced in 2.2.1 + +Example setting a 4-point custom curve: +```lua + params = {} + params["x"] = {0, 34, 77, 100} + params["y"] = {-70, 20, -89, -100} + params["smooth"] = 1 + params["type"] = 1 + val = model.setCurve(2, params) + ``` +setting a 6-point standard smoothed curve + ```lua + val = model.setCurve(3, {smooth=1, y={-100, -50, 0, 50, 100, 80}}) + ``` + +*/ +static int luaModelSetCurve(lua_State *L) +{ + unsigned int curveIdx = luaL_checkunsigned(L, 1); + + if (curveIdx >= MAX_CURVES) { + lua_pushinteger(L, 2); + return 1; + } + int8_t xPoints[MAX_POINTS_PER_CURVE]; + int8_t yPoints[MAX_POINTS_PER_CURVE]; + + // Init to invalid values + memset(xPoints, -127, sizeof(xPoints)); + memset(yPoints, -127, sizeof(yPoints)); + + + CurveData &destCurveData = g_model.curves[curveIdx]; + CurveData newCurveData; + memclear(&newCurveData, sizeof(CurveData)); + + luaL_checktype(L, -1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); // key is string + const char *key = luaL_checkstring(L, -2); + if (!strcmp(key, "name")) { + const char *name = luaL_checkstring(L, -1); + str2zchar(newCurveData.name, name, sizeof(newCurveData.name)); + } + else if (!strcmp(key, "type")) { + newCurveData.type = luaL_checkinteger(L, -1); + } + else if (!strcmp(key, "smooth")) { + newCurveData.smooth = luaL_checkinteger(L, -1); + } + else if (!strcmp(key, "x") || !strcmp(key, "y")) { + luaL_checktype(L, -1, LUA_TTABLE); + bool isX = !strcmp(key, "x"); + + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + int idx = luaL_checkinteger(L, -2)-1; + if (idx < 0 || idx > MAX_POINTS_PER_CURVE) { + lua_pushinteger(L, 4); + return 1; + } + int8_t val = luaL_checkinteger(L, -1); + if (val < -100 || val > 100) { + lua_pushinteger(L, 6); + return 1; + } + if (isX) + xPoints[idx] = val; + else + yPoints[idx] = val; + } + } + } + // Check how many points are set + uint8_t numPoints=0; + do { + numPoints++; + } while (yPoints[numPoints]!=-127 && numPoints < MAX_POINTS_PER_CURVE); + newCurveData.points = numPoints - 5; + + if (numPoints < MIN_POINTS_PER_CURVE || numPoints > MAX_POINTS_PER_CURVE) { + lua_pushinteger(L, 1); + return 1; + } + + if (newCurveData.type == CURVE_TYPE_CUSTOM) { + + // The rest of the points are checked by the monotic condition + for (unsigned int i=numPoints; i < sizeof(xPoints);i++) + { + if (xPoints[i] != -127) + { + lua_pushinteger(L, 8); + return 1; + } + } + + // Check first and last point + if (xPoints[0] != 0 || xPoints[newCurveData.points + 4] != 100) { + lua_pushinteger(L, 5); + return 1; + } + + // Check that x values are increasing + for (int i = 1; i < numPoints; i++) { + if (xPoints[i - 1] > xPoints[i]) { + lua_pushinteger(L, 5); + return 1; + } + } + } + + // Check that ypoints have the right number of points set + for (int i=0; i < 5 + newCurveData.points;i++) + { + if (yPoints[i] == -127) + { + lua_pushinteger(L, 7); + return 1; + } + } + + // Calculate size of curve we replace + int oldCurveMemSize; + if (destCurveData.type == CURVE_TYPE_STANDARD) { + oldCurveMemSize = 5 + destCurveData.points; + } + else { + oldCurveMemSize = 8 + 2 * destCurveData.points; + } + + // Calculate own size + int newCurveMemSize; + if (newCurveData.type == CURVE_TYPE_STANDARD) + newCurveMemSize = 5 + newCurveData.points; + else + newCurveMemSize = 8 + 2 * newCurveData.points; + + int shift = newCurveMemSize - oldCurveMemSize; + + // Also checks if new curve size would fit + if (!moveCurve(curveIdx, shift)) { + lua_pushinteger(L, 3); + TRACE("curve shift is %d", shift); + return 1; + } + + // Curve fits into mem, fill new curve + destCurveData = newCurveData; + + int8_t *point = curveAddress(curveIdx); + for (int i = 0; i < destCurveData.points + 5; i++) { + *point++ = yPoints[i]; + } + + if (destCurveData.type == CURVE_TYPE_CUSTOM) { + for (int i = 1; i < destCurveData.points + 4; i++) { + *point++ = yPoints[i]; + } + } + storageDirty(EE_MODEL); + + lua_pushinteger(L, 0); + return 1; +} + /*luadoc @function model.getCustomFunction(function) @@ -1132,6 +1323,7 @@ const luaL_Reg modelLib[] = { { "getCustomFunction", luaModelGetCustomFunction }, { "setCustomFunction", luaModelSetCustomFunction }, { "getCurve", luaModelGetCurve }, + { "setCurve", luaModelSetCurve }, { "getOutput", luaModelGetOutput }, { "setOutput", luaModelSetOutput }, { "getGlobalVariable", luaModelGetGlobalVariable },