From cb12161191be148906d31642b44af04248c3d6cc Mon Sep 17 00:00:00 2001
From: wgm4321 <wgm4321@live.com>
Date: Sun, 28 Dec 2014 20:43:14 -0500
Subject: [PATCH] Add Filament menu and add Filament/Retract settings to config
 store.

---
 Marlin/ConfigurationStore.cpp                 | 124 ++++++++++++++++--
 Marlin/Marlin.h                               |   4 +
 Marlin/Marlin_main.cpp                        |  78 ++++++++---
 Marlin/language_en.h                          |   5 +
 Marlin/ultralcd.cpp                           |  45 ++++++-
 Marlin/ultralcd.h                             |   1 +
 .../ultralcd_implementation_hitachi_HD44780.h |   4 +
 7 files changed, 232 insertions(+), 29 deletions(-)

diff --git a/Marlin/ConfigurationStore.cpp b/Marlin/ConfigurationStore.cpp
index 20e68d09e3..0b3e485503 100644
--- a/Marlin/ConfigurationStore.cpp
+++ b/Marlin/ConfigurationStore.cpp
@@ -38,15 +38,7 @@ void _EEPROM_readData(int &pos, uint8_t* value, uint8_t size)
 // wrong data being written to the variables.
 // ALSO:  always make sure the variables in the Store and retrieve sections are in the same order.
 
-#define EEPROM_VERSION "V10"
-#ifdef DELTA
-	#undef EEPROM_VERSION
-	#define EEPROM_VERSION "V11"
-#endif
-#ifdef SCARA
-	#undef EEPROM_VERSION
-	#define EEPROM_VERSION "V12"
-#endif
+#define EEPROM_VERSION "V13"
 
 #ifdef EEPROM_SETTINGS
 void Config_StoreSettings() 
@@ -101,6 +93,31 @@ void Config_StoreSettings()
   #ifdef SCARA
   EEPROM_WRITE_VAR(i,axis_scaling);        // Add scaling for SCARA
   #endif
+  #ifdef FWRETRACT
+  EEPROM_WRITE_VAR(i,autoretract_enabled);
+  EEPROM_WRITE_VAR(i,retract_length);
+  #if EXTRUDERS > 1
+  EEPROM_WRITE_VAR(i,retract_length_swap);
+  #endif
+  EEPROM_WRITE_VAR(i,retract_feedrate);
+  EEPROM_WRITE_VAR(i,retract_zlift);
+  EEPROM_WRITE_VAR(i,retract_recover_length);
+  #if EXTRUDERS > 1
+  EEPROM_WRITE_VAR(i,retract_recover_length_swap);
+  #endif
+  EEPROM_WRITE_VAR(i,retract_recover_feedrate);
+  #endif
+
+  // Save filament sizes
+  EEPROM_WRITE_VAR(i, volumetric_enabled);
+  EEPROM_WRITE_VAR(i, filament_size[0]);
+  #if EXTRUDERS > 1
+  EEPROM_WRITE_VAR(i, filament_size[1]);
+  #if EXTRUDERS > 2
+  EEPROM_WRITE_VAR(i, filament_size[2]);
+  #endif
+  #endif
+  
   char ver2[4]=EEPROM_VERSION;
   i=EEPROM_OFFSET;
   EEPROM_WRITE_VAR(i,ver2); // validate data
@@ -210,12 +227,46 @@ SERIAL_ECHOLNPGM("Scaling factors:");
     SERIAL_ECHO_START;
     SERIAL_ECHOLNPGM("Recover: S=Extra length (mm) F:Speed (mm/m)");
     SERIAL_ECHO_START;
