Allow Edit menu to call fn after edit; Fix PID Ki and Kd display in menus; Actually use changed PID and Max Accel values

Add new 'callback' edit-menu types that call a function after the edit is done. Use this to display and edit Ki and Kd correctly (removing the scaling first and reapplying it after). Also use it to reset maximum stepwise acceleration rates, after updating mm/s^2 rates via menus. (Previously, changes did nothing to affect planner unless saved back to EEPROM, and the machine reset).

Add calls to updatePID() so that PID loop uses updated values whether set by gcode (it already did this), or by restoring defaults, or loading from EEPROM (it didn't do those last two). Similarly, update the maximum step/s^2 accel rates when the mm/s^2 values are changed - whether by menu edits, restore defaults, or EEPROM read.

Refactor the acceleration rate update logic, and the PID scaling logic, into new functions that can be called from wherever, including the callbacks.

Add menu items to allow the z jerk and e jerk to be viewed/edited in the Control->Motion menu, as per xy jerk.

Conflicts:
	Marlin/language.h
This commit is contained in:
Simon Oliver 2013-03-19 09:05:11 -05:00 committed by daid303
parent 1f74ef4157
commit 93f0463b21
9 changed files with 243 additions and 74 deletions

View file

@ -122,7 +122,7 @@ void Config_PrintSettings()
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)");
SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum XY jerk (mm/s), Z=maximum Z jerk (mm/s), E=maximum E jerk (mm/s)");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M205 S",minimumfeedrate );
SERIAL_ECHOPAIR(" T" ,mintravelfeedrate );
@ -144,8 +144,8 @@ void Config_PrintSettings()
SERIAL_ECHOLNPGM("PID settings:");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M301 P",Kp);
SERIAL_ECHOPAIR(" I" ,Ki/PID_dT);
SERIAL_ECHOPAIR(" D" ,Kd*PID_dT);
SERIAL_ECHOPAIR(" I" ,unscalePID_i(Ki));
SERIAL_ECHOPAIR(" D" ,unscalePID_d(Kd));
SERIAL_ECHOLN("");
#endif
}
@ -166,6 +166,10 @@ void Config_RetrieveSettings()
EEPROM_READ_VAR(i,axis_steps_per_unit);
EEPROM_READ_VAR(i,max_feedrate);
EEPROM_READ_VAR(i,max_acceleration_units_per_sq_second);
// steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner)
reset_acceleration_rates();
EEPROM_READ_VAR(i,acceleration);
EEPROM_READ_VAR(i,retract_acceleration);
EEPROM_READ_VAR(i,minimumfeedrate);
@ -188,18 +192,19 @@ void Config_RetrieveSettings()
#ifndef PIDTEMP
float Kp,Ki,Kd;
#endif
// do not need to scale PID values as the values in EEPROM are already scaled
EEPROM_READ_VAR(i,Kp);
EEPROM_READ_VAR(i,Ki);
EEPROM_READ_VAR(i,Kd);
// Call updatePID (similar to when we have processed M301)
updatePID();
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Stored settings retreived:");
SERIAL_ECHOLNPGM("Stored settings retrieved");
}
else
{
Config_ResetDefault();
SERIAL_ECHO_START;
SERIAL_ECHOLN("Using Default settings:");
}
Config_PrintSettings();
}
@ -216,6 +221,10 @@ void Config_ResetDefault()
max_feedrate[i]=tmp2[i];
max_acceleration_units_per_sq_second[i]=tmp3[i];
}
// steps per sq second need to be updated to agree with the units per sq second
reset_acceleration_rates();
acceleration=DEFAULT_ACCELERATION;
retract_acceleration=DEFAULT_RETRACT_ACCELERATION;
minimumfeedrate=DEFAULT_MINIMUMFEEDRATE;
@ -235,10 +244,18 @@ void Config_ResetDefault()
#endif
#ifdef PIDTEMP
Kp = DEFAULT_Kp;
Ki = (DEFAULT_Ki*PID_dT);
Kd = (DEFAULT_Kd/PID_dT);
Ki = scalePID_i(DEFAULT_Ki);
Kd = scalePID_d(DEFAULT_Kd);
// call updatePID (similar to when we have processed M301)
updatePID();
#ifdef PID_ADD_EXTRUSION_RATE
Kc = DEFAULT_Kc;
#endif//PID_ADD_EXTRUSION_RATE
#endif//PIDTEMP
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded");
}

View file

