From 16212432c9152a6e9f678ad7e21cfc7dfc8d7e7e Mon Sep 17 00:00:00 2001
From: Reid Rankin <reidrankin@gmail.com>
Date: Tue, 31 May 2016 10:26:08 -0500
Subject: [PATCH 1/4] G20/21 and M149 support, and code_value() refactor

This is an update of MarlinDev PR #196.

G20/21: support for switching input units between millimeters and
inches.
M149: support for changing input temperature units.

In support of these changes, code_value() and code_value_short() are
replaced with an array of functions which handle converting to the
proper types and/or units.
---
 Marlin/Configuration.h                        |  10 +
 Marlin/M100_Free_Mem_Chk.cpp                  |   5 +-
 Marlin/Marlin.h                               |  18 +-
 Marlin/Marlin_main.cpp                        | 493 ++++++++++++------
 .../Felix/Configuration.h                     |  10 +
 .../Felix/DUAL/Configuration.h                |  10 +
 .../Hephestos/Configuration.h                 |  10 +
 .../Hephestos_2/Configuration.h               |  10 +
 .../K8200/Configuration.h                     |  10 +
 .../RepRapWorld/Megatronics/Configuration.h   |  10 +
 .../RigidBot/Configuration.h                  |  10 +
 .../SCARA/Configuration.h                     |  10 +
 .../TAZ4/Configuration.h                      |  10 +
 .../WITBOX/Configuration.h                    |  10 +
 .../adafruit/ST7565/Configuration.h           |  10 +
 .../delta/biv2.5/Configuration.h              |  10 +
 .../delta/generic/Configuration.h             |  10 +
 .../delta/kossel_mini/Configuration.h         |  10 +
 .../delta/kossel_pro/Configuration.h          |  10 +
 .../delta/kossel_xl/Configuration.h           |  10 +
 .../makibox/Configuration.h                   |  10 +
 .../tvrrug/Round2/Configuration.h             |  10 +
 Marlin/planner.cpp                            |   6 +-
 23 files changed, 531 insertions(+), 181 deletions(-)

diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h
index 4c17271023..502690ada0 100644
--- a/Marlin/Configuration.h
+++ b/Marlin/Configuration.h
@@ -749,6 +749,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/M100_Free_Mem_Chk.cpp b/Marlin/M100_Free_Mem_Chk.cpp
index 276df98eb1..36e01ae6cd 100644
--- a/Marlin/M100_Free_Mem_Chk.cpp
+++ b/Marlin/M100_Free_Mem_Chk.cpp
@@ -51,8 +51,7 @@ extern size_t  __heap_start, __heap_end, __flp;
 // Declare all the functions we need from Marlin_Main.cpp to do the work!
 //
 
-float code_value();
-long code_value_long();
+int code_value_int();
 bool code_seen(char);
 void serial_echopair_P(const char*, float);
 void serial_echopair_P(const char*, double);