-    SERIAL_ECHOPAIR("   M208 S",retract_recover_length); 
-    SERIAL_ECHOPAIR(" F" ,retract_recover_feedrate*60); 
-    SERIAL_ECHOLN(""); 
+    SERIAL_ECHOPAIR("   M208 S",retract_recover_length);
+    SERIAL_ECHOPAIR(" F", retract_recover_feedrate*60);
+	SERIAL_ECHOLN("");
+    SERIAL_ECHO_START;
+    SERIAL_ECHOLNPGM("Auto-Retract: S=0 to disable, 1 to interpret extrude-only moves as retracts or recoveries");
+    SERIAL_ECHO_START;
+    SERIAL_ECHOPAIR("   M209 S", (unsigned long)(autoretract_enabled ? 1 : 0));
+    SERIAL_ECHOLN("");
+#if EXTRUDERS > 1
+    SERIAL_ECHO_START;
+    SERIAL_ECHOLNPGM("Multi-extruder settings:");
+    SERIAL_ECHO_START;
+    SERIAL_ECHOPAIR("   Swap retract length (mm):    ", retract_length_swap);
+    SERIAL_ECHOLN("");
+    SERIAL_ECHO_START;
+    SERIAL_ECHOPAIR("   Swap rec. addl. length (mm): ", retract_recover_length_swap);
+    SERIAL_ECHOLN("");
 #endif
+    SERIAL_ECHO_START;
+    if (volumetric_enabled) {
+        SERIAL_ECHOLNPGM("Filament settings:");
+        SERIAL_ECHO_START;
+        SERIAL_ECHOPAIR("   M200 D", filament_size[0]);
+        SERIAL_ECHOLN(""); 
+#if EXTRUDERS > 1
+		SERIAL_ECHO_START;
+        SERIAL_ECHOPAIR("   M200 T1 D", filament_size[1]);
+        SERIAL_ECHOLN(""); 
+#if EXTRUDERS > 2
+		SERIAL_ECHO_START;
+        SERIAL_ECHOPAIR("   M200 T2 D", filament_size[2]);
+		SERIAL_ECHOLN("");
+#endif
+#endif
+    } else {
+        SERIAL_ECHOLNPGM("Filament settings: Disabled");
+    }
 } 
 #endif
+#endif
 
 
 #ifdef EEPROM_SETTINGS
@@ -277,6 +328,30 @@ void Config_RetrieveSettings()
 		EEPROM_READ_VAR(i,axis_scaling);
 		#endif
 
+		#ifdef FWRETRACT
+		EEPROM_READ_VAR(i,autoretract_enabled);
+		EEPROM_READ_VAR(i,retract_length);
+		#if EXTRUDERS > 1
+		EEPROM_READ_VAR(i,retract_length_swap);
+		#endif
+		EEPROM_READ_VAR(i,retract_feedrate);
+		EEPROM_READ_VAR(i,retract_zlift);
+		EEPROM_READ_VAR(i,retract_recover_length);
+		#if EXTRUDERS > 1
+		EEPROM_READ_VAR(i,retract_recover_length_swap);
+		#endif
+		EEPROM_READ_VAR(i,retract_recover_feedrate);
+		#endif
+
+		EEPROM_READ_VAR(i, volumetric_enabled);
+		EEPROM_READ_VAR(i, filament_size[0]);
+#if EXTRUDERS > 1
+		EEPROM_READ_VAR(i, filament_size[1]);
+#if EXTRUDERS > 2
+		EEPROM_READ_VAR(i, filament_size[2]);
+#endif
+#endif
+		calculate_volumetric_multipliers();
 		// Call updatePID (similar to when we have processed M301)
 		updatePID();
         SERIAL_ECHO_START;
@@ -353,6 +428,31 @@ void Config_ResetDefault()
 #endif//PID_ADD_EXTRUSION_RATE
 #endif//PIDTEMP
 
+#ifdef FWRETRACT
+	autoretract_enabled = false;
+	retract_length = RETRACT_LENGTH;
+#if EXTRUDERS > 1
+	retract_length_swap = RETRACT_LENGTH_SWAP;
+#endif
+	retract_feedrate = RETRACT_FEEDRATE;
+	retract_zlift = RETRACT_ZLIFT;
+	retract_recover_length = RETRACT_RECOVER_LENGTH;
+#if EXTRUDERS > 1
+	retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
+#endif
+	retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE;
+#endif
+
+	volumetric_enabled = false;
+	filament_size[0] = DEFAULT_NOMINAL_FILAMENT_DIA;
+#if EXTRUDERS > 1
+	filament_size[1] = DEFAULT_NOMINAL_FILAMENT_DIA;
+#if EXTRUDERS > 2
+	filament_size[2] = DEFAULT_NOMINAL_FILAMENT_DIA;
+#endif
+#endif
+	calculate_volumetric_multipliers();
+
 SERIAL_ECHO_START;
 SERIAL_ECHOLNPGM("Hardcoded Default Settings Loaded");
 
diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index 444c43f695..84915e7b2a 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -209,7 +209,9 @@ extern float homing_feedrate[];
 extern bool axis_relative_modes[];
 extern int feedmultiply;
 extern int extrudemultiply; // Sets extrude multiply factor (in percent) for all extruders
+extern bool volumetric_enabled;
 extern int extruder_multiply[EXTRUDERS]; // sets extrude multiply factor (in percent) for each extruder individually
+extern float filament_size[EXTRUDERS]; // cross-sectional area of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder.
 extern float volumetric_multiplier[EXTRUDERS]; // reciprocal of cross-sectional area of filament (in square millimeters), stored this way to reduce computational burden in planner
 extern float current_position[NUM_AXIS] ;
 extern float add_homing[3];
@@ -266,3 +268,5 @@ extern void digipot_i2c_init();
 #endif
 
 #endif
+
+extern void calculate_volumetric_multipliers();
\ No newline at end of file
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 644ae31f1a..314eb433ee 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -215,6 +215,15 @@ int extruder_multiply[EXTRUDERS] = {100
     #endif
   #endif
 };
+bool volumetric_enabled = false;
+float filament_size[EXTRUDERS] = { DEFAULT_NOMINAL_FILAMENT_DIA
+  #if EXTRUDERS > 1
+      , DEFAULT_NOMINAL_FILAMENT_DIA
+    #if EXTRUDERS > 2
+       , DEFAULT_NOMINAL_FILAMENT_DIA
+    #endif
+  #endif
+};
 float volumetric_multiplier[EXTRUDERS] = {1.0
   #if EXTRUDERS > 1
     , 1.0
@@ -2823,21 +2832,7 @@ Sigma_Exit:
     #endif //BLINKM
     case 200: // M200 D<millimeters> set filament diameter and set E axis units to cubic millimeters (use S0 to set back to millimeters).
       {
-        float area = .0;
-        float radius = .0;
-        if(code_seen('D')) {
-          radius = (float)code_value() * .5;
-          if(radius == 0) {
-            area = 1;
-          } else {
-            area = M_PI * pow(radius, 2);
-          }
-        } else {
-          //reserved for setting filament diameter via UFID or filament measuring device
-          break;
-        
-          
-        }
+
         tmp_extruder = active_extruder;
         if(code_seen('T')) {
           tmp_extruder = code_value();
@@ -2847,7 +2842,32 @@ Sigma_Exit:
             break;
           }
         }
-        volumetric_multiplier[tmp_extruder] = 1 / area;
+
+        float area = .0;
+        if(code_seen('D')) {
+		  float diameter = (float)code_value();
+		  if (diameter == 0.0) {
+			// setting any extruder filament size disables volumetric on the assumption that
+			// slicers either generate in extruder values as cubic mm or as as filament feeds
+			// for all extruders
+		    volumetric_enabled = false;
+		  } else {
+            filament_size[tmp_extruder] = (float)code_value();
+			// make sure all extruders have some sane value for the filament size
+			filament_size[0] = (filament_size[0] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[0]);
+            #if EXTRUDERS > 1
+			filament_size[1] = (filament_size[1] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[1]);
+            #if EXTRUDERS > 2
+			filament_size[2] = (filament_size[2] == 0.0 ? DEFAULT_NOMINAL_FILAMENT_DIA : filament_size[2]);
+            #endif
+            #endif
+			volumetric_enabled = true;
+		  }
+        } else {
+          //reserved for setting filament diameter via UFID or filament measuring device
+          break;
+        }
+		calculate_volumetric_multipliers();
       }
       break;
     case 201: // M201