@ -363,13 +363,8 @@ void setup()
fromsd[i] = false;
}
Config_RetrieveSettings(); // loads data from EEPROM if available
for(int8_t i=0; i < NUM_AXIS; i++)
{
axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
}
// loads data from EEPROM if available else uses defaults (and resets step acceleration rate)
Config_RetrieveSettings();
tp_init(); // Initialize temperature loop
plan_init(); // Initialize planner;
@ -1323,9 +1318,10 @@ void process_commands()
if(code_seen(axis_codes[i]))
{
max_acceleration_units_per_sq_second[i] = code_value();
axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
}
}
// steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner)
reset_acceleration_rates();
break;
#if 0 // Not used for Sprinter/grbl gen6
case 202: // M202
@ -1468,22 +1464,25 @@ void process_commands()
case 301: // M301
{
if(code_seen('P')) Kp = code_value();
if(code_seen('I')) Ki = code_value()*PID_dT;
if(code_seen('D')) Kd = code_value()/PID_dT;
if(code_seen('I')) Ki = scalePID_i(code_value());
if(code_seen('D')) Kd = scalePID_d(code_value());
#ifdef PID_ADD_EXTRUSION_RATE
if(code_seen('C')) Kc = code_value();
#endif
updatePID();
SERIAL_PROTOCOL(MSG_OK);
SERIAL_PROTOCOL(" p:");
SERIAL_PROTOCOL(Kp);
SERIAL_PROTOCOL(" i:");
SERIAL_PROTOCOL(Ki/PID_dT);
SERIAL_PROTOCOL(unscalePID_i(Ki));
SERIAL_PROTOCOL(" d:");
SERIAL_PROTOCOL(Kd*PID_dT);
SERIAL_PROTOCOL(unscalePID_d(Kd));
#ifdef PID_ADD_EXTRUSION_RATE
SERIAL_PROTOCOL(" c:");
SERIAL_PROTOCOL(Kc*PID_dT);
//Kc does not have scaling applied above, or in resetting defaults
SERIAL_PROTOCOL(Kc);
#endif
SERIAL_PROTOCOLLN("");
}
@ -1493,16 +1492,18 @@ void process_commands()
case 304: // M304
{
if(code_seen('P')) bedKp = code_value();
if(code_seen('I')) bedKi = code_value()*PID_dT;
if(code_seen('D')) bedKd = code_value()/PID_dT;
if(code_seen('I')) bedKi = scalePID_i(code_value());
if(code_seen('D')) bedKd = scalePID_d(code_value());
// Scale the Bed PID values by PID_dT
scaleBedPID();
updatePID();
SERIAL_PROTOCOL(MSG_OK);
SERIAL_PROTOCOL(" p:");
SERIAL_PROTOCOL(bedKp);
SERIAL_PROTOCOL(" i:");
SERIAL_PROTOCOL(bedKi/PID_dT);
SERIAL_PROTOCOL(unscalePID_i(bedKi));
SERIAL_PROTOCOL(" d:");
SERIAL_PROTOCOL(bedKd*PID_dT);
SERIAL_PROTOCOL(unscalePID_d(bedKd));
SERIAL_PROTOCOLLN("");
}
break;

View file

@ -76,6 +76,8 @@
#define MSG_PID_C "PID-C"
#define MSG_ACC "Accel"
#define MSG_VXY_JERK "Vxy-jerk"
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX "Vmax "
#define MSG_X "x"
#define MSG_Y "y"
@ -233,6 +235,8 @@
#define MSG_PID_C "PID-C"
#define MSG_ACC "Acc"
#define MSG_VXY_JERK "Zryw Vxy"
#define MSG_VZ_JERK "Zryw Vz"
#define MSG_VE_JERK "Zryw Ve"
#define MSG_VMAX "Vmax"
#define MSG_X "x"
#define MSG_Y "y"
@ -391,7 +395,9 @@
#define MSG_PID_D " PID-D: "
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VXY_JERK "Vxy-jerk"
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
@ -555,6 +561,8 @@
#define MSG_PID_C "PID-C"
#define MSG_ACC "Acc"
#define MSG_VXY_JERK "Vxy-jerk"
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX "Vmax "
#define MSG_X "x"
#define MSG_Y "y"
@ -713,6 +721,8 @@
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
@ -871,6 +881,8 @@
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
@ -1024,6 +1036,8 @@
#define MSG_PID_C "PID-C"
#define MSG_ACC "Accel"
#define MSG_VXY_JERK "Vxy-jerk"
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX "Vmax"
#define MSG_X "x"
#define MSG_Y "y"
@ -1184,6 +1198,8 @@
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
@ -1350,6 +1366,8 @@
#define MSG_PID_C "PID-C"
#define MSG_ACC "Kiihtyv"
#define MSG_VXY_JERK "Vxy-jerk"
#define MSG_VZ_JERK "Vz-jerk"
#define MSG_VE_JERK "Ve-jerk"
#define MSG_VMAX "Vmax "
#define MSG_X "x"
#define MSG_Y "y"
@ -1465,4 +1483,3 @@
#endif
#endif // ifndef LANGUAGE_H

