diff --git a/grid_common/CMakeLists.txt b/grid_common/CMakeLists.txt index 6b1efab2..65995605 100644 --- a/grid_common/CMakeLists.txt +++ b/grid_common/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.10) idf_component_register( SRCS "grid_protocol.c" + "grid_cal.c" "grid_ain.c" "grid_led.c" "grid_sys.c" diff --git a/grid_common/grid_cal.c b/grid_common/grid_cal.c new file mode 100644 index 00000000..1cdc714d --- /dev/null +++ b/grid_common/grid_cal.c @@ -0,0 +1,131 @@ +/* + * grid_cal.c + * + * Created: 25/11/2024 3:01:37 PM + * Author : BENB + */ + +#include "grid_cal.h" + +struct grid_cal_model grid_cal_state; + +int grid_cal_init(struct grid_cal_model* cal, uint8_t resolution, uint8_t length) { + + cal->resolution = resolution; + cal->length = length; + + cal->maximum = 1 << cal->resolution; + + cal->value = (uint16_t*)malloc(cal->length * sizeof(uint16_t)); + cal->center = (uint16_t*)malloc(cal->length * sizeof(uint16_t)); + cal->enable = (uint8_t*)malloc(cal->length * sizeof(uint8_t)); + + const uint16_t half_value = cal->maximum / 2; + + const uint16_t default_offset = +32 * 4.5; + + for (uint8_t i = 0; i < length; ++i) { + cal->value[i] = half_value + default_offset; + cal->center[i] = cal->value[i]; + cal->enable[i] = 0; + } + + return 0; +} + +int grid_cal_enable_range(struct grid_cal_model* cal, uint8_t start, uint8_t length) { + + if (!(start < cal->length)) { + return 1; + } + + uint8_t end = start + length; + + if (!(end < cal->length)) { + return 1; + } + + for (uint8_t i = start; i < end; ++i) { + cal->enable[i] = 1; + } + + return 0; +} + +int grid_cal_center_set(struct grid_cal_model* cal, uint8_t channel, uint16_t center) { + + if (!(channel < cal->length)) { + return 1; + } + + if (!cal->enable[channel]) { + return 1; + } + + cal->center[channel] = center; + + return 0; +} + +int grid_cal_value_get(struct grid_cal_model* cal, uint8_t channel, uint16_t* value) { + + if (!(channel < cal->length)) { + return 1; + } + + if (!cal->enable[channel]) { + return 1; + } + + *value = cal->value[channel]; + + return 0; +} + +int grid_cal_enable_get(struct grid_cal_model* cal, uint8_t channel, uint8_t* enable) { + + if (!(channel < cal->length)) { + return 1; + } + + *enable = cal->enable[channel]; + + return 0; +} + +static float lerp(float a, float b, float x) { return a * (1.0 - x) + (b * x); } + +static int32_t inverse_error_centering(int32_t a, int32_t b, float x, float c, uint8_t iter) { + + for (uint8_t i = 0; i < iter; ++i) { + + if (x < c) { + b = (a + b) / 2; + x = x / c; + } else { + a = (a + b) / 2; + x = (x - c) / (1.0 - c); + } + } + + return lerp(a, b, x); +} + +int grid_cal_next(struct grid_cal_model* cal, uint8_t channel, uint16_t in, uint16_t* out) { + + if (!(channel < cal->length)) { + return 1; + } + + if (!cal->enable[channel]) { + return 1; + } + + cal->value[channel] = in; + + float in_norm = in / (float)cal->maximum; + float center_norm = cal->center[channel] / (float)cal->maximum; + *out = inverse_error_centering(0, cal->maximum, in_norm, center_norm, 2); + + return 0; +} diff --git a/grid_common/grid_cal.h b/grid_common/grid_cal.h new file mode 100644 index 00000000..2a9fb083 --- /dev/null +++ b/grid_common/grid_cal.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef GRID_CAL_H_INCLUDED +#define GRID_CAL_H_INCLUDED + +// only for uint definitions +#include +// only for malloc +#include + +struct grid_cal_model { + + uint8_t resolution; + uint8_t length; + uint16_t maximum; + uint16_t* value; + uint16_t* center; + uint8_t* enable; +}; + +extern struct grid_cal_model grid_cal_state; + +int grid_cal_init(struct grid_cal_model* cal, uint8_t resolution, uint8_t length); +int grid_cal_enable_range(struct grid_cal_model* cal, uint8_t start, uint8_t length); +int grid_cal_center_set(struct grid_cal_model* cal, uint8_t channel, uint16_t center); +int grid_cal_value_get(struct grid_cal_model* cal, uint8_t channel, uint16_t* value); +int grid_cal_enable_get(struct grid_cal_model* cal, uint8_t channel, uint8_t* enable); +int grid_cal_next(struct grid_cal_model* cal, uint8_t channel, uint16_t in, uint16_t* out); + +#endif /* GRID_CAL_H_INCLUDED */ diff --git a/grid_common/grid_lua_api.c b/grid_common/grid_lua_api.c index fc8ab6ec..75d729d2 100644 --- a/grid_common/grid_lua_api.c +++ b/grid_common/grid_lua_api.c @@ -1590,6 +1590,109 @@ return 1; } +/*static*/ int l_grid_potmeter_calibration_get(lua_State* L) { + + int nargs = lua_gettop(L); + + if (nargs != 0) { + // error + strcat(grid_lua_state.stde, "#invalidParams"); + return 0; + } + + lua_newtable(L); + + for (uint8_t i = 0; i < grid_ui_state.element_list_length; ++i) { + + struct grid_ui_element* ele = grid_ui_element_find(&grid_ui_state, i); + + uint8_t enabled = 0; + if (grid_cal_enable_get(&grid_cal_state, i, &enabled) != 0) { + + strcat(grid_lua_state.stde, "#indexOutOfRange"); + return 0; + } + + uint16_t value = 0; + + if (ele->type == GRID_PARAMETER_ELEMENT_POTMETER && enabled) { + + if (grid_cal_value_get(&grid_cal_state, i, &value) != 0) { + + strcat(grid_lua_state.stde, "#indexOutOfRange"); + lua_pop(L, 1); + return 0; + } + } + + lua_pushinteger(L, i + 1); + lua_pushinteger(L, value); + lua_settable(L, -3); + } + + grid_platform_printf("potmeter_calibration_get()\n"); + + return 1; +} + +/*static*/ int l_grid_potmeter_calibration_set(lua_State* L) { + + int nargs = lua_gettop(L); + + if (nargs != 1) { + // error + strcat(grid_lua_state.stde, "#invalidParams"); + return 0; + } + + if (!lua_istable(L, -1)) { + strcat(grid_lua_state.stde, "#invalidParams"); + return 0; + } + + for (uint8_t i = 0; i < grid_ui_state.element_list_length; ++i) { + + struct grid_ui_element* ele = grid_ui_element_find(&grid_ui_state, i); + + uint8_t enabled = 0; + if (grid_cal_enable_get(&grid_cal_state, i, &enabled) != 0) { + + strcat(grid_lua_state.stde, "#indexOutOfRange"); + return 0; + } + + if (!enabled) { + continue; + } + + lua_pushinteger(L, i + 1); + lua_gettable(L, -2); + + if (!lua_isinteger(L, -1)) { + strcat(grid_lua_state.stde, "#invalidParams"); + return 0; + } + + int32_t value = 0; + + if (ele->type == GRID_PARAMETER_ELEMENT_POTMETER) { + value = lua_tointeger(L, -1); + } + + lua_pop(L, 1); + + if (grid_cal_center_set(&grid_cal_state, i, value) != 0) { + + strcat(grid_lua_state.stde, "#indexOutOfRange"); + return 0; + } + } + + grid_platform_printf("potmeter_calibration_set()\n"); + + return 0; +} + /*static*/ const struct luaL_Reg grid_lua_api_generic_lib[] = { {"print", l_my_print}, {"grid_send", l_grid_send}, @@ -1652,6 +1755,8 @@ {GRID_LUA_FNC_G_IMMEDIATE_SEND_short, GRID_LUA_FNC_G_IMMEDIATE_SEND_fnptr}, {GRID_LUA_FNC_G_ELEMENT_COUNT_short, GRID_LUA_FNC_G_ELEMENT_COUNT_fnptr}, + {GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_short, GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_fnptr}, + {GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_short, GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_fnptr}, {"print", l_my_print}, diff --git a/grid_common/grid_lua_api.h b/grid_common/grid_lua_api.h index e5f477d2..cefd090e 100644 --- a/grid_common/grid_lua_api.h +++ b/grid_common/grid_lua_api.h @@ -87,6 +87,9 @@ extern void grid_platform_delay_ms(uint32_t delay_milliseconds); /*static*/ int l_grid_element_count(lua_State* L); +/*static*/ int l_grid_potmeter_calibration_get(lua_State* L); +/*static*/ int l_grid_potmeter_calibration_set(lua_State* L); + extern struct luaL_Reg* grid_lua_api_generic_lib_reference; #endif /* GRID_LUA_API_H_INCLUDED */ diff --git a/grid_common/grid_protocol.h b/grid_common/grid_protocol.h index 1bdd423c..3e2bbda5 100644 --- a/grid_common/grid_protocol.h +++ b/grid_common/grid_protocol.h @@ -393,6 +393,16 @@ #define GRID_LUA_FNC_G_ELEMENT_COUNT_fnptr l_grid_element_count #define GRID_LUA_FNC_G_ELEMENT_COUNT_usage "element_count(void) Returns the number of elements on the current module." +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_short "gpcg" +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_human "potmeter_calibration_get" +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_fnptr l_grid_potmeter_calibration_get +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_GET_usage "potmeter_calibration_get() Returns raw potentiometer values as an array of integers." + +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_short "gpcs" +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_human "potmeter_calibration_set" +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_fnptr l_grid_potmeter_calibration_set +#define GRID_LUA_FNC_G_POTMETER_CALIBRATION_SET_usage "potmeter_calibration_set({ int c1, ... }) Sets potentiometer calibration centers from an array of integers." + #define GRID_LUA_FNC_G_GUI_DRAW_PIXEL_short "ggdp" #define GRID_LUA_FNC_G_GUI_DRAW_PIXEL_human "gui_draw_pixel" #define GRID_LUA_FNC_G_GUI_DRAW_PIXEL_fnptr l_grid_gui_draw_pixel diff --git a/grid_common/grid_ui.h b/grid_common/grid_ui.h index 7e69ea9e..08784092 100644 --- a/grid_common/grid_ui.h +++ b/grid_common/grid_ui.h @@ -11,6 +11,7 @@ #include #include "grid_ain.h" +#include "grid_cal.h" #include "grid_lua_api.h" #include "grid_protocol.h" diff --git a/grid_esp/components/grid_common/CMakeLists.txt b/grid_esp/components/grid_common/CMakeLists.txt index fdcc3bb6..c4289312 100644 --- a/grid_esp/components/grid_common/CMakeLists.txt +++ b/grid_esp/components/grid_common/CMakeLists.txt @@ -5,6 +5,7 @@ idf_component_register( SRCS "../../../grid_common/grid_protocol.c" + "../../../grid_common/grid_cal.c" "../../../grid_common/grid_ain.c" "../../../grid_common/grid_led.c" "../../../grid_common/grid_sys.c" diff --git a/grid_esp/components/grid_esp32_adc/grid_esp32_adc.c b/grid_esp/components/grid_esp32_adc/grid_esp32_adc.c index dae0df79..347544fa 100644 --- a/grid_esp/components/grid_esp32_adc/grid_esp32_adc.c +++ b/grid_esp/components/grid_esp32_adc/grid_esp32_adc.c @@ -194,6 +194,7 @@ void grid_esp32_adc_stop(struct grid_esp32_adc_model* adc) {} #include "ulp_riscv_lock.h" +/* static float restrictToRange(float value) { if (value < 0.0) { return 0.0; @@ -218,6 +219,7 @@ static uint32_t grid_esp32_adc_cal(uint32_t input) { return input + parameter_1 * strength; } +*/ void IRAM_ATTR grid_esp32_adc_convert(void) { @@ -232,12 +234,14 @@ void IRAM_ATTR grid_esp32_adc_convert(void) { struct grid_esp32_adc_result result_0; result_0.channel = 0; result_0.mux_state = grid_esp32_adc_mux_get_index(&grid_esp32_adc_state); - result_0.value = grid_esp32_adc_cal(ulp_adc_value_1); + // result_0.value = grid_esp32_adc_cal(ulp_adc_value_1); + result_0.value = ulp_adc_value_1; struct grid_esp32_adc_result result_1; result_1.channel = 1; result_1.mux_state = grid_esp32_adc_mux_get_index(&grid_esp32_adc_state); - result_1.value = grid_esp32_adc_cal(ulp_adc_value_2); + // result_1.value = grid_esp32_adc_cal(ulp_adc_value_2); + result_1.value = ulp_adc_value_2; xRingbufferSendFromISR(adc->ringbuffer_handle, &result_0, sizeof(struct grid_esp32_adc_result), NULL); xRingbufferSendFromISR(adc->ringbuffer_handle, &result_1, sizeof(struct grid_esp32_adc_result), NULL); diff --git a/grid_esp/components/grid_esp32_module_pbf4/grid_esp32_module_pbf4.c b/grid_esp/components/grid_esp32_module_pbf4/grid_esp32_module_pbf4.c index 837d480b..5d2bf8bb 100644 --- a/grid_esp/components/grid_esp32_module_pbf4/grid_esp32_module_pbf4.c +++ b/grid_esp/components/grid_esp32_module_pbf4/grid_esp32_module_pbf4.c @@ -29,6 +29,9 @@ void grid_esp32_module_pbf4_task(void* arg) { static const uint8_t invert_result_lookup[16] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const uint8_t multiplexer_overflow = 8; + grid_cal_init(&grid_cal_state, 12, grid_ui_state.element_list_length); + grid_cal_enable_range(&grid_cal_state, 0, 4); + grid_esp32_adc_init(&grid_esp32_adc_state); grid_esp32_adc_mux_init(&grid_esp32_adc_state, multiplexer_overflow); grid_esp32_adc_start(&grid_esp32_adc_state); @@ -50,7 +53,9 @@ void grid_esp32_module_pbf4_task(void* arg) { if (multiplexer_lookup[lookup_index] < 8) { - grid_ui_potmeter_store_input(multiplexer_lookup[lookup_index], &potmeter_last_real_time[lookup_index], result->value, 12); + uint16_t calibrated; + grid_cal_next(&grid_cal_state, multiplexer_lookup[lookup_index], result->value, &calibrated); + grid_ui_potmeter_store_input(multiplexer_lookup[lookup_index], &potmeter_last_real_time[lookup_index], calibrated, 12); } else if (multiplexer_lookup[lookup_index] < 12) { grid_ui_button_store_input(multiplexer_lookup[lookup_index], &potmeter_last_real_time[lookup_index], result->value, 12); diff --git a/grid_esp/components/grid_esp32_module_po16/grid_esp32_module_po16.c b/grid_esp/components/grid_esp32_module_po16/grid_esp32_module_po16.c index 01313964..b31c7870 100644 --- a/grid_esp/components/grid_esp32_module_po16/grid_esp32_module_po16.c +++ b/grid_esp/components/grid_esp32_module_po16/grid_esp32_module_po16.c @@ -27,6 +27,9 @@ void grid_esp32_module_po16_task(void* arg) { static const uint8_t invert_result_lookup[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; const uint8_t multiplexer_overflow = 8; + grid_cal_init(&grid_cal_state, 12, grid_ui_state.element_list_length); + grid_cal_enable_range(&grid_cal_state, 0, 16); + grid_esp32_adc_init(&grid_esp32_adc_state); grid_esp32_adc_mux_init(&grid_esp32_adc_state, multiplexer_overflow); grid_esp32_adc_start(&grid_esp32_adc_state); @@ -46,7 +49,9 @@ void grid_esp32_module_po16_task(void* arg) { result->value = 4095 - result->value; } - grid_ui_potmeter_store_input(multiplexer_lookup[lookup_index], &potmeter_last_real_time[lookup_index], result->value, 12); + uint16_t calibrated; + grid_cal_next(&grid_cal_state, multiplexer_lookup[lookup_index], result->value, &calibrated); + grid_ui_potmeter_store_input(multiplexer_lookup[lookup_index], &potmeter_last_real_time[lookup_index], calibrated, 12); vRingbufferReturnItem(grid_esp32_adc_state.ringbuffer_handle, result); } diff --git a/grid_make/gcc/Makefile b/grid_make/gcc/Makefile index 0dae9856..9a37cc16 100644 --- a/grid_make/gcc/Makefile +++ b/grid_make/gcc/Makefile @@ -14,6 +14,7 @@ OBJS += \ \ usb/class/midi/device/audiodf_midi.o \ usb/class/midi/usb_protocol_midi.o \ +../grid_common/grid_cal.o \ ../grid_common/grid_ain.o \ ../grid_common/grid_sys.o \ ../grid_common/grid_allocator.o \ @@ -88,6 +89,7 @@ OBJS_AS_ARGS += \ \ "usb/class/midi/device/audiodf_midi.o" \ "usb/class/midi/usb_protocol_midi.o" \ +"../grid_common/grid_cal.o" \ "../grid_common/grid_ain.o" \ "../grid_common/grid_sys.o" \ "../grid_common/grid_allocator.o" \ @@ -174,6 +176,7 @@ DEPS_AS_ARGS += \ \ "usb/class/midi/device/audiodf_midi.d" \ "usb/class/midi/usb_protocol_midi.d" \ +"../grid_common/grid_cal.d" \ "../grid_common/grid_ain.d" \ "../grid_common/grid_sys.d" \ "../grid_common/grid_allocator.d" \