@@ -4580,3 +4600,29 @@ bool setTargetedHotend(int code){
   return false;
 }
 
+
+float calculate_volumetric_multiplier(float diameter) {
+	float area = .0;
+	float radius = .0;
+
+	radius = diameter * .5;
+	if (! volumetric_enabled || radius == 0) {
+		area = 1;
+	}
+	else {
+		area = M_PI * pow(radius, 2);
+	}
+
+	return 1.0 / area;
+}
+
+void calculate_volumetric_multipliers() {
+	volumetric_multiplier[0] = calculate_volumetric_multiplier(filament_size[0]);
+#if EXTRUDERS > 1
+	volumetric_multiplier[1] = calculate_volumetric_multiplier(filament_size[1]);
+#if EXTRUDERS > 2
+	volumetric_multiplier[2] = calculate_volumetric_multiplier(filament_size[2]);
+#endif
+#endif
+}
+
diff --git a/Marlin/language_en.h b/Marlin/language_en.h
index c094ff641f..5758e7a7b4 100644
--- a/Marlin/language_en.h
+++ b/Marlin/language_en.h
@@ -86,6 +86,11 @@
 #define MSG_ESTEPS                          "Esteps/mm"
 #define MSG_TEMPERATURE                     "Temperature"
 #define MSG_MOTION                          "Motion"
+#define MSG_VOLUMETRIC                      "Filament"
+#define MSG_VOLUMETRIC_ENABLED		        "E in mm3"
+#define MSG_FILAMENT_SIZE_EXTRUDER_0        "Fil. Dia. 1"
+#define MSG_FILAMENT_SIZE_EXTRUDER_1        "Fil. Dia. 2"
+#define MSG_FILAMENT_SIZE_EXTRUDER_2        "Fil. Dia. 3"
 #define MSG_CONTRAST                        "LCD contrast"
 #define MSG_STORE_EPROM                     "Store memory"
 #define MSG_LOAD_EPROM                      "Load memory"
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 916114899c..adae93bc8d 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -59,6 +59,7 @@ static void lcd_control_temperature_menu();
 static void lcd_control_temperature_preheat_pla_settings_menu();
 static void lcd_control_temperature_preheat_abs_settings_menu();
 static void lcd_control_motion_menu();
+static void lcd_control_volumetric_menu();
 #ifdef DOGLCD
 static void lcd_set_contrast();
 #endif
@@ -78,6 +79,7 @@ static void menu_action_setting_edit_bool(const char* pstr, bool* ptr);
 static void menu_action_setting_edit_int3(const char* pstr, int* ptr, int minValue, int maxValue);
 static void menu_action_setting_edit_float3(const char* pstr, float* ptr, float minValue, float maxValue);
 static void menu_action_setting_edit_float32(const char* pstr, float* ptr, float minValue, float maxValue);
+static void menu_action_setting_edit_float43(const char* pstr, float* ptr, float minValue, float maxValue);
 static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float minValue, float maxValue);
 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);
@@ -86,6 +88,7 @@ static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr,
 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_float43(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);
@@ -721,6 +724,8 @@ static void lcd_control_menu()
     MENU_ITEM(back, MSG_MAIN, lcd_main_menu);
     MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
     MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu);
+	MENU_ITEM(submenu, MSG_VOLUMETRIC, lcd_control_volumetric_menu);
+
 #ifdef DOGLCD
 //    MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63);
     MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast);
@@ -849,6 +854,26 @@ static void lcd_control_motion_menu()
     END_MENU();
 }
 