View file

@ -895,3 +895,11 @@ void allow_cold_extrudes(bool allow)
#endif
}
// Calculate the steps/s^2 acceleration rates, based on the mm/s^s
void reset_acceleration_rates()
{
for(int8_t i=0; i < NUM_AXIS; i++)
{
axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
}
}

View file

@ -136,4 +136,6 @@ FORCE_INLINE bool blocks_queued()
}
void allow_cold_extrudes(bool allow);
void reset_acceleration_rates();
#endif

View file

@ -1128,3 +1128,31 @@ ISR(TIMER0_COMPB_vect)
#endif
}
}
#ifdef PIDTEMP
// Apply the scale factors to the PID values
float scalePID_i(float i)
{
return i*PID_dT;
}
float unscalePID_i(float i)
{
return i/PID_dT;
}
float scalePID_d(float d)
{
return d/PID_dT;
}
float unscalePID_d(float d)
{
return d*PID_dT;
}
#endif //PIDTEMP

View file

@ -31,8 +31,8 @@
void tp_init(); //initialise the heating
void manage_heater(); //it is critical that this is called periodically.
//low leven conversion routines
// do not use this routines and variables outsie of temperature.cpp
// low level conversion routines
// do not use these routines and variables outside of temperature.cpp
extern int target_temperature[EXTRUDERS];
extern float current_temperature[EXTRUDERS];
extern int target_temperature_bed;
@ -40,6 +40,11 @@ extern float current_temperature_bed;
#ifdef PIDTEMP
extern float Kp,Ki,Kd,Kc;
float scalePID_i(float i);
float scalePID_d(float d);
float unscalePID_i(float i);
float unscalePID_d(float d);
#endif
#ifdef PIDTEMPBED
extern float bedKp,bedKi,bedKd;

View file