@@ -177,7 +176,7 @@ void gcode_M100() {
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
   if (code_seen('C')) {
     int x;      // x gets the # of locations to corrupt within the memory pool
-    x = code_value();
+    x = code_value_int();
     SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
     ptr = (unsigned char*) __brkval;
     SERIAL_ECHOPAIR("\n__brkval : ", ptr);
diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index 1268308f1b..5e0b6bfb9f 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -217,6 +217,9 @@ enum AxisEnum {NO_AXIS = -1, X_AXIS = 0, A_AXIS = 0, Y_AXIS = 1, B_AXIS = 1, Z_A
 
 #define _AXIS(AXIS) AXIS ##_AXIS
 
+typedef enum { LINEARUNIT_MM = 0, LINEARUNIT_INCH = 1 } LinearUnit;
+typedef enum { TEMPUNIT_C = 0, TEMPUNIT_K = 1, TEMPUNIT_F = 2 } TempUnit;
+
 void enable_all_steppers();
 void disable_all_steppers();
 
@@ -288,9 +291,20 @@ extern bool axis_homed[3]; // axis[n].is_homed
 
 // GCode support for external objects
 bool code_seen(char);
-float code_value();
+float code_value_float();
+unsigned long code_value_ulong();
 long code_value_long();
-int16_t code_value_short();
+int code_value_int();
+uint16_t code_value_ushort();
+uint8_t code_value_byte();
+bool code_value_bool();
+float code_value_linear_units();
+float code_value_per_axis_unit(int axis);
+float code_value_axis_units(int axis);
+float code_value_temp_abs();
+float code_value_temp_diff();
+millis_t code_value_millis();
+millis_t code_value_millis_from_seconds();
 
 #if ENABLED(DELTA)
   extern float delta[3];
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 75c7661180..cb14abe39e 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -109,6 +109,8 @@
  * G5  - Cubic B-spline with XYZE destination and IJPQ offsets
  * G10 - retract filament according to settings of M207
  * G11 - retract recover filament according to settings of M208
+ * G20 - Set input units to inches
+ * G21 - Set input units to millimeters
  * G28 - Home one or more axes
  * G29 - Detailed Z probe, probes the bed at 3 or more points.  Will fail if you haven't homed yet.
  * G30 - Single Z probe, probes bed at current XY location.
@@ -178,6 +180,7 @@
  * M129 - EtoP Closed (BariCUDA EtoP = electricity to air pressure transducer by jmil)
  * M140 - Set bed target temp
  * M145 - Set the heatup state H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
+ * M149 - Set temperature units
  * M150 - Set BlinkM Color Output R: Red<0-255> U(!): Green<0-255> B: Blue<0-255> over i2c, G for green does not work.
  * M190 - Sxxx Wait for bed current temp to reach target temp. Waits only when heating
  *        Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
@@ -285,6 +288,14 @@ static int cmd_queue_index_w = 0;
 static int commands_in_queue = 0;
 static char command_queue[BUFSIZE][MAX_CMD_SIZE];
 
+#if ENABLED(INCH_MODE_SUPPORT)
+  float linear_unit_factor = 1.0;
+  float volumetric_unit_factor = 1.0;
+#endif
+#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
+  TempUnit input_temp_units = TEMPUNIT_C;
+#endif
+
 const float homing_feedrate[] = HOMING_FEEDRATE;
 bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
 int feedrate_multiplier = 100; //100->1 200->2
@@ -1165,7 +1176,7 @@ bool code_has_value() {
   return NUMERIC(c);
 }
 
-float code_value() {
+float code_value_float() {
   float ret;
   char* e = strchr(seen_pointer, 'E');
   if (e) {
@@ -1178,9 +1189,96 @@ float code_value() {
   return ret;
 }
 
+unsigned long code_value_ulong() { return strtoul(seen_pointer + 1, NULL, 10); }
+
 long code_value_long() { return strtol(seen_pointer + 1, NULL, 10); }
 
-int16_t code_value_short() { return (int16_t)strtol(seen_pointer + 1, NULL, 10); }
+int code_value_int() { return (int)strtol(seen_pointer + 1, NULL, 10); }
+
+uint16_t code_value_ushort() { return (uint16_t)strtoul(seen_pointer + 1, NULL, 10); }
+
+uint8_t code_value_byte() { return (uint8_t)(constrain(strtol(seen_pointer + 1, NULL, 10), 0, 255)); }
+
+bool code_value_bool() { return code_value_byte() > 0; }
+
+#if ENABLED(INCH_MODE_SUPPORT)
+  void set_input_linear_units(LinearUnit units) {
+    switch (units) {
+      case LINEARUNIT_INCH:
+        linear_unit_factor = 25.4;
+        break;
+      case LINEARUNIT_MM:
+      default:
+        linear_unit_factor = 1.0;
+        break;
+    }
+    volumetric_unit_factor = pow(linear_unit_factor, 3.0);
+  }
+
+  float axis_unit_factor(int axis) {
+    return (axis == E_AXIS && volumetric_enabled ? volumetric_unit_factor : linear_unit_factor);
+  }
+
+  float code_value_linear_units() {
+    return code_value_float() * linear_unit_factor;
+  }
+
+  float code_value_per_axis_unit(int axis) {
+    return code_value_float() / axis_unit_factor(axis);
+  }
+
+  float code_value_axis_units(int axis) {
+    return code_value_float() * axis_unit_factor(axis);
+  }
+#else
+  float code_value_linear_units() { return code_value_float(); }
+
+  float code_value_per_axis_unit(int axis) { return code_value_float(); }
+
+  float code_value_axis_units(int axis) { return code_value_float(); }
+#endif
+
+#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
+  void set_input_temp_units(TempUnit units) {
+    input_temp_units = units;
+  }
+  
+  float code_value_temp_abs() {
+    switch (input_temp_units) {
+      case TEMPUNIT_C:
+        return code_value_float();
+      case TEMPUNIT_F:
+        return (code_value_float() - 32) / 1.8;
+      case TEMPUNIT_K:
+        return code_value_float() - 272.15;
+      default:
+        return code_value_float();
+    }
+  }
+
+  float code_value_temp_diff() {
+    switch (input_temp_units) {
+      case TEMPUNIT_C:
+      case TEMPUNIT_K:
+        return code_value_float();
+      case TEMPUNIT_F:
+        return code_value_float() / 1.8;
+      default:
+        return code_value_float();
+    }
+  }
+#else
+  float code_value_temp_abs() { return code_value_float(); }
+  float code_value_temp_diff() { return code_value_float(); }
+#endif
+
+millis_t code_value_millis() {
+  return code_value_ulong();
+}
+
+millis_t code_value_millis_from_seconds() {
+  return code_value_float() * 1000;
+}
 
 bool code_seen(char code) {
   seen_pointer = strchr(current_command_args, code);
@@ -1194,7 +1292,7 @@ bool code_seen(char code) {
  */
 bool get_target_extruder_from_command(int code) {
   if (code_seen('T')) {
-    short t = code_value_short();
+    uint8_t t = code_value_byte();
     if (t >= EXTRUDERS) {
       SERIAL_ECHO_START;
       SERIAL_CHAR('M');
@@ -2429,12 +2527,12 @@ static void homeaxis(AxisEnum axis) {
 void gcode_get_destination() {
   for (int i = 0; i < NUM_AXIS; i++) {
     if (code_seen(axis_codes[i]))
-      destination[i] = code_value() + (axis_relative_modes[i] || relative_mode ? current_position[i] : 0);
+      destination[i] = code_value_axis_units(i) + (axis_relative_modes[i] || relative_mode ? current_position[i] : 0);
     else
       destination[i] = current_position[i];
   }
   if (code_seen('F')) {
-    float next_feedrate = code_value();
+    float next_feedrate = code_value_linear_units();
     if (next_feedrate > 0.0) feedrate = next_feedrate;
   }
 }
@@ -2526,8 +2624,8 @@ inline void gcode_G0_G1() {
 
       // Center of arc as offset from current_position
       float arc_offset[2] = {
-        code_seen('I') ? code_value() : 0,
-        code_seen('J') ? code_value() : 0
+        code_seen('I') ? code_value_axis_units(X_AXIS) : 0,
+        code_seen('J') ? code_value_axis_units(Y_AXIS) : 0
       };
 
       // Send an arc to the planner
@@ -2544,8 +2642,8 @@ inline void gcode_G0_G1() {
 inline void gcode_G4() {
   millis_t codenum = 0;
 
-  if (code_seen('P')) codenum = code_value_long(); // milliseconds to wait
-  if (code_seen('S')) codenum = code_value() * 1000UL; // seconds to wait
+  if (code_seen('P')) codenum = code_value_millis(); // milliseconds to wait
+  if (code_seen('S')) codenum = code_value_millis_from_seconds(); // seconds to wait
 
   stepper.synchronize();
   refresh_cmd_timeout();
@@ -2574,10 +2672,10 @@ inline void gcode_G4() {
       gcode_get_destination();
 
       float offset[] = {
-        code_seen('I') ? code_value() : 0.0,
-        code_seen('J') ? code_value() : 0.0,
-        code_seen('P') ? code_value() : 0.0,
-        code_seen('Q') ? code_value() : 0.0
+        code_seen('I') ? code_value_axis_units(X_AXIS) : 0.0,
+        code_seen('J') ? code_value_axis_units(Y_AXIS) : 0.0,
+        code_seen('P') ? code_value_axis_units(X_AXIS) : 0.0,
+        code_seen('Q') ? code_value_axis_units(Y_AXIS) : 0.0
       };
 
       plan_cubic_move(offset);
@@ -2595,7 +2693,7 @@ inline void gcode_G4() {
   inline void gcode_G10_G11(bool doRetract=false) {
     #if EXTRUDERS > 1
       if (doRetract) {
-        retracted_swap[active_extruder] = (code_seen('S') && code_value_short() == 1); // checks for swap retract argument
+        retracted_swap[active_extruder] = (code_seen('S') && code_value_bool()); // checks for swap retract argument
       }
     #endif
     retract(doRetract
@@ -2607,6 +2705,22 @@ inline void gcode_G4() {
 
 #endif //FWRETRACT
 
+#if ENABLED(INCH_MODE_SUPPORT)
+  /**
+   * G20: Set input mode to inches
+   */
+  inline void gcode_G20() {
+    set_input_linear_units(LINEARUNIT_INCH);
+  }
+
+  /**
+   * G21: Set input mode to millimeters
+   */
+  inline void gcode_G21() {
+    set_input_linear_units(LINEARUNIT_MM);
+  }
+#endif
+
 /**
  * G28: Home all axes according to settings
  *
@@ -3047,7 +3161,7 @@ inline void gcode_G28() {
   inline void gcode_G29() {
 
     static int probe_point = -1;
-    MeshLevelingState state = code_seen('S') ? (MeshLevelingState)code_value_short() : MeshReport;
+    MeshLevelingState state = code_seen('S') ? (MeshLevelingState)code_value_byte() : MeshReport;
     if (state < 0 || state > 5) {
       SERIAL_PROTOCOLLNPGM("S out of range (0-5).");
       return;
@@ -3132,7 +3246,7 @@ inline void gcode_G28() {
 
       case MeshSet:
         if (code_seen('X')) {
-          px = code_value_long() - 1;
+          px = code_value_int() - 1;
           if (px < 0 || px >= MESH_NUM_X_POINTS) {
             SERIAL_PROTOCOLPGM("X out of range (1-" STRINGIFY(MESH_NUM_X_POINTS) ").\n");
             return;
@@ -3143,7 +3257,7 @@ inline void gcode_G28() {
           return;
         }
         if (code_seen('Y')) {
-          py = code_value_long() - 1;
+          py = code_value_int() - 1;
           if (py < 0 || py >= MESH_NUM_Y_POINTS) {
             SERIAL_PROTOCOLPGM("Y out of range (1-" STRINGIFY(MESH_NUM_Y_POINTS) ").\n");
             return;
@@ -3154,7 +3268,7 @@ inline void gcode_G28() {
           return;
         }
         if (code_seen('Z')) {
-          z = code_value();
+          z = code_value_axis_units(Z_AXIS);
         }
         else {
           SERIAL_PROTOCOLPGM("Z not entered.\n");
@@ -3165,7 +3279,7 @@ inline void gcode_G28() {
 
       case MeshSetZOffset:
         if (code_seen('Z')) {
-          z = code_value();
+          z = code_value_axis_units(Z_AXIS);
         }
         else {
           SERIAL_PROTOCOLPGM("Z not entered.\n");
@@ -3251,7 +3365,7 @@ inline void gcode_G28() {
       return;
     }
 
-    int verbose_level = code_seen('V') ? code_value_short() : 1;
+    int verbose_level = code_seen('V') ? code_value_int() : 1;
     if (verbose_level < 0 || verbose_level > 4) {
       SERIAL_ECHOLNPGM("?(V)erbose Level is implausible (0-4).");
       return;
@@ -3274,19 +3388,19 @@ inline void gcode_G28() {
       int auto_bed_leveling_grid_points = AUTO_BED_LEVELING_GRID_POINTS;
 
       #if DISABLED(DELTA)
-        if (code_seen('P')) auto_bed_leveling_grid_points = code_value_short();
+        if (code_seen('P')) auto_bed_leveling_grid_points = code_value_int();
         if (auto_bed_leveling_grid_points < 2) {
           SERIAL_PROTOCOLPGM("?Number of probed (P)oints is implausible (2 minimum).\n");
           return;
         }
       #endif
 
-      xy_travel_speed = code_seen('S') ? code_value_short() : XY_TRAVEL_SPEED;
+      xy_travel_speed = code_seen('S') ? (int)code_value_linear_units() : XY_TRAVEL_SPEED;
 
-      int left_probe_bed_position = code_seen('L') ? code_value_short() : LEFT_PROBE_BED_POSITION,
-          right_probe_bed_position = code_seen('R') ? code_value_short() : RIGHT_PROBE_BED_POSITION,
-          front_probe_bed_position = code_seen('F') ? code_value_short() : FRONT_PROBE_BED_POSITION,
-          back_probe_bed_position = code_seen('B') ? code_value_short() : BACK_PROBE_BED_POSITION;
+      int left_probe_bed_position = code_seen('L') ? (int)code_value_axis_units(X_AXIS) : LEFT_PROBE_BED_POSITION,
+          right_probe_bed_position = code_seen('R') ? (int)code_value_axis_units(X_AXIS) : RIGHT_PROBE_BED_POSITION,
+          front_probe_bed_position = code_seen('F') ? (int)code_value_axis_units(Y_AXIS) : FRONT_PROBE_BED_POSITION,
+          back_probe_bed_position = code_seen('B') ? (int)code_value_axis_units(Y_AXIS) : BACK_PROBE_BED_POSITION;
 
       bool left_out_l = left_probe_bed_position < MIN_PROBE_X,
            left_out = left_out_l || left_probe_bed_position > right_probe_bed_position - (MIN_PROBE_EDGE),
@@ -3377,7 +3491,7 @@ inline void gcode_G28() {
         delta_grid_spacing[0] = xGridSpacing;
         delta_grid_spacing[1] = yGridSpacing;
         float zoffset = zprobe_zoffset;
-        if (code_seen(axis_codes[Z_AXIS])) zoffset += code_value();
+        if (code_seen(axis_codes[Z_AXIS])) zoffset += code_value_axis_units(Z_AXIS);
       #else // !DELTA
         /**
          * solve the plane equation ax + by + d = z
@@ -3783,7 +3897,7 @@ inline void gcode_G92() {
   for (int i = 0; i < NUM_AXIS; i++) {
     if (code_seen(axis_codes[i])) {
       float p = current_position[i],
-            v = code_value();
+            v = code_value_axis_units(i);
 
       current_position[i] = v;
 
@@ -3821,11 +3935,11 @@ inline void gcode_G92() {
     millis_t codenum = 0;
     bool hasP = false, hasS = false;
     if (code_seen('P')) {
-      codenum = code_value_short(); // milliseconds to wait
+      codenum = code_value_millis(); // milliseconds to wait
       hasP = codenum > 0;
     }
     if (code_seen('S')) {
-      codenum = code_value() * 1000UL; // seconds to wait
+      codenum = code_value_millis_from_seconds(); // seconds to wait
       hasS = codenum > 0;
     }
 
@@ -4040,10 +4154,10 @@ inline void gcode_M31() {
  */
 inline void gcode_M42() {
   if (code_seen('S')) {
-    int pin_status = code_value_short();
+    int pin_status = code_value_int();
     if (pin_status < 0 || pin_status > 255) return;
 
-    int pin_number = code_seen('P') ? code_value_short() : LED_PIN;
+    int pin_number = code_seen('P') ? code_value_int() : LED_PIN;
     if (pin_number < 0) return;
 
     for (uint8_t i = 0; i < COUNT(sensitive_pins); i++)
@@ -4113,7 +4227,7 @@ inline void gcode_M42() {
     int8_t verbose_level = 1, n_samples = 10, n_legs = 0, schizoid_flag = 0;
 
     if (code_seen('V')) {
-      verbose_level = code_value_short();
+      verbose_level = code_value_byte();
       if (verbose_level < 0 || verbose_level > 4) {
         SERIAL_PROTOCOLPGM("?Verbose Level not plausible (0-4).\n");
         return;
@@ -4124,7 +4238,7 @@ inline void gcode_M42() {
       SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test\n");
 
     if (code_seen('P')) {
-      n_samples = code_value_short();
+      n_samples = code_value_byte();
       if (n_samples < 4 || n_samples > 50) {
         SERIAL_PROTOCOLPGM("?Sample size not plausible (4-50).\n");
         return;
@@ -4140,7 +4254,7 @@ inline void gcode_M42() {
     bool deploy_probe_for_each_reading = code_seen('E');
 
     if (code_seen('X')) {
-      X_probe_location = code_value();
+      X_probe_location = code_value_axis_units(X_AXIS);
       #if DISABLED(DELTA)
         if (X_probe_location < MIN_PROBE_X || X_probe_location > MAX_PROBE_X) {
           out_of_range_error(PSTR("X"));
@@ -4150,7 +4264,7 @@ inline void gcode_M42() {
     }
 
     if (code_seen('Y')) {
-      Y_probe_location = code_value();
+      Y_probe_location = code_value_axis_units(Y_AXIS);
       #if DISABLED(DELTA)
         if (Y_probe_location < MIN_PROBE_Y || Y_probe_location > MAX_PROBE_Y) {
           out_of_range_error(PSTR("Y"));
@@ -4169,7 +4283,7 @@ inline void gcode_M42() {
     bool seen_L = code_seen('L');
 
     if (seen_L) {
-      n_legs = code_value_short();
+      n_legs = code_value_byte();
       if (n_legs < 0 || n_legs > 15) {
         SERIAL_PROTOCOLPGM("?Number of legs in movement not plausible (0-15).\n");
         return;
@@ -4387,7 +4501,7 @@ inline void gcode_M77() { print_job_timer.stop(); }
    */
   inline void gcode_M78() {
     // "M78 S78" will reset the statistics
-    if (code_seen('S') && code_value_short() == 78)
+    if (code_seen('S') && code_value_int() == 78)
       print_job_timer.initStats();
     else print_job_timer.showStats();
   }
@@ -4405,7 +4519,7 @@ inline void gcode_M104() {
   #endif
 
   if (code_seen('S')) {
-    float temp = code_value();
+    float temp = code_value_temp_abs();
     thermalManager.setTargetHotend(temp, target_extruder);
     #if ENABLED(DUAL_X_CARRIAGE)
       if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0)
@@ -4533,8 +4647,8 @@ inline void gcode_M105() {
    *  P<index> Fan index, if more than one fan
    */
   inline void gcode_M106() {
-    uint16_t s = code_seen('S') ? code_value_short() : 255,
-             p = code_seen('P') ? code_value_short() : 0;
+    uint16_t s = code_seen('S') ? code_value_ushort() : 255,
+             p = code_seen('P') ? code_value_ushort() : 0;
     NOMORE(s, 255);
     if (p < FAN_COUNT) fanSpeeds[p] = s;
   }
@@ -4543,7 +4657,7 @@ inline void gcode_M105() {
    * M107: Fan Off
    */
   inline void gcode_M107() {
-    uint16_t p = code_seen('P') ? code_value_short() : 0;
+    uint16_t p = code_seen('P') ? code_value_ushort() : 0;
     if (p < FAN_COUNT) fanSpeeds[p] = 0;
   }
 
@@ -4564,7 +4678,7 @@ inline void gcode_M109() {
 
   bool no_wait_for_cooling = code_seen('S');
   if (no_wait_for_cooling || code_seen('R')) {
-    float temp = code_value();
+    float temp = code_value_temp_abs();
     thermalManager.setTargetHotend(temp, target_extruder);
     #if ENABLED(DUAL_X_CARRIAGE)
       if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0)
@@ -4681,7 +4795,7 @@ inline void gcode_M109() {
 
     LCD_MESSAGEPGM(MSG_BED_HEATING);
     bool no_wait_for_cooling = code_seen('S');
-    if (no_wait_for_cooling || code_seen('R')) thermalManager.setTargetBed(code_value());
+    if (no_wait_for_cooling || code_seen('R')) thermalManager.setTargetBed(code_value_temp_abs());
 
     #if TEMP_BED_RESIDENCY_TIME > 0
       millis_t residency_start_ms = 0;
@@ -4767,7 +4881,7 @@ inline void gcode_M110() {
  * M111: Set the debug level
  */
 inline void gcode_M111() {
-  marlin_debug_flags = code_seen('S') ? code_value_short() : DEBUG_NONE;
+  marlin_debug_flags = code_seen('S') ? code_value_byte() : DEBUG_NONE;
 
   const static char str_debug_1[] PROGMEM = MSG_DEBUG_ECHO;
   const static char str_debug_2[] PROGMEM = MSG_DEBUG_INFO;
@@ -4816,7 +4930,7 @@ inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }
    */
   inline void gcode_M113() {
     if (code_seen('S')) {
-      host_keepalive_interval = (uint8_t)code_value_short();
+      host_keepalive_interval = code_value_byte();
       NOMORE(host_keepalive_interval, 60);
     }
     else {
@@ -4834,7 +4948,7 @@ inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }
     /**
      * M126: Heater 1 valve open
      */
-    inline void gcode_M126() { baricuda_valve_pressure = code_seen('S') ? constrain(code_value(), 0, 255) : 255; }
+    inline void gcode_M126() { baricuda_valve_pressure = code_seen('S') ? code_value_byte() : 255; }
     /**
      * M127: Heater 1 valve close
      */
@@ -4845,7 +4959,7 @@ inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }
     /**
      * M128: Heater 2 valve open
      */
-    inline void gcode_M128() { baricuda_e_to_p_pressure = code_seen('S') ? constrain(code_value(), 0, 255) : 255; }
+    inline void gcode_M128() { baricuda_e_to_p_pressure = code_seen('S') ? code_value_byte() : 255; }
     /**
      * M129: Heater 2 valve close
      */
@@ -4859,7 +4973,7 @@ inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }
  */
 inline void gcode_M140() {
   if (DEBUGGING(DRYRUN)) return;
-  if (code_seen('S')) thermalManager.setTargetBed(code_value());
+  if (code_seen('S')) thermalManager.setTargetBed(code_value_temp_abs());
 }
 
 #if ENABLED(ULTIPANEL)
@@ -4872,7 +4986,7 @@ inline void gcode_M140() {
    *   F<fan speed>
    */
   inline void gcode_M145() {
-    int8_t material = code_seen('S') ? code_value_short() : 0;
+    int8_t material = code_seen('S') ? (int8_t)code_value_int() : 0;
     if (material < 0 || material > 1) {
       SERIAL_ERROR_START;
       SERIAL_ERRORLNPGM(MSG_ERR_MATERIAL_INDEX);
@@ -4882,32 +4996,32 @@ inline void gcode_M140() {
       switch (material) {
         case 0:
           if (code_seen('H')) {
-            v = code_value_short();
+            v = code_value_int();
             plaPreheatHotendTemp = constrain(v, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - 15);
           }
           if (code_seen('F')) {
-            v = code_value_short();
+            v = code_value_int();
             plaPreheatFanSpeed = constrain(v, 0, 255);
           }
           #if TEMP_SENSOR_BED != 0
             if (code_seen('B')) {
-              v = code_value_short();
+              v = code_value_int();
               plaPreheatHPBTemp = constrain(v, BED_MINTEMP, BED_MAXTEMP - 15);
             }
           #endif
           break;
         case 1:
           if (code_seen('H')) {
-            v = code_value_short();
+            v = code_value_int();
             absPreheatHotendTemp = constrain(v, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - 15);
           }
           if (code_seen('F')) {
-            v = code_value_short();
+            v = code_value_int();
             absPreheatFanSpeed = constrain(v, 0, 255);
           }
           #if TEMP_SENSOR_BED != 0
             if (code_seen('B')) {
-              v = code_value_short();
+              v = code_value_int();
               absPreheatHPBTemp = constrain(v, BED_MINTEMP, BED_MAXTEMP - 15);
             }
           #endif
@@ -4918,6 +5032,21 @@ inline void gcode_M140() {
 
 #endif
 
+#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
+  /**
+   * M149: Set temperature units
+   */
+  inline void gcode_M149() {
+    if (code_seen('C')) {
+      set_input_temp_units(TEMPUNIT_C);
+    } else if (code_seen('K')) {
+      set_input_temp_units(TEMPUNIT_K);
+    } else if (code_seen('F')) {
+      set_input_temp_units(TEMPUNIT_F);
+    }
+  }
+#endif
+
 #if HAS_POWER_SWITCH
 
   /**
@@ -4991,7 +5120,7 @@ inline void gcode_M83() { axis_relative_modes[E_AXIS] = true; }
  */
 inline void gcode_M18_M84() {
   if (code_seen('S')) {
-    stepper_inactive_time = code_value() * 1000UL;
+    stepper_inactive_time = code_value_millis_from_seconds();
   }
   else {
     bool all_axis = !((code_seen(axis_codes[X_AXIS])) || (code_seen(axis_codes[Y_AXIS])) || (code_seen(axis_codes[Z_AXIS])) || (code_seen(axis_codes[E_AXIS])));
@@ -5019,7 +5148,7 @@ inline void gcode_M18_M84() {
  * M85: Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
  */
 inline void gcode_M85() {
-  if (code_seen('S')) max_inactive_time = code_value() * 1000UL;
+  if (code_seen('S')) max_inactive_time = code_value_millis_from_seconds();
 }
 
 /**
@@ -5030,7 +5159,7 @@ inline void gcode_M92() {
   for (int8_t i = 0; i < NUM_AXIS; i++) {
     if (code_seen(axis_codes[i])) {
       if (i == E_AXIS) {
-        float value = code_value();
+        float value = code_value_per_axis_unit(i);
         if (value < 20.0) {
           float factor = planner.axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
           planner.max_e_jerk *= factor;
@@ -5040,7 +5169,7 @@ inline void gcode_M92() {
         planner.axis_steps_per_unit[i] = value;
       }
       else {
-        planner.axis_steps_per_unit[i] = code_value();
+        planner.axis_steps_per_unit[i] = code_value_per_axis_unit(i);
       }
     }
   }
@@ -5123,9 +5252,9 @@ inline void gcode_M121() { endstops.enable_globally(false); }
    */
   inline void gcode_M150() {
     SendColors(
-      code_seen('R') ? (byte)code_value_short() : 0,
-      code_seen('U') ? (byte)code_value_short() : 0,
-      code_seen('B') ? (byte)code_value_short() : 0
+      code_seen('R') ? code_value_byte() : 0,
+      code_seen('U') ? code_value_byte() : 0,
+      code_seen('B') ? code_value_byte() : 0
     );
   }
 
@@ -5152,11 +5281,11 @@ inline void gcode_M121() { endstops.enable_globally(false); }
   inline void gcode_M155() {
     // Set the target address
     if (code_seen('A'))
-      i2c.address((uint8_t) code_value_short());
+      i2c.address(code_value_byte());
 
     // Add a new byte to the buffer
     else if (code_seen('B'))
-      i2c.addbyte((int) code_value_short());
+      i2c.addbyte(code_value_int());
 
     // Flush the buffer to the bus
     else if (code_seen('S')) i2c.send();
@@ -5171,8 +5300,8 @@ inline void gcode_M121() { endstops.enable_globally(false); }
    * Usage: M156 A<slave device address base 10> B<number of bytes>
    */
   inline void gcode_M156() {
-    uint8_t addr = code_seen('A') ? code_value_short() : 0;
-    int bytes    = code_seen('B') ? code_value_short() : 1;
+    uint8_t addr = code_seen('A') ? code_value_byte() : 0;
+    int bytes    = code_seen('B') ? code_value_int() : 1;
 
     if (addr && bytes > 0 && bytes <= 32) {
       i2c.address(addr);
@@ -5187,17 +5316,17 @@ inline void gcode_M121() { endstops.enable_globally(false); }
 #endif //EXPERIMENTAL_I2CBUS
 
 /**
- * M200: Set filament diameter and set E axis units to cubic millimeters
+ * M200: Set filament diameter and set E axis units to cubic units
  *
  *    T<extruder> - Optional extruder number. Current extruder if omitted.
- *    D<mm> - Diameter of the filament. Use "D0" to set units back to millimeters.
+ *    D<mm> - Diameter of the filament. Use "D0" to switch back to linear units on the E axis.
  */
 inline void gcode_M200() {
 
   if (get_target_extruder_from_command(200)) return;
 
   if (code_seen('D')) {
-    float diameter = code_value();
+    float diameter = code_value_linear_units();
     // 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
@@ -5222,7 +5351,7 @@ inline void gcode_M200() {
 inline void gcode_M201() {
   for (int8_t i = 0; i < NUM_AXIS; i++) {
     if (code_seen(axis_codes[i])) {
-      planner.max_acceleration_units_per_sq_second[i] = code_value();
+      planner.max_acceleration_units_per_sq_second[i] = code_value_axis_units(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)
@@ -5232,7 +5361,7 @@ inline void gcode_M201() {
 #if 0 // Not used for Sprinter/grbl gen6
   inline void gcode_M202() {
     for (int8_t i = 0; i < NUM_AXIS; i++) {
-      if (code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * planner.axis_steps_per_unit[i];
+      if (code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value_axis_units(i) * planner.axis_steps_per_unit[i];
     }
   }
 #endif
@@ -5244,7 +5373,7 @@ inline void gcode_M201() {
 inline void gcode_M203() {
   for (int8_t i = 0; i < NUM_AXIS; i++) {
     if (code_seen(axis_codes[i])) {
-      planner.max_feedrate[i] = code_value();
+      planner.max_feedrate[i] = code_value_axis_units(i);
     }
   }
 }
@@ -5260,22 +5389,22 @@ inline void gcode_M203() {
  */
 inline void gcode_M204() {
   if (code_seen('S')) {  // Kept for legacy compatibility. Should NOT BE USED for new developments.
-    planner.travel_acceleration = planner.acceleration = code_value();
+    planner.travel_acceleration = planner.acceleration = code_value_linear_units();
     SERIAL_ECHOPAIR("Setting Print and Travel Acceleration: ", planner.acceleration);
     SERIAL_EOL;
   }
   if (code_seen('P')) {
-    planner.acceleration = code_value();
+    planner.acceleration = code_value_linear_units();
     SERIAL_ECHOPAIR("Setting Print Acceleration: ", planner.acceleration);
     SERIAL_EOL;
   }
   if (code_seen('R')) {
-    planner.retract_acceleration = code_value();
+    planner.retract_acceleration = code_value_linear_units();
     SERIAL_ECHOPAIR("Setting Retract Acceleration: ", planner.retract_acceleration);
     SERIAL_EOL;
   }
   if (code_seen('T')) {
-    planner.travel_acceleration = code_value();
+    planner.travel_acceleration = code_value_linear_units();
     SERIAL_ECHOPAIR("Setting Travel Acceleration: ", planner.travel_acceleration);
     SERIAL_EOL;
   }
@@ -5292,12 +5421,12 @@ inline void gcode_M204() {
  *    E = Max E Jerk (mm/s/s)
  */
 inline void gcode_M205() {
-  if (code_seen('S')) planner.min_feedrate = code_value();
-  if (code_seen('T')) planner.min_travel_feedrate = code_value();
-  if (code_seen('B')) planner.min_segment_time = code_value();
-  if (code_seen('X')) planner.max_xy_jerk = code_value();
-  if (code_seen('Z')) planner.max_z_jerk = code_value();
-  if (code_seen('E')) planner.max_e_jerk = code_value();
+  if (code_seen('S')) planner.min_feedrate = code_value_linear_units();
+  if (code_seen('T')) planner.min_travel_feedrate = code_value_linear_units();
+  if (code_seen('B')) planner.min_segment_time = code_value_millis();
+  if (code_seen('X')) planner.max_xy_jerk = code_value_linear_units();
+  if (code_seen('Z')) planner.max_z_jerk = code_value_axis_units(Z_AXIS);
+  if (code_seen('E')) planner.max_e_jerk = code_value_axis_units(E_AXIS);
 }
 
 /**
@@ -5306,11 +5435,11 @@ inline void gcode_M205() {
 inline void gcode_M206() {
   for (int8_t i = X_AXIS; i <= Z_AXIS; i++)
     if (code_seen(axis_codes[i]))
-      set_home_offset((AxisEnum)i, code_value());
+      set_home_offset((AxisEnum)i, code_value_axis_units(i));
 
   #if ENABLED(SCARA)
-    if (code_seen('T')) set_home_offset(X_AXIS, code_value()); // Theta
-    if (code_seen('P')) set_home_offset(Y_AXIS, code_value()); // Psi
+    if (code_seen('T')) set_home_offset(X_AXIS, code_value_axis_units(X_AXIS)); // Theta
+    if (code_seen('P')) set_home_offset(Y_AXIS, code_value_axis_units(Y_AXIS)); // Psi
   #endif
 
   sync_plan_position();
@@ -5329,12 +5458,12 @@ inline void gcode_M206() {
    *    C = Gamma (Tower 3) diagonal rod trim
    */
   inline void gcode_M665() {
-    if (code_seen('L')) delta_diagonal_rod = code_value();
-    if (code_seen('R')) delta_radius = code_value();
-    if (code_seen('S')) delta_segments_per_second = code_value();
-    if (code_seen('A')) delta_diagonal_rod_trim_tower_1 = code_value();
-    if (code_seen('B')) delta_diagonal_rod_trim_tower_2 = code_value();
-    if (code_seen('C')) delta_diagonal_rod_trim_tower_3 = code_value();
+    if (code_seen('L')) delta_diagonal_rod = code_value_linear_units();
+    if (code_seen('R')) delta_radius = code_value_linear_units();
+    if (code_seen('S')) delta_segments_per_second = code_value_float();
+    if (code_seen('A')) delta_diagonal_rod_trim_tower_1 = code_value_linear_units();
+    if (code_seen('B')) delta_diagonal_rod_trim_tower_2 = code_value_linear_units();
+    if (code_seen('C')) delta_diagonal_rod_trim_tower_3 = code_value_linear_units();
     recalc_delta_settings(delta_radius, delta_diagonal_rod);
   }
   /**
@@ -5348,7 +5477,7 @@ inline void gcode_M206() {
     #endif
     for (int8_t i = X_AXIS; i <= Z_AXIS; i++) {
       if (code_seen(axis_codes[i])) {
-        endstop_adj[i] = code_value();
+        endstop_adj[i] = code_value_axis_units(i);
         #if ENABLED(DEBUG_LEVELING_FEATURE)
           if (DEBUGGING(LEVELING)) {
             SERIAL_ECHOPGM("endstop_adj[");
@@ -5372,7 +5501,7 @@ inline void gcode_M206() {
    * M666: For Z Dual Endstop setup, set z axis offset to the z2 axis.
    */
   inline void gcode_M666() {
-    if (code_seen('Z')) z_endstop_adj = code_value();
+    if (code_seen('Z')) z_endstop_adj = code_value_axis_units(Z_AXIS);
     SERIAL_ECHOPAIR("Z Endstop Adjustment set to (mm):", z_endstop_adj);
     SERIAL_EOL;
   }
@@ -5390,11 +5519,11 @@ inline void gcode_M206() {
    *   Z[mm]     retract_zlift
    */
   inline void gcode_M207() {
-    if (code_seen('S')) retract_length = code_value();
-    if (code_seen('F')) retract_feedrate = code_value() / 60;
-    if (code_seen('Z')) retract_zlift = code_value();
+    if (code_seen('S')) retract_length = code_value_axis_units(E_AXIS);
+    if (code_seen('F')) retract_feedrate = code_value_axis_units(E_AXIS) / 60;
+    if (code_seen('Z')) retract_zlift = code_value_axis_units(Z_AXIS);
     #if EXTRUDERS > 1
-      if (code_seen('W')) retract_length_swap = code_value();
+      if (code_seen('W')) retract_length_swap = code_value_axis_units(E_AXIS);
     #endif
   }
 
@@ -5406,10 +5535,10 @@ inline void gcode_M206() {
    *   F[mm/min] retract_recover_feedrate
    */
   inline void gcode_M208() {
-    if (code_seen('S')) retract_recover_length = code_value();
-    if (code_seen('F')) retract_recover_feedrate = code_value() / 60;
+    if (code_seen('S')) retract_recover_length = code_value_axis_units(E_AXIS);
+    if (code_seen('F')) retract_recover_feedrate = code_value_axis_units(E_AXIS) / 60;
     #if EXTRUDERS > 1
-      if (code_seen('W')) retract_recover_length_swap = code_value();
+      if (code_seen('W')) retract_recover_length_swap = code_value_axis_units(E_AXIS);
     #endif
   }
 
@@ -5419,7 +5548,7 @@ inline void gcode_M206() {
    */
   inline void gcode_M209() {
     if (code_seen('S')) {
-      int t = code_value_short();
+      int t = code_value_int();
       switch (t) {
         case 0:
           autoretract_enabled = false;
@@ -5450,11 +5579,11 @@ inline void gcode_M206() {
   inline void gcode_M218() {
     if (get_target_extruder_from_command(218)) return;
 
-    if (code_seen('X')) hotend_offset[X_AXIS][target_extruder] = code_value();
-    if (code_seen('Y')) hotend_offset[Y_AXIS][target_extruder] = code_value();
+    if (code_seen('X')) hotend_offset[X_AXIS][target_extruder] = code_value_axis_units(X_AXIS);
+    if (code_seen('Y')) hotend_offset[Y_AXIS][target_extruder] = code_value_axis_units(Y_AXIS);
 
     #if ENABLED(DUAL_X_CARRIAGE)
-      if (code_seen('Z')) hotend_offset[Z_AXIS][target_extruder] = code_value();
+      if (code_seen('Z')) hotend_offset[Z_AXIS][target_extruder] = code_value_axis_units(Z_AXIS);
     #endif
 
     SERIAL_ECHO_START;
@@ -5478,7 +5607,7 @@ inline void gcode_M206() {
  * M220: Set speed percentage factor, aka "Feed Rate" (M220 S95)
  */
 inline void gcode_M220() {
-  if (code_seen('S')) feedrate_multiplier = code_value();
+  if (code_seen('S')) feedrate_multiplier = code_value_int();
 }
 
 /**
@@ -5486,7 +5615,7 @@ inline void gcode_M220() {
  */
 inline void gcode_M221() {
   if (code_seen('S')) {
-    int sval = code_value();
+    int sval = code_value_int();
     if (get_target_extruder_from_command(221)) return;
     extruder_multiplier[target_extruder] = sval;
   }
@@ -5497,9 +5626,9 @@ inline void gcode_M221() {
  */
 inline void gcode_M226() {
   if (code_seen('P')) {
-    int pin_number = code_value();
+    int pin_number = code_value_int();
 
-    int pin_state = code_seen('S') ? code_value() : -1; // required pin state - default is inverted
+    int pin_state = code_seen('S') ? code_value_int() : -1; // required pin state - default is inverted
 
     if (pin_state >= -1 && pin_state <= 1) {
 
@@ -5544,10 +5673,10 @@ inline void gcode_M226() {
    * M280: Get or set servo position. P<index> S<angle>
    */
   inline void gcode_M280() {
-    int servo_index = code_seen('P') ? code_value_short() : -1;
+    int servo_index = code_seen('P') ? code_value_int() : -1;
     int servo_position = 0;
     if (code_seen('S')) {
-      servo_position = code_value_short();
+      servo_position = code_value_int();
       if (servo_index >= 0 && servo_index < NUM_SERVOS)
         servo[servo_index].move(servo_position);
       else {
@@ -5574,8 +5703,8 @@ inline void gcode_M226() {
    * M300: Play beep sound S<frequency Hz> P<duration ms>
    */
   inline void gcode_M300() {
-    uint16_t beepS = code_seen('S') ? code_value_short() : 110;
-    uint32_t beepP = code_seen('P') ? code_value_long() : 1000;
+    uint16_t beepS = code_seen('S') ? code_value_ushort() : 110;
+    uint32_t beepP = code_seen('P') ? code_value_ulong() : 1000;
     if (beepP > 5000) beepP = 5000; // limit to 5 seconds
     buzz(beepP, beepS);
   }
@@ -5600,15 +5729,15 @@ inline void gcode_M226() {
 
     // multi-extruder PID patch: M301 updates or prints a single extruder's PID values
     // default behaviour (omitting E parameter) is to update for extruder 0 only
-    int e = code_seen('E') ? code_value() : 0; // extruder being updated
+    int e = code_seen('E') ? code_value_int() : 0; // extruder being updated
 
     if (e < HOTENDS) { // catch bad input value
-      if (code_seen('P')) PID_PARAM(Kp, e) = code_value();
-      if (code_seen('I')) PID_PARAM(Ki, e) = scalePID_i(code_value());
-      if (code_seen('D')) PID_PARAM(Kd, e) = scalePID_d(code_value());
+      if (code_seen('P')) PID_PARAM(Kp, e) = code_value_float();
+      if (code_seen('I')) PID_PARAM(Ki, e) = scalePID_i(code_value_float());
+      if (code_seen('D')) PID_PARAM(Kd, e) = scalePID_d(code_value_float());
       #if ENABLED(PID_ADD_EXTRUSION_RATE)
-        if (code_seen('C')) PID_PARAM(Kc, e) = code_value();
-        if (code_seen('L')) lpq_len = code_value();
+        if (code_seen('C')) PID_PARAM(Kc, e) = code_value_float();
+        if (code_seen('L')) lpq_len = code_value_float();
         NOMORE(lpq_len, LPQ_MAX_LEN);
       #endif
 
@@ -5642,9 +5771,9 @@ inline void gcode_M226() {
 #if ENABLED(PIDTEMPBED)
 
   inline void gcode_M304() {
-    if (code_seen('P')) thermalManager.bedKp = code_value();
-    if (code_seen('I')) thermalManager.bedKi = scalePID_i(code_value());
-    if (code_seen('D')) thermalManager.bedKd = scalePID_d(code_value());
+    if (code_seen('P')) thermalManager.bedKp = code_value_float();
+    if (code_seen('I')) thermalManager.bedKi = scalePID_i(code_value_float());
+    if (code_seen('D')) thermalManager.bedKd = scalePID_d(code_value_float());
 
     thermalManager.updatePID();
 
@@ -5701,7 +5830,7 @@ inline void gcode_M226() {
    * M250: Read and optionally set the LCD contrast
    */
   inline void gcode_M250() {
-    if (code_seen('C')) set_lcd_contrast(code_value_short());
+    if (code_seen('C')) set_lcd_contrast(code_value_int());
     SERIAL_PROTOCOLPGM("lcd contrast value: ");
     SERIAL_PROTOCOL(lcd_contrast);
     SERIAL_EOL;
@@ -5715,7 +5844,7 @@ inline void gcode_M226() {
    * M302: Allow cold extrudes, or set the minimum extrude S<temperature>.
    */
   inline void gcode_M302() {
-    thermalManager.extrude_min_temp = code_seen('S') ? code_value() : 0;
+    thermalManager.extrude_min_temp = code_seen('S') ? code_value_temp_abs() : 0;
   }
 
 #endif // PREVENT_DANGEROUS_EXTRUDE
@@ -5730,11 +5859,11 @@ inline void gcode_M226() {
  */
 inline void gcode_M303() {
   #if HAS_PID_HEATING
-    int e = code_seen('E') ? code_value_short() : 0;
-    int c = code_seen('C') ? code_value_short() : 5;
-    bool u = code_seen('U') && code_value_short() != 0;
+    int e = code_seen('E') ? code_value_int() : 0;
+    int c = code_seen('C') ? code_value_int() : 5;
+    bool u = code_seen('U') && code_value_bool();
 
-    float temp = code_seen('S') ? code_value() : (e < 0 ? 70.0 : 150.0);
+    float temp = code_seen('S') ? code_value_temp_abs() : (e < 0 ? 70.0 : 150.0);
 
     if (e >= 0 && e < HOTENDS)
       target_extruder = e;
@@ -5814,7 +5943,7 @@ inline void gcode_M303() {
   inline void gcode_M365() {
     for (int8_t i = X_AXIS; i <= Z_AXIS; i++) {
       if (code_seen(axis_codes[i])) {
-        axis_scaling[i] = code_value();
+        axis_scaling[i] = code_value_float();
       }
     }
   }
@@ -5907,7 +6036,7 @@ inline void gcode_M400() { stepper.synchronize(); }
    */
   inline void gcode_M404() {
     if (code_seen('W')) {
-      filament_width_nominal = code_value();
+      filament_width_nominal = code_value_linear_units();
     }
     else {
       SERIAL_PROTOCOLPGM("Filament dia (nominal mm):");
@@ -5919,7 +6048,9 @@ inline void gcode_M400() { stepper.synchronize(); }
    * M405: Turn on filament sensor for control
    */
   inline void gcode_M405() {
-    if (code_seen('D')) meas_delay_cm = code_value();
+    // This is technically a linear measurement, but since it's quantized to centimeters and is a different unit than
+    // everything else, it uses code_value_int() instead of code_value_linear_units().
+    if (code_seen('D')) meas_delay_cm = code_value_int();
     NOMORE(meas_delay_cm, MAX_MEASUREMENT_DELAY);
 
     if (filwidth_delay_index2 == -1) { // Initialize the ring buffer if not done since startup
@@ -5990,7 +6121,7 @@ inline void gcode_M410() {
   /**
    * M420: Enable/Disable Mesh Bed Leveling
    */
-  inline void gcode_M420() { if (code_seen('S') && code_has_value()) mbl.set_has_mesh(!!code_value_short()); }
+  inline void gcode_M420() { if (code_seen('S') && code_has_value()) mbl.set_has_mesh(code_value_bool()); }
 
   /**
    * M421: Set a single Mesh Bed Leveling Z coordinate
@@ -6000,11 +6131,11 @@ inline void gcode_M410() {
     int8_t px, py;
     float z = 0;
     bool hasX, hasY, hasZ, hasI, hasJ;
-    if ((hasX = code_seen('X'))) px = mbl.probe_index_x(code_value());
-    if ((hasY = code_seen('Y'))) py = mbl.probe_index_y(code_value());
-    if ((hasI = code_seen('I'))) px = code_value();
-    if ((hasJ = code_seen('J'))) py = code_value();
-    if ((hasZ = code_seen('Z'))) z = code_value();
+    if ((hasX = code_seen('X'))) px = mbl.probe_index_x(code_value_axis_units(X_AXIS));
+    if ((hasY = code_seen('Y'))) py = mbl.probe_index_y(code_value_axis_units(Y_AXIS));
+    if ((hasI = code_seen('I'))) px = code_value_axis_units(X_AXIS);
+    if ((hasJ = code_seen('J'))) py = code_value_axis_units(Y_AXIS);
+    if ((hasZ = code_seen('Z'))) z = code_value_axis_units(Z_AXIS);
 
     if (hasX && hasY && hasZ) {
 
@@ -6104,7 +6235,7 @@ inline void gcode_M502() {
  * M503: print settings currently in memory
  */
 inline void gcode_M503() {
-  Config_PrintSettings(code_seen('S') && code_value() == 0);
+  Config_PrintSettings(code_seen('S') && !code_value_bool());
 }
 
 #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
@@ -6113,7 +6244,7 @@ inline void gcode_M503() {
    * M540: Set whether SD card print should abort on endstop hit (M540 S<0|1>)
    */
   inline void gcode_M540() {
-    if (code_seen('S')) stepper.abort_on_endstop_hit = (code_value() > 0);
+    if (code_seen('S')) stepper.abort_on_endstop_hit = code_value_bool();
   }
 
 #endif // ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
@@ -6127,7 +6258,7 @@ inline void gcode_M503() {
     SERIAL_CHAR(' ');
 
     if (code_seen('Z')) {
-      float value = code_value();
+      float value = code_value_axis_units(Z_AXIS);
       if (Z_PROBE_OFFSET_RANGE_MIN <= value && value <= Z_PROBE_OFFSET_RANGE_MAX) {
         zprobe_zoffset = value;
         SERIAL_ECHO(zprobe_zoffset);
@@ -6186,7 +6317,7 @@ inline void gcode_M503() {
     #endif
 
     //retract by E
-    if (code_seen('E')) destination[E_AXIS] += code_value();
+    if (code_seen('E')) destination[E_AXIS] += code_value_axis_units(E_AXIS);
     #ifdef FILAMENTCHANGE_FIRSTRETRACT
       else destination[E_AXIS] += FILAMENTCHANGE_FIRSTRETRACT;
     #endif
@@ -6194,7 +6325,7 @@ inline void gcode_M503() {
     RUNPLAN;
 
     //lift Z
-    if (code_seen('Z')) destination[Z_AXIS] += code_value();
+    if (code_seen('Z')) destination[Z_AXIS] += code_value_axis_units(Z_AXIS);
     #ifdef FILAMENTCHANGE_ZADD
       else destination[Z_AXIS] += FILAMENTCHANGE_ZADD;
     #endif
@@ -6202,19 +6333,19 @@ inline void gcode_M503() {
     RUNPLAN;
 
     //move xy
-    if (code_seen('X')) destination[X_AXIS] = code_value();
+    if (code_seen('X')) destination[X_AXIS] = code_value_axis_units(X_AXIS);
     #ifdef FILAMENTCHANGE_XPOS
       else destination[X_AXIS] = FILAMENTCHANGE_XPOS;
     #endif
 
-    if (code_seen('Y')) destination[Y_AXIS] = code_value();
+    if (code_seen('Y')) destination[Y_AXIS] = code_value_axis_units(Y_AXIS);
     #ifdef FILAMENTCHANGE_YPOS
       else destination[Y_AXIS] = FILAMENTCHANGE_YPOS;
     #endif
 
     RUNPLAN;
 
-    if (code_seen('L')) destination[E_AXIS] += code_value();
+    if (code_seen('L')) destination[E_AXIS] += code_value_axis_units(E_AXIS);
     #ifdef FILAMENTCHANGE_FINALRETRACT
       else destination[E_AXIS] += FILAMENTCHANGE_FINALRETRACT;
     #endif
@@ -6258,7 +6389,7 @@ inline void gcode_M503() {
     #endif
 
     //return to normal
-    if (code_seen('L')) destination[E_AXIS] -= code_value();
+    if (code_seen('L')) destination[E_AXIS] -= code_value_axis_units(E_AXIS);
     #ifdef FILAMENTCHANGE_FINALRETRACT
       else destination[E_AXIS] -= FILAMENTCHANGE_FINALRETRACT;
     #endif
@@ -6310,11 +6441,11 @@ inline void gcode_M503() {
    */
   inline void gcode_M605() {
     stepper.synchronize();
-    if (code_seen('S')) dual_x_carriage_mode = code_value();
+    if (code_seen('S')) dual_x_carriage_mode = code_value_byte();
     switch (dual_x_carriage_mode) {
       case DXC_DUPLICATION_MODE:
-        if (code_seen('X')) duplicate_extruder_x_offset = max(code_value(), X2_MIN_POS - x_home_pos(0));
-        if (code_seen('R')) duplicate_extruder_temp_offset = code_value();
+        if (code_seen('X')) duplicate_extruder_x_offset = max(code_value_axis_units(X_AXIS), X2_MIN_POS - x_home_pos(0));
+        if (code_seen('R')) duplicate_extruder_temp_offset = code_value_temp_diff();
         SERIAL_ECHO_START;
         SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
         SERIAL_CHAR(' ');
@@ -6346,31 +6477,31 @@ inline void gcode_M503() {
 inline void gcode_M907() {
   #if HAS_DIGIPOTSS
     for (int i = 0; i < NUM_AXIS; i++)
-      if (code_seen(axis_codes[i])) stepper.digipot_current(i, code_value());
-    if (code_seen('B')) stepper.digipot_current(4, code_value());
-    if (code_seen('S')) for (int i = 0; i <= 4; i++) stepper.digipot_current(i, code_value());
+      if (code_seen(axis_codes[i])) stepper.digipot_current(i, code_value_int());
+    if (code_seen('B')) stepper.digipot_current(4, code_value_int());
+    if (code_seen('S')) for (int i = 0; i <= 4; i++) stepper.digipot_current(i, code_value_int());
   #endif
   #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
-    if (code_seen('X')) stepper.digipot_current(0, code_value());
+    if (code_seen('X')) stepper.digipot_current(0, code_value_int());
   #endif
   #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
-    if (code_seen('Z')) stepper.digipot_current(1, code_value());
+    if (code_seen('Z')) stepper.digipot_current(1, code_value_int());
   #endif
   #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
-    if (code_seen('E')) stepper.digipot_current(2, code_value());
+    if (code_seen('E')) stepper.digipot_current(2, code_value_int());
   #endif
   #if ENABLED(DIGIPOT_I2C)
     // this one uses actual amps in floating point
-    for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) digipot_i2c_set_current(i, code_value());
+    for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) digipot_i2c_set_current(i, code_value_float());
     // for each additional extruder (named B,C,D,E..., channels 4,5,6,7...)
-    for (int i = NUM_AXIS; i < DIGIPOT_I2C_NUM_CHANNELS; i++) if (code_seen('B' + i - (NUM_AXIS))) digipot_i2c_set_current(i, code_value());
+    for (int i = NUM_AXIS; i < DIGIPOT_I2C_NUM_CHANNELS; i++) if (code_seen('B' + i - (NUM_AXIS))) digipot_i2c_set_current(i, code_value_float());
   #endif
   #if ENABLED(DAC_STEPPER_CURRENT)
     if (code_seen('S')) {
-      float dac_percent = code_value();
+      float dac_percent = code_value_float();
       for (uint8_t i = 0; i <= 4; i++) dac_current_percent(i, dac_percent);
     }
-    for (uint8_t i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) dac_current_percent(i, code_value());
+    for (uint8_t i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) dac_current_percent(i, code_value_float());
   #endif
 }
 
@@ -6382,14 +6513,14 @@ inline void gcode_M907() {
   inline void gcode_M908() {
     #if HAS_DIGIPOTSS
       stepper.digitalPotWrite(
-        code_seen('P') ? code_value() : 0,
-        code_seen('S') ? code_value() : 0
+        code_seen('P') ? code_value_int() : 0,
+        code_seen('S') ? code_value_int() : 0
       );
     #endif
     #ifdef DAC_STEPPER_CURRENT
       dac_current_raw(
-        code_seen('P') ? code_value_long() : -1,
-        code_seen('S') ? code_value_short() : 0
+        code_seen('P') ? code_value_byte() : -1,
+        code_seen('S') ? code_value_ushort() : 0
       );
     #endif
   }
@@ -6408,9 +6539,9 @@ inline void gcode_M907() {
 
   // M350 Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
   inline void gcode_M350() {
-    if (code_seen('S')) for (int i = 0; i <= 4; i++) stepper.microstep_mode(i, code_value());
-    for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_mode(i, (uint8_t)code_value());
-    if (code_seen('B')) stepper.microstep_mode(4, code_value());
+    if (code_seen('S')) for (int i = 0; i <= 4; i++) stepper.microstep_mode(i, code_value_byte());
+    for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_mode(i, code_value_byte());
+    if (code_seen('B')) stepper.microstep_mode(4, code_value_byte());
     stepper.microstep_readings();
   }
 
@@ -6419,14 +6550,14 @@ inline void gcode_M907() {
    *       S# determines MS1 or MS2, X# sets the pin high/low.
    */
   inline void gcode_M351() {
-    if (code_seen('S')) switch (code_value_short()) {
+    if (code_seen('S')) switch (code_value_byte()) {
       case 1:
-        for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_ms(i, code_value(), -1);
-        if (code_seen('B')) stepper.microstep_ms(4, code_value(), -1);
+        for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_ms(i, code_value_byte(), -1);
+        if (code_seen('B')) stepper.microstep_ms(4, code_value_byte(), -1);
         break;
       case 2:
-        for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_ms(i, -1, code_value());
-        if (code_seen('B')) stepper.microstep_ms(4, -1, code_value());
+        for (int i = 0; i < NUM_AXIS; i++) if (code_seen(axis_codes[i])) stepper.microstep_ms(i, -1, code_value_byte());
+        if (code_seen('B')) stepper.microstep_ms(4, -1, code_value_byte());
         break;
     }
     stepper.microstep_readings();
@@ -6448,7 +6579,7 @@ inline void gcode_M999() {
   Running = true;
   lcd_reset_alert_level();
 
-  if (code_seen('S') && code_value_short() == 1) return;
+  if (code_seen('S') && code_value_bool()) return;
 
   // gcode_LastN = Stopped_gcode_LastN;
   FlushSerialRequestResend();
@@ -6471,7 +6602,7 @@ inline void gcode_T(uint8_t tmp_extruder) {
   float stored_feedrate = feedrate;
 
   if (code_seen('F')) {
-    float next_feedrate = code_value();
+    float next_feedrate = code_value_axis_units(E_AXIS);
     if (next_feedrate > 0.0) stored_feedrate = feedrate = next_feedrate;
   }
   else {
@@ -6703,6 +6834,16 @@ void process_next_command() {
 
       #endif // FWRETRACT
 
+      #if ENABLED(INCH_MODE_SUPPORT)
+        case 20: //G20: Inch Mode
+          gcode_G20();
+          break;
+
+        case 21: //G21: MM Mode
+          gcode_G21();
+          break;
+      #endif
+
       case 28: // G28: Home all axes, one at a time
         gcode_G28();
         break;
@@ -6961,6 +7102,12 @@ void process_next_command() {
 
       #endif
 
+      #if ENABLED(TEMPERATURE_UNITS_SUPPORT)
+        case 149:
+          gcode_M149();
+          break;
+      #endif
+
       #if ENABLED(BLINKM)
 
         case 150: // M150
diff --git a/Marlin/example_configurations/Felix/Configuration.h b/Marlin/example_configurations/Felix/Configuration.h
index 2cfe41a9df..d0e6a24539 100644
--- a/Marlin/example_configurations/Felix/Configuration.h
+++ b/Marlin/example_configurations/Felix/Configuration.h
@@ -732,6 +732,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/Felix/DUAL/Configuration.h b/Marlin/example_configurations/Felix/DUAL/Configuration.h
index 0fbcb652d7..fad9739572 100644
--- a/Marlin/example_configurations/Felix/DUAL/Configuration.h
+++ b/Marlin/example_configurations/Felix/DUAL/Configuration.h
@@ -730,6 +730,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/Hephestos/Configuration.h b/Marlin/example_configurations/Hephestos/Configuration.h
index 989d6ae27d..e8285598fe 100644
--- a/Marlin/example_configurations/Hephestos/Configuration.h
+++ b/Marlin/example_configurations/Hephestos/Configuration.h
@@ -741,6 +741,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/Hephestos_2/Configuration.h b/Marlin/example_configurations/Hephestos_2/Configuration.h
index 4f2c1fab09..efb8f5bfd5 100644
--- a/Marlin/example_configurations/Hephestos_2/Configuration.h
+++ b/Marlin/example_configurations/Hephestos_2/Configuration.h
@@ -743,6 +743,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/K8200/Configuration.h b/Marlin/example_configurations/K8200/Configuration.h
index c4c0572c6d..c0530274c3 100644
--- a/Marlin/example_configurations/K8200/Configuration.h
+++ b/Marlin/example_configurations/K8200/Configuration.h
@@ -766,6 +766,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
index 27c70aa97a..098c813ec2 100644
--- a/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
+++ b/Marlin/example_configurations/RepRapWorld/Megatronics/Configuration.h
@@ -749,6 +749,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/RigidBot/Configuration.h b/Marlin/example_configurations/RigidBot/Configuration.h
index 40910c8cb5..0ea2475510 100644
--- a/Marlin/example_configurations/RigidBot/Configuration.h
+++ b/Marlin/example_configurations/RigidBot/Configuration.h
@@ -744,6 +744,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/SCARA/Configuration.h b/Marlin/example_configurations/SCARA/Configuration.h
index 736b835a43..77c1105b93 100644
--- a/Marlin/example_configurations/SCARA/Configuration.h
+++ b/Marlin/example_configurations/SCARA/Configuration.h
@@ -757,6 +757,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/TAZ4/Configuration.h b/Marlin/example_configurations/TAZ4/Configuration.h
index 4586e843f4..af2ca3faff 100644
--- a/Marlin/example_configurations/TAZ4/Configuration.h
+++ b/Marlin/example_configurations/TAZ4/Configuration.h
@@ -770,6 +770,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/WITBOX/Configuration.h b/Marlin/example_configurations/WITBOX/Configuration.h
index 58bb250abf..dc0debd762 100644
--- a/Marlin/example_configurations/WITBOX/Configuration.h
+++ b/Marlin/example_configurations/WITBOX/Configuration.h
@@ -741,6 +741,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/adafruit/ST7565/Configuration.h b/Marlin/example_configurations/adafruit/ST7565/Configuration.h
index 5cec855847..70bf487ea8 100644
--- a/Marlin/example_configurations/adafruit/ST7565/Configuration.h
+++ b/Marlin/example_configurations/adafruit/ST7565/Configuration.h
@@ -749,6 +749,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/delta/biv2.5/Configuration.h b/Marlin/example_configurations/delta/biv2.5/Configuration.h
index 94565f1aaf..76d7046a9f 100644
--- a/Marlin/example_configurations/delta/biv2.5/Configuration.h
+++ b/Marlin/example_configurations/delta/biv2.5/Configuration.h
@@ -838,6 +838,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/delta/generic/Configuration.h b/Marlin/example_configurations/delta/generic/Configuration.h
index c04ba99428..e3e0988caa 100644
--- a/Marlin/example_configurations/delta/generic/Configuration.h
+++ b/Marlin/example_configurations/delta/generic/Configuration.h
@@ -832,6 +832,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/delta/kossel_mini/Configuration.h b/Marlin/example_configurations/delta/kossel_mini/Configuration.h
index 7e9d06d840..b0811e3ed6 100644
--- a/Marlin/example_configurations/delta/kossel_mini/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_mini/Configuration.h
@@ -835,6 +835,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/delta/kossel_pro/Configuration.h b/Marlin/example_configurations/delta/kossel_pro/Configuration.h
index 8e21082dd3..8d6aed2f01 100644
--- a/Marlin/example_configurations/delta/kossel_pro/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_pro/Configuration.h
@@ -835,6 +835,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/delta/kossel_xl/Configuration.h b/Marlin/example_configurations/delta/kossel_xl/Configuration.h
index 0c5efa12e7..812af17cad 100644
--- a/Marlin/example_configurations/delta/kossel_xl/Configuration.h
+++ b/Marlin/example_configurations/delta/kossel_xl/Configuration.h
@@ -837,6 +837,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/makibox/Configuration.h b/Marlin/example_configurations/makibox/Configuration.h
index 615fec0826..4434c68c04 100644
--- a/Marlin/example_configurations/makibox/Configuration.h
+++ b/Marlin/example_configurations/makibox/Configuration.h
@@ -752,6 +752,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = false; // set to true to invert the l
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/example_configurations/tvrrug/Round2/Configuration.h b/Marlin/example_configurations/tvrrug/Round2/Configuration.h
index 4c9cbe352c..5ec43116f9 100644
--- a/Marlin/example_configurations/tvrrug/Round2/Configuration.h
+++ b/Marlin/example_configurations/tvrrug/Round2/Configuration.h
@@ -743,6 +743,16 @@ const bool Z_MIN_PROBE_ENDSTOP_INVERTING = true; // set to true to invert the lo
 //
 //#define M100_FREE_MEMORY_WATCHER // uncomment to add the M100 Free Memory Watcher for debug purpose
 
+//
+// G20/G21 Inch mode support
+//
+//#define INCH_MODE_SUPPORT
+
+//
+// M149 Set temperature units support
+//
+//#define TEMPERATURE_UNITS_SUPPORT
+
 // @section temperature
 
 // Preheat Constants
diff --git a/Marlin/planner.cpp b/Marlin/planner.cpp
index c4c551f017..d5e8312eda 100644
--- a/Marlin/planner.cpp
+++ b/Marlin/planner.cpp
@@ -1155,9 +1155,9 @@ void Planner::reset_acceleration_rates() {
 
   void Planner::autotemp_M109() {
     autotemp_enabled = code_seen('F');
-    if (autotemp_enabled) autotemp_factor = code_value();
-    if (code_seen('S')) autotemp_min = code_value();
-    if (code_seen('B')) autotemp_max = code_value();
+    if (autotemp_enabled) autotemp_factor = code_value_temp_diff();
+    if (code_seen('S')) autotemp_min = code_value_temp_abs();
+    if (code_seen('B')) autotemp_max = code_value_temp_abs();
   }
 
 #endif

From 4980ecc1f76d8e8952ec5acfae33854f6f81acdf Mon Sep 17 00:00:00 2001
From: Scott Lahteine <sourcetree@thinkyhead.com>
Date: Wed, 8 Jun 2016 17:03:28 -0700
Subject: [PATCH 2/4] Smaller binary using inline gcode argument getters

---
 Marlin/Marlin.h        | 11 ---------
 Marlin/Marlin_main.cpp | 52 +++++++++++++++---------------------------
 2 files changed, 19 insertions(+), 44 deletions(-)

diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index 5e0b6bfb9f..7b275b0cb8 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -291,20 +291,9 @@ extern bool axis_homed[3]; // axis[n].is_homed
 
 // GCode support for external objects
 bool code_seen(char);
-float code_value_float();
-unsigned long code_value_ulong();
-long code_value_long();
 int code_value_int();
-uint16_t code_value_ushort();
-uint8_t code_value_byte();
-bool code_value_bool();
-float code_value_linear_units();
-float code_value_per_axis_unit(int axis);
-float code_value_axis_units(int axis);
 float code_value_temp_abs();
 float code_value_temp_diff();
-millis_t code_value_millis();
-millis_t code_value_millis_from_seconds();
 
 #if ENABLED(DELTA)
   extern float delta[3];
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index cb14abe39e..475dea4aa2 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -1167,7 +1167,7 @@ void get_available_commands() {
   #endif
 }
 
-bool code_has_value() {
+inline bool code_has_value() {
   int i = 1;
   char c = seen_pointer[i];
   while (c == ' ') c = seen_pointer[++i];
@@ -1176,7 +1176,7 @@ bool code_has_value() {
   return NUMERIC(c);
 }
 
-float code_value_float() {
+inline float code_value_float() {
   float ret;
   char* e = strchr(seen_pointer, 'E');
   if (e) {
@@ -1189,20 +1189,20 @@ float code_value_float() {
   return ret;
 }
 
-unsigned long code_value_ulong() { return strtoul(seen_pointer + 1, NULL, 10); }
+inline unsigned long code_value_ulong() { return strtoul(seen_pointer + 1, NULL, 10); }
 
-long code_value_long() { return strtol(seen_pointer + 1, NULL, 10); }
+inline long code_value_long() { return strtol(seen_pointer + 1, NULL, 10); }
 
-int code_value_int() { return (int)strtol(seen_pointer + 1, NULL, 10); }
+inline int code_value_int() { return (int)strtol(seen_pointer + 1, NULL, 10); }
 
-uint16_t code_value_ushort() { return (uint16_t)strtoul(seen_pointer + 1, NULL, 10); }
+inline uint16_t code_value_ushort() { return (uint16_t)strtoul(seen_pointer + 1, NULL, 10); }
 
-uint8_t code_value_byte() { return (uint8_t)(constrain(strtol(seen_pointer + 1, NULL, 10), 0, 255)); }
+inline uint8_t code_value_byte() { return (uint8_t)(constrain(strtol(seen_pointer + 1, NULL, 10), 0, 255)); }
 
-bool code_value_bool() { return code_value_byte() > 0; }
+inline bool code_value_bool() { return code_value_byte() > 0; }
 
 #if ENABLED(INCH_MODE_SUPPORT)
-  void set_input_linear_units(LinearUnit units) {
+  inline void set_input_linear_units(LinearUnit units) {
     switch (units) {
       case LINEARUNIT_INCH:
         linear_unit_factor = 25.4;
@@ -1215,33 +1215,24 @@ bool code_value_bool() { return code_value_byte() > 0; }
     volumetric_unit_factor = pow(linear_unit_factor, 3.0);
   }
 
-  float axis_unit_factor(int axis) {
+  inline float axis_unit_factor(int axis) {
     return (axis == E_AXIS && volumetric_enabled ? volumetric_unit_factor : linear_unit_factor);
   }
 
-  float code_value_linear_units() {
-    return code_value_float() * linear_unit_factor;
-  }
+  inline float code_value_linear_units() { return code_value_float() * linear_unit_factor; }
+  inline float code_value_per_axis_unit(int axis) { return code_value_float() / axis_unit_factor(axis); }
+  inline float code_value_axis_units(int axis) { return code_value_float() * axis_unit_factor(axis); }
 
-  float code_value_per_axis_unit(int axis) {
-    return code_value_float() / axis_unit_factor(axis);
-  }
-
-  float code_value_axis_units(int axis) {
-    return code_value_float() * axis_unit_factor(axis);
-  }
 #else
-  float code_value_linear_units() { return code_value_float(); }
 
-  float code_value_per_axis_unit(int axis) { return code_value_float(); }
+  inline float code_value_linear_units() { return code_value_float(); }
+  inline float code_value_per_axis_unit(int axis) { return code_value_float(); }
+  inline float code_value_axis_units(int axis) { return code_value_float(); }
 
-  float code_value_axis_units(int axis) { return code_value_float(); }
 #endif
 
 #if ENABLED(TEMPERATURE_UNITS_SUPPORT)
-  void set_input_temp_units(TempUnit units) {
-    input_temp_units = units;
-  }
+  inline void set_input_temp_units(TempUnit units) { input_temp_units = units; }
   
   float code_value_temp_abs() {
     switch (input_temp_units) {
@@ -1272,13 +1263,8 @@ bool code_value_bool() { return code_value_byte() > 0; }
   float code_value_temp_diff() { return code_value_float(); }
 #endif
 
-millis_t code_value_millis() {
-  return code_value_ulong();
-}
-
-millis_t code_value_millis_from_seconds() {
-  return code_value_float() * 1000;
-}
+inline millis_t code_value_millis() { return code_value_ulong(); }
+inline millis_t code_value_millis_from_seconds() { return code_value_float() * 1000; }
 
 bool code_seen(char code) {
   seen_pointer = strchr(current_command_args, code);

From 0b3142b45b2862e4bd3f35dcf7fd07941086aa7e Mon Sep 17 00:00:00 2001
From: Scott Lahteine <sourcetree@thinkyhead.com>
Date: Wed, 8 Jun 2016 17:03:45 -0700
Subject: [PATCH 3/4] Remove redundant declarations from M100 code

---
 Marlin/M100_Free_Mem_Chk.cpp | 18 +-----------------
 1 file changed, 1 insertion(+), 17 deletions(-)

diff --git a/Marlin/M100_Free_Mem_Chk.cpp b/Marlin/M100_Free_Mem_Chk.cpp
index 36e01ae6cd..521b759e36 100644
--- a/Marlin/M100_Free_Mem_Chk.cpp
+++ b/Marlin/M100_Free_Mem_Chk.cpp
@@ -47,21 +47,6 @@ extern void* __brkval;
 extern size_t  __heap_start, __heap_end, __flp;
 
 
-//
-// Declare all the functions we need from Marlin_Main.cpp to do the work!
-//
-
-int code_value_int();
-bool code_seen(char);
-void serial_echopair_P(const char*, float);
-void serial_echopair_P(const char*, double);
-void serial_echopair_P(const char*, unsigned long);
-void serial_echopair_P(const char*, int);
-void serial_echopair_P(const char*, long);
-
-
-
-
 //
 // Utility functions used by M100 to get its work done.
 //
@@ -175,8 +160,7 @@ void gcode_M100() {
   //
 #if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
   if (code_seen('C')) {
-    int x;      // x gets the # of locations to corrupt within the memory pool
-    x = code_value_int();
+    int x = code_value_int(); // x gets the # of locations to corrupt within the memory pool
     SERIAL_ECHOLNPGM("Corrupting free memory block.\n");
     ptr = (unsigned char*) __brkval;
     SERIAL_ECHOPAIR("\n__brkval : ", ptr);

From 38279a02b2a1f05bfe3917272c517b0efc5fb40c Mon Sep 17 00:00:00 2001
From: Scott Lahteine <sourcetree@thinkyhead.com>
Date: Wed, 8 Jun 2016 17:12:54 -0700
Subject: [PATCH 4/4] Travis tests for Inch, Fahrenheit, Kelvin, M100

---
 .travis.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index c112202925..088f1c56cf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -105,10 +105,10 @@ script:
   - opt_enable NUM_SERVOS Z_ENDSTOP_SERVO_NR SERVO_ENDSTOP_ANGLES DEACTIVATE_SERVOS_AFTER_MOVE
   - build_marlin
   #
-  # Test EEPROM_SETTINGS & EEPROM_CHITCHAT
+  # Test EEPROM_SETTINGS, EEPROM_CHITCHAT, M100_FREE_MEMORY_WATCHER, INCH_MODE_SUPPORT, TEMPERATURE_UNITS_SUPPORT
   #
   - restore_configs
-  - opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT
+  - opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT M100_FREE_MEMORY_WATCHER INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT
   - build_marlin
   #
   # Test DUAL_X_CARRIAGE