+static void lcd_control_volumetric_menu()
+{
+	START_MENU();
+	MENU_ITEM(back, MSG_CONTROL, lcd_control_menu);
+
+	MENU_ITEM_EDIT(bool, MSG_VOLUMETRIC_ENABLED, &volumetric_enabled);
+
+	if (volumetric_enabled) {
+		MENU_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER_0, &filament_size[0], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
+#if EXTRUDERS > 1
+		MENU_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER_1, &filament_size[1], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
+#if EXTRUDERS > 2
+		MENU_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_SIZE_EXTRUDER_2, &filament_size[2], DEFAULT_NOMINAL_FILAMENT_DIA - .5, DEFAULT_NOMINAL_FILAMENT_DIA + .5, calculate_volumetric_multipliers);
+#endif
+#endif
+	}
+
+	END_MENU();
+}
+
 #ifdef DOGLCD
 static void lcd_set_contrast()
 {
@@ -992,6 +1017,7 @@ void lcd_sdcard_menu()
 menu_edit_type(int, int3, itostr3, 1)
 menu_edit_type(float, float3, ftostr3, 1)
 menu_edit_type(float, float32, ftostr32, 100)
+menu_edit_type(float, float43, ftostr43, 1000)
 menu_edit_type(float, float5, ftostr5, 0.01)
 menu_edit_type(float, float51, ftostr51, 10)
 menu_edit_type(float, float52, ftostr52, 100)
@@ -1461,7 +1487,24 @@ char *ftostr32(const float &x)
   return conv;
 }
 
-// Convert float to string with 1.23 format
+// Convert float to string with 1.234 format
+char *ftostr43(const float &x)
+{
+	long xx = x * 1000;
+    if (xx >= 0)
+		conv[0] = (xx / 1000) % 10 + '0';
+	else
+		conv[0] = '-';
+	xx = abs(xx);
+	conv[1] = '.';
+	conv[2] = (xx / 100) % 10 + '0';
+	conv[3] = (xx / 10) % 10 + '0';
+	conv[4] = (xx) % 10 + '0';
+	conv[5] = 0;
+	return conv;
+}
+
+//Float to string with 1.23 format
 char *ftostr12ns(const float &x)
 {
   long xx=x*100;
diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h
index 339955e592..144bfa60be 100644
--- a/Marlin/ultralcd.h
+++ b/Marlin/ultralcd.h
@@ -118,6 +118,7 @@ char *ftostr3(const float &x);
 char *ftostr31ns(const float &x); // float to string without sign character
 char *ftostr31(const float &x);
 char *ftostr32(const float &x);
+char *ftostr43(const float &x);
 char *ftostr12ns(const float &x); 
 char *ftostr5(const float &x);
 char *ftostr51(const float &x);
diff --git a/Marlin/ultralcd_implementation_hitachi_HD44780.h b/Marlin/ultralcd_implementation_hitachi_HD44780.h
index bf50812c4f..af38003c49 100644
--- a/Marlin/ultralcd_implementation_hitachi_HD44780.h
+++ b/Marlin/ultralcd_implementation_hitachi_HD44780.h
@@ -693,6 +693,8 @@ static void lcd_implementation_drawmenu_setting_edit_generic_P(uint8_t row, cons
 #define lcd_implementation_drawmenu_setting_edit_float3(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr3(*(data)))
 #define lcd_implementation_drawmenu_setting_edit_float32_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr32(*(data)))
 #define lcd_implementation_drawmenu_setting_edit_float32(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr32(*(data)))
+#define lcd_implementation_drawmenu_setting_edit_float43_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr43(*(data)))
+#define lcd_implementation_drawmenu_setting_edit_float43(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr43(*(data)))
 #define lcd_implementation_drawmenu_setting_edit_float5_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr5(*(data)))
 #define lcd_implementation_drawmenu_setting_edit_float5(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr5(*(data)))
 #define lcd_implementation_drawmenu_setting_edit_float52_selected(row, pstr, pstr2, data, minValue, maxValue) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr52(*(data)))
@@ -711,6 +713,8 @@ static void lcd_implementation_drawmenu_setting_edit_generic_P(uint8_t row, cons
 #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_float43_selected(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, '>', ftostr43(*(data)))
+#define lcd_implementation_drawmenu_setting_edit_callback_float43(row, pstr, pstr2, data, minValue, maxValue, callback) lcd_implementation_drawmenu_setting_edit_generic(row, pstr, ' ', ftostr43(*(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)))