@ -31,6 +31,10 @@ char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG;
#endif
/** forward declerations **/
void copy_and_scalePID_i();
void copy_and_scalePID_d();
/* Different menus */
static void lcd_status_screen();
#ifdef ULTIPANEL
@ -63,6 +67,14 @@ static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float
static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue);
static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue);
static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float32(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float5(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc);
static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc);
#define ENCODER_STEPS_PER_MENU_ITEM 5
@ -93,6 +105,7 @@ static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr,
} while(0)
#define MENU_ITEM_DUMMY() do { _menuItemNr++; } while(0)
#define MENU_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label) , ## args )
#define MENU_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label) , ## args )
#define END_MENU() \
if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM >= _menuItemNr) encoderPosition = _menuItemNr * ENCODER_STEPS_PER_MENU_ITEM - 1; \
if ((uint8_t)(encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) >= currentMenuViewOffset + LCD_HEIGHT) { currentMenuViewOffset = (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) - LCD_HEIGHT + 1; lcdDrawUpdate = 1; _lineNr = currentMenuViewOffset - 1; _drawLineNr = -1; } \
@ -123,6 +136,10 @@ uint16_t prevEncoderPosition;
const char* editLabel;
void* editValue;
int32_t minEditValue, maxEditValue;
menuFunc_t callbackFunc;
// placeholders for Ki and Kd edits
float raw_Ki, raw_Kd;
/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependend */
static void lcd_status_screen()
@ -442,6 +459,10 @@ static void lcd_control_menu()
static void lcd_control_temperature_menu()
{
// set up temp variables - undo the default scaling
raw_Ki = unscalePID_i(Ki);
raw_Kd = unscalePID_d(Kd);
START_MENU();
MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15);
@ -463,9 +484,9 @@ static void lcd_control_temperature_menu()
#endif
#ifdef PIDTEMP
MENU_ITEM_EDIT(float52, MSG_PID_P, &Kp, 1, 9990);
//TODO, I and D should have a PID_dT multiplier (Ki = PID_I * PID_dT, Kd = PID_D / PID_dT)
MENU_ITEM_EDIT(float52, MSG_PID_I, &Ki, 1, 9990);
MENU_ITEM_EDIT(float52, MSG_PID_D, &Kd, 1, 9990);
// i is typically a small value so allows values below 1
MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i);
MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d);
# ifdef PID_ADD_EXTRUSION_RATE
MENU_ITEM_EDIT(float3, MSG_PID_C, &Kc, 1, 9990);
# endif//PID_ADD_EXTRUSION_RATE
@ -511,16 +532,18 @@ static void lcd_control_motion_menu()
MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 99000);
MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990);
MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &max_z_jerk, 0.1, 990);
MENU_ITEM_EDIT(float3, MSG_VE_JERK, &max_e_jerk, 1, 990);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &max_feedrate[X_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &max_feedrate[Y_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &max_feedrate[Z_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &max_feedrate[E_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMIN, &minimumfeedrate, 0, 999);
MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &mintravelfeedrate, 0, 999);
MENU_ITEM_EDIT(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000);
MENU_ITEM_EDIT(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000);
MENU_ITEM_EDIT(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 100, 99000);
MENU_ITEM_EDIT(long5, MSG_AMAX MSG_E, &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000, reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000, reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 100, 99000, reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000, reset_acceleration_rates);
MENU_ITEM_EDIT(float5, MSG_A_RETRACT, &retract_acceleration, 100, 99000);
MENU_ITEM_EDIT(float52, MSG_XSTEPS, &axis_steps_per_unit[X_AXIS], 5, 9999);
MENU_ITEM_EDIT(float52, MSG_YSTEPS, &axis_steps_per_unit[Y_AXIS], 5, 9999);
@ -610,6 +633,23 @@ void lcd_sdcard_menu()
encoderPosition = prevEncoderPosition; \
} \
} \
void menu_edit_callback_ ## _name () \
{ \
if ((int32_t)encoderPosition < minEditValue) \
encoderPosition = minEditValue; \
if ((int32_t)encoderPosition > maxEditValue) \
encoderPosition = maxEditValue; \
if (lcdDrawUpdate) \
lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \
if (LCD_CLICKED) \
{ \
*((_type*)editValue) = ((_type)encoderPosition) / scale; \
lcd_quick_feedback(); \
currentMenu = prevMenu; \
encoderPosition = prevEncoderPosition; \
(*callbackFunc)();\
} \
} \
static void menu_action_setting_edit_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) \
{ \
prevMenu = currentMenu; \
@ -623,6 +663,21 @@ void lcd_sdcard_menu()
minEditValue = minValue * scale; \
maxEditValue = maxValue * scale; \
encoderPosition = (*ptr) * scale; \
}\
static void menu_action_setting_edit_callback_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) \
{ \
prevMenu = currentMenu; \
prevEncoderPosition = encoderPosition; \
\
lcdDrawUpdate = 2; \
currentMenu = menu_edit_callback_ ## _name; \
\
editLabel = pstr; \
editValue = ptr; \
minEditValue = minValue * scale; \
maxEditValue = maxValue * scale; \
encoderPosition = (*ptr) * scale; \
callbackFunc = callback;\
}
menu_edit_type(int, int3, itostr3, 1)
menu_edit_type(float, float3, ftostr3, 1)
@ -1070,4 +1125,20 @@ char *ftostr52(const float &x)
return conv;
}
// Callback for after editing PID i value
// grab the pid i value out of the temp variable; scale it; then update the PID driver
void copy_and_scalePID_i()
{
Ki = scalePID_i(raw_Ki);
updatePID();
}
// Callback for after editing PID d value
// grab the pid d value out of the temp variable; scale it; then update the PID driver
void copy_and_scalePID_d()
{
Kd = scalePID_d(raw_Kd);
updatePID();
}
#endif //ULTRA_LCD

View file

@ -376,6 +376,26 @@ static void lcd_implementation_drawmenu_setting_edit_generic_P(uint8_t row, cons
#define lcd_implementation_drawmenu_setting_edit_long5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_bool_selected(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
#define lcd_implementation_drawmenu_setting_edit_bool(row, pstr, pstr2, data) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
//Add version for callback functions
#define lcd_implementation_drawmenu_setting_edit_callback_int3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', itostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_int3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', itostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float3_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float3(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float32_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float32(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float52_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float52(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr52(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float51_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr51(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_float51(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr51(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_long5_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_long5(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data)))
#define lcd_implementation_drawmenu_setting_edit_callback_bool_selected(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
#define lcd_implementation_drawmenu_setting_edit_callback_bool(row, pstr, pstr2, data, callback) lcd_implementation_drawmenu_setting_edit_generic_P(row, pstr, ' ', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF))
void lcd_implementation_drawedit(const char* pstr, char* value)
{
lcd.setCursor(1, 1);