More cleanup
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Wed, 6 Jan 2016 09:05:22 +0000 (01:05 -0800)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Wed, 6 Jan 2016 09:05:22 +0000 (01:05 -0800)
src/config.c
src/controller.c
src/gcode_parser.c
src/kinematics.c
src/kinematics.h
src/text_parser.c
src/tinyg.h
src/util.c

index cb262bf6990a8791e4bc7544825fb729b01ef58d..5c65a558b0db5502aa98b40fe42203e8ea1ecd0b 100644 (file)
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-/*
- *    See config.h for a Config system overview and a bunch of details.
- */
-
 #include "tinyg.h"        // #1
 #include "config.h"       // #2
 #include "report.h"
 
 static void _set_defa(nvObj_t *nv);
 
-/***********************************************************************************
- **** STRUCTURE ALLOCATIONS ********************************************************
- ***********************************************************************************/
-
 nvStr_t nvStr;
 nvList_t nvl;
 
@@ -57,8 +49,8 @@ nvList_t nvl;
  *
  * nv_set()     - Write a value or invoke a function - operates on single valued elements or groups
  * nv_get()     - Build a nvObj with the values from the target & return the value
- *                     Populate nv body with single valued elements or groups (iterates)
- * nv_print()    - Output a formatted string for the value.
+ *                Populate nv body with single valued elements or groups (iterates)
+ * nv_print()   - Output a formatted string for the value.
  * nv_persist() - persist value to non-volatile storage. Takes special cases into account
  *
  *    !!!! NOTE: nv_persist() cannot be called from an interrupt on the AVR due to the AVR1008 EEPROM workaround
@@ -82,7 +74,7 @@ void nv_print(nvObj_t *nv) {
 }
 
 
-stat_t nv_persist(nvObj_t *nv) {   // nv_persist() cannot be called from an interrupt on the AVR due to the AVR1008 EEPROM workaround
+stat_t nv_persist(nvObj_t *nv) { // nv_persist() cannot be called from an interrupt on the AVR due to the AVR1008 EEPROM workaround
   if (nv_index_lt_groups(nv->index) == false) return STAT_INTERNAL_RANGE_ERROR;
   if (GET_TABLE_BYTE(flags) & F_PERSIST) return write_persistent_value(nv);
 
@@ -91,7 +83,7 @@ stat_t nv_persist(nvObj_t *nv) {   // nv_persist() cannot be called from an inte
 
 
 /************************************************************************************
- * config_init() - called once on hard reset
+ * Called once on hard reset
  *
  * Performs one of 2 actions:
  *    (1) if persistence is set up or out-of-rev load RAM and NVM with settings.h defaults
@@ -106,18 +98,18 @@ void config_init() {
   nvObj_t *nv = nv_reset_nv_list();
   config_init_assertions();
 
-  cm_set_units_mode(MILLIMETERS);                // must do inits in millimeter mode
-  nv->index = 0;                                // this will read the first record in NVM
+  cm_set_units_mode(MILLIMETERS);              // must do inits in millimeter mode
+  nv->index = 0;                               // this will read the first record in NVM
 
   read_persistent_value(nv);
-  if (nv->value != cs.fw_build)                // case (1) NVM is not setup or not in revision
-    _set_defa(nv);
-  else {                                    // case (2) NVM is setup and in revision
+  if (nv->value != cs.fw_build) _set_defa(nv); // case (1) NVM is not setup or not in revision
+
+  else {                                       // case (2) NVM is setup and in revision
     rpt_print_loading_configs_message();
 
-    for (nv->index=0; nv_index_is_single(nv->index); nv->index++)
+    for (nv->index = 0; nv_index_is_single(nv->index); nv->index++)
       if (GET_TABLE_BYTE(flags) & F_INITIALIZE) {
-        strncpy_P(nv->token, cfgArray[nv->index].token, TOKEN_LEN);    // read the token from the array
+        strncpy_P(nv->token, cfgArray[nv->index].token, TOKEN_LEN); // read the token from the array
         read_persistent_value(nv);
         nv_set(nv);
       }
@@ -133,7 +125,7 @@ void config_init() {
  */
 static void _set_defa(nvObj_t *nv) {
   cm_set_units_mode(MILLIMETERS);                // must do inits in MM mode
-  for (nv->index=0; nv_index_is_single(nv->index); nv->index++)
+  for (nv->index = 0; nv_index_is_single(nv->index); nv->index++)
     if (GET_TABLE_BYTE(flags) & F_INITIALIZE) {
       nv->value = GET_TABLE_FLOAT(def_value);
       strncpy_P(nv->token, cfgArray[nv->index].token, TOKEN_LEN);
@@ -142,7 +134,7 @@ static void _set_defa(nvObj_t *nv) {
     }
 
   sr_init_status_report();                    // reset status reports
-  rpt_print_initializing_message();            // don't start TX until all the NVM persistence is done
+  rpt_print_initializing_message();           // don't start TX until all the NVM persistence is done
 }
 
 
index 15e52703b202d305223ee01a64a08802fd394b76..9e40057d3ef4d91ced59d002ce064f0601f6afaa 100644 (file)
@@ -140,7 +140,25 @@ void controller_run() {
   DISPATCH(_sync_to_tx_buffer());              // sync with TX buffer (pseudo-blocking)
   DISPATCH(set_baud_callback());               // perform baud rate update (must be after TX sync)
   DISPATCH(_command_dispatch());               // read and execute next command
-  DISPATCH(_normal_idler());                   // blink LEDs slowly to show everything is OK
+  DISPATCH(_normal_idler());
+}
+
+
+stat_t _command_dispatch() {
+  stat_t status;
+
+  // read input line or return if not a completed line
+  // usart_gets() is a non-blocking workalike of fgets()
+  while (true) {
+    if ((status = usart_gets(cs.in_buf, sizeof(cs.in_buf))) == STAT_OK) {
+      cs.bufp = cs.in_buf;
+      break;
+    }
+
+    return status;                                // Note: STAT_EAGAIN, errors, etc. will drop through
+  }
+
+  return gc_gcode_parser(cs.in_buf);
 }
 
 
@@ -151,7 +169,7 @@ void controller_run() {
  *    Accepts commands if the move queue has room - EAGAINS if it doesn't
  *    Also responsible for prompts and for flow control
  */
-static stat_t _command_dispatch() {
+stat_t _command_dispatch_old() {
   stat_t status;
 
   // read input line or return if not a completed line
@@ -170,7 +188,7 @@ static stat_t _command_dispatch() {
   strncpy(cs.saved_buf, cs.bufp, SAVED_BUFFER_LEN - 1);  // save input buffer for reporting
 
   // dispatch the new text line
-  switch (toupper(*cs.bufp)) {                    // first char
+  switch (*cs.bufp) {                             // first char
   case '!': cm_request_feedhold(); break;         // include for diagnostics
   case '%': cm_request_queue_flush(); break;
   case '~': cm_request_cycle_start(); break;
@@ -180,7 +198,7 @@ static stat_t _command_dispatch() {
       text_response(STAT_OK, cs.saved_buf);
     break;
 
-  case '$': case '?': case 'H':                   // text mode input
+  case '$': case '?': case 'H': case 'h':         // text mode input
     cfg.comm_mode = TEXT_MODE;
     text_response(text_parser(cs.bufp), cs.saved_buf);
     break;
index 7185d7f92b719c0f0d40374c59b4c9a4c9389ae6..9505c0444c52a2b54b76c85476df5425eecd665d 100644 (file)
@@ -40,6 +40,7 @@ static stat_t _execute_gcode_block();        // Execute the gcode block
 #define SET_NON_MODAL(parm,val) ({cm.gn.parm=val; cm.gf.parm=1; break;})
 #define EXEC_FUNC(f,v) if((uint8_t)cm.gf.v != false) { status = f(cm.gn.v);}
 
+
 /// Parse a block (line) of gcode
 /// Top level of gcode parser. Normalizes block and looks for special cases
 stat_t gc_gcode_parser(char_t *block) {
index 622c5b54128969a4adb512cc92d0441bcb939913..554f67217e95bd234f4c66e5900a88acaa487006 100644 (file)
@@ -33,7 +33,7 @@
 
 
 /*
- * ik_kinematics() - wrapper routine for inverse kinematics
+ * Wrapper routine for inverse kinematics
  *
  *    Calls kinematics function(s).
  *    Performs axis mapping & conversion of length units to steps (and deals with inhibited axes)
  *    order to get the smoothest possible operation. Steps are passed to the move prep routine
  *    as floats and converted to fixed-point binary during queue loading. See stepper.c for details.
  */
+void ik_kinematics(const float travel[], float steps[]) {
+  float joint[AXES];
 
-void ik_kinematics(const float travel[], float steps[])
-{
-    float joint[AXES];
+  //  _inverse_kinematics(travel, joint);           // you can insert inverse kinematics transformations here
+  memcpy(joint, travel, sizeof(float) * AXES);      //...or just do a memcpy for Cartesian machines
 
-//    _inverse_kinematics(travel, joint);                // you can insert inverse kinematics transformations here
-    memcpy(joint, travel, sizeof(float)*AXES);        //...or just do a memcpy for Cartesian machines
+  // Map motors to axes and convert length units to steps
+  // Most of the conversion math has already been done in during config in steps_per_unit()
+  // which takes axis travel, step angle and microsteps into account.
+  for (uint8_t axis = 0; axis < AXES; axis++) {
+    if (cm.a[axis].axis_mode == AXIS_INHIBITED) joint[axis] = 0;
 
-    // Map motors to axes and convert length units to steps
-    // Most of the conversion math has already been done in during config in steps_per_unit()
-    // which takes axis travel, step angle and microsteps into account.
-    for (uint8_t axis=0; axis<AXES; axis++) {
-        if (cm.a[axis].axis_mode == AXIS_INHIBITED) { joint[axis] = 0;}
-        if (st_cfg.mot[MOTOR_1].motor_map == axis) { steps[MOTOR_1] = joint[axis] * st_cfg.mot[MOTOR_1].steps_per_unit;}
-        if (st_cfg.mot[MOTOR_2].motor_map == axis) { steps[MOTOR_2] = joint[axis] * st_cfg.mot[MOTOR_2].steps_per_unit;}
-        if (st_cfg.mot[MOTOR_3].motor_map == axis) { steps[MOTOR_3] = joint[axis] * st_cfg.mot[MOTOR_3].steps_per_unit;}
-        if (st_cfg.mot[MOTOR_4].motor_map == axis) { steps[MOTOR_4] = joint[axis] * st_cfg.mot[MOTOR_4].steps_per_unit;}
-#if (MOTORS >= 5)
-        if (st_cfg.mot[MOTOR_5].motor_map == axis) { steps[MOTOR_5] = joint[axis] * st_cfg.mot[MOTOR_5].steps_per_unit;}
-#endif
-#if (MOTORS >= 6)
-        if (st_cfg.mot[MOTOR_6].motor_map == axis) { steps[MOTOR_6] = joint[axis] * st_cfg.mot[MOTOR_6].steps_per_unit;}
-#endif
-    }
+    for (int i = 0; i < MOTORS; i++)
+      if (st_cfg.mot[i].motor_map == axis)
+        steps[i] = joint[axis] * st_cfg.mot[i].steps_per_unit;
+  }
 }
 
index dbb8826c035f70a77e7524c5702f4e05935b69ce..4b0e901971cea16019bdda90c5864e04ff30cd20 100644 (file)
 #ifndef KINEMATICS_H_ONCE
 #define KINEMATICS_H_ONCE
 
-/*
- * Global Scope Functions
- */
-
 void ik_kinematics(const float travel[], float steps[]);
 
-#endif // End of include Guard: KINEMATICS_H_ONCE
+#endif // KINEMATICS_H_ONCE
index ea43c1d56335bcd3425df38c85acce439318f862..69cc432c7c27cde631f77e84446aabc57a5f7893 100644 (file)
@@ -59,7 +59,7 @@ static stat_t _text_parser_kernal(char_t *str, nvObj_t *nv);
  *    - ?                generate a status report (multiline format)
  */
 stat_t text_parser(char_t *str) {
-  nvObj_t *nv = nv_reset_nv_list();                // returns first object in the body
+  nvObj_t *nv = nv_reset_nv_list();               // returns first object in the body
   stat_t status = STAT_OK;
 
   // trap special displays
@@ -74,19 +74,19 @@ stat_t text_parser(char_t *str) {
   }
 
   // pre-process the command
-  if ((str[0] == '$') && (str[1] == 0))          // treat a lone $ as a sys request
-    strcat(str,"sys");
+  if ((str[0] == '$') && (str[1] == 0))           // treat a lone $ as a sys request
+    strcat(str, "sys");
 
   // parse and execute the command (only processes 1 command per line)
-  ritorno(_text_parser_kernal(str, nv));            // run the parser to decode the command
+  ritorno(_text_parser_kernal(str, nv));          // run the parser to decode the command
   if ((nv->valuetype == TYPE_0) || (nv->valuetype == TYPE_PARENT)) {
-    if (nv_get(nv) == STAT_COMPLETE)         // populate value, group values, or run uber-group displays
-      return STAT_OK;                        // return for uber-group displays so they don't print twice
+    if (nv_get(nv) == STAT_COMPLETE)              // populate value, group values, or run uber-group displays
+      return STAT_OK;                             // return for uber-group displays so they don't print twice
 
-  } else {                                         // process SET and RUN commands
+  } else {                                        // process SET and RUN commands
     if (cm.machine_state == MACHINE_ALARM) return STAT_MACHINE_ALARMED;
-    status = nv_set(nv);                        // set (or run) single value
-    if (status == STAT_OK) nv_persist(nv);      // conditionally persist depending on flags in array
+    status = nv_set(nv);                          // set (or run) single value
+    if (status == STAT_OK) nv_persist(nv);        // conditionally persist depending on flags in array
   }
 
   nv_print_list(status, TEXT_MULTILINE_FORMATTED, JSON_RESPONSE_FORMAT); // print the results
index 99e69e1b328bff50005825374564581642d894cf..205c5f45691db498588b8009c91af16680d6b597 100644 (file)
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
-/* Is this code over documented? Possibly.
- * We try to follow this (at least we are evolving to it). It's worth a read.
- * ftp://ftp.idsoftware.com/idstuff/doom3/source/CodeStyleConventions.doc
- */
-/* Xmega project setup notes:
- * from: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=117023
- * "Yes it's definitely worth making WinAVR work. To install WinAVR for the project use
- * Project-Configuration Options and under Custom Options untick the "Use toolchain" box
- * then set the top one to \winavr\bin\avr-gcc.exe  (C:\WinAVR-20100110\bin\avr-gcc.exe)
- * and the lower one to \winavr\utils\bin\make.exe  (C:\WinAVR-20100110\utils\bin\make.exe)"
- */
 
 #ifndef TINYG_H_ONCE
 #define TINYG_H_ONCE
 #include <string.h>
 #include <math.h>
 
-/****** REVISIONS ******/
-
+// Revisions
 #ifndef TINYG_FIRMWARE_BUILD
 #define TINYG_FIRMWARE_BUILD        440.20    // arc test
 
 #endif
-#define TINYG_FIRMWARE_VERSION        0.97                      // firmware major version
-#define TINYG_HARDWARE_PLATFORM       HW_PLATFORM_TINYG_XMEGA   // see hardware.h
-#define TINYG_HARDWARE_VERSION        HW_VERSION_TINYGV8        // see hardware.h
-#define TINYG_HARDWARE_VERSION_MAX    TINYG_HARDWARE_VERSION
-
-/****** COMPILE-TIME SETTINGS ******/
+#define TINYG_FIRMWARE_VERSION     0.97                      // firmware major version
+#define TINYG_HARDWARE_PLATFORM    HW_PLATFORM_TINYG_XMEGA   // see hardware.h
+#define TINYG_HARDWARE_VERSION     HW_VERSION_TINYGV8        // see hardware.h
+#define TINYG_HARDWARE_VERSION_MAX TINYG_HARDWARE_VERSION
 
+// Compile-time settings
 #define __STEP_CORRECTION
-//#define __JERK_EXEC                        // Use computed jerk (versus forward difference based exec)
-//#define __KAHAN                            // Use Kahan summation in aline exec functions
+//#define __JERK_EXEC                         // Use computed jerk (versus forward difference based exec)
+//#define __KAHAN                             // Use Kahan summation in aline exec functions
 
-#define __TEXT_MODE                            // enables text mode    (~10Kb)
+#define __TEXT_MODE                           // enables text mode    (~10Kb)
 #define __HELP_SCREENS                        // enables help screens (~3.5Kb)
-//#define __CANNED_TESTS                         // enables $tests         (~12Kb)
-//#define __TEST_99                             // enables diagnostic test 99 (independent of other tests)
+//#define __CANNED_TESTS                      // enables $tests         (~12Kb)
+//#define __TEST_99                           // enables diagnostic test 99 (independent of other tests)
 
-/****** DEVELOPMENT SETTINGS ******/
-
-#define __DIAGNOSTIC_PARAMETERS                // enables system diagnostic parameters (_xx) in config_app
+// Development settings
+#define __DIAGNOSTIC_PARAMETERS               // enables system diagnostic parameters (_xx) in config_app
 //#define __DEBUG_SETTINGS                    // special settings. See settings.h
 //#define __CANNED_STARTUP                    // run any canned startup moves
 
@@ -75,7 +61,7 @@ typedef char char_t;
                                                                     // gets rely on nv->index having been set
 #define GET_TABLE_WORD(a)  pgm_read_word(&cfgArray[nv->index].a)    // get word value from cfgArray
 #define GET_TABLE_BYTE(a)  pgm_read_byte(&cfgArray[nv->index].a)    // get byte value from cfgArray
-#define GET_TABLE_FLOAT(a) pgm_read_float(&cfgArray[nv->index].a)    // get float value from cfgArray
+#define GET_TABLE_FLOAT(a) pgm_read_float(&cfgArray[nv->index].a)   // get float value from cfgArray
 #define GET_TOKEN_BYTE(a)  (char_t)pgm_read_byte(&cfgArray[i].a)    // get token byte value from cfgArray
 
 // populate the shared buffer with the token string given the index
@@ -90,9 +76,6 @@ typedef char char_t;
 // String compatibility
 #define strtof strtod            // strtof is not in the AVR lib
 
-/******************************************************************************
- ***** TINYG APPLICATION DEFINITIONS ******************************************
- ******************************************************************************/
 
 typedef uint16_t magic_t;        // magic number size
 #define MAGICNUM 0x12EF          // used for memory integrity assertions
@@ -114,12 +97,12 @@ typedef uint16_t magic_t;        // magic number size
 #define AXIS_A        3
 #define AXIS_B        4
 #define AXIS_C        5
-#define AXIS_U        6            // reserved
-#define AXIS_V        7            // reserved
-#define AXIS_W        8            // reserved
+#define AXIS_U        6           // reserved
+#define AXIS_V        7           // reserved
+#define AXIS_W        8           // reserved
 
-#define MOTOR_1        0            // define motor numbers and array indexes
-#define MOTOR_2        1            // must be defines. enums don't work
+#define MOTOR_1        0          // define motor numbers and array indexes
+#define MOTOR_2        1          // must be defines. enums don't work
 #define MOTOR_3        2
 #define MOTOR_4        3
 #define MOTOR_5        4
@@ -128,6 +111,7 @@ typedef uint16_t magic_t;        // magic number size
 #define PWM_1        0
 #define PWM_2        1
 
+
 /************************************************************************************
  * STATUS CODES
  *
@@ -137,10 +121,10 @@ typedef uint16_t magic_t;        // magic number size
  *
  * Ranges are:
  *
- *   0 - 19        OS, communications and low-level status
+ *   0 - 19      OS, communications and low-level status
  *
- *  20 - 99        Generic internal and application errors. Internal errors start at 20 and work up,
- *                 Assertion failures start at 99 and work down.
+ *  20 - 99      Generic internal and application errors. Internal errors start at 20 and work up,
+ *               Assertion failures start at 99 and work down.
  *
  * 100 - 129    Generic data and input errors - not specific to Gcode or TinyG
  *
@@ -318,23 +302,23 @@ char *get_status_message(stat_t status);
 // Gcode errors and warnings (Most originate from NIST - by concept, not number)
 // Fascinating: http://www.cncalarms.com/
 
-#define STAT_GCODE_GENERIC_INPUT_ERROR 130                // generic error for gcode input
-#define STAT_GCODE_COMMAND_UNSUPPORTED 131                // G command is not supported
-#define STAT_MCODE_COMMAND_UNSUPPORTED 132                // M command is not supported
+#define STAT_GCODE_GENERIC_INPUT_ERROR 130              // generic error for gcode input
+#define STAT_GCODE_COMMAND_UNSUPPORTED 131              // G command is not supported
+#define STAT_MCODE_COMMAND_UNSUPPORTED 132              // M command is not supported
 #define STAT_GCODE_MODAL_GROUP_VIOLATION 133            // gcode modal group error
-#define STAT_GCODE_AXIS_IS_MISSING 134                    // command requires at least one axis present
-#define STAT_GCODE_AXIS_CANNOT_BE_PRESENT 135            // error if G80 has axis words
-#define STAT_GCODE_AXIS_IS_INVALID 136                    // an axis is specified that is illegal for the command
-#define STAT_GCODE_AXIS_IS_NOT_CONFIGURED 137            // WARNING: attempt to program an axis that is disabled
-#define STAT_GCODE_AXIS_NUMBER_IS_MISSING 138            // axis word is missing its value
-#define STAT_GCODE_AXIS_NUMBER_IS_INVALID 139             // axis word value is illegal
-
-#define STAT_GCODE_ACTIVE_PLANE_IS_MISSING 140            // active plane is not programmed
-#define STAT_GCODE_ACTIVE_PLANE_IS_INVALID 141            // active plane selected is not valid for this command
-#define STAT_GCODE_FEEDRATE_NOT_SPECIFIED 142            // move has no feedrate
-#define STAT_GCODE_INVERSE_TIME_MODE_CANNOT_BE_USED 143    // G38.2 and some canned cycles cannot accept inverse time mode
-#define STAT_GCODE_ROTARY_AXIS_CANNOT_BE_USED 144        // G38.2 and some other commands cannot have rotary axes
-#define STAT_GCODE_G53_WITHOUT_G0_OR_G1 145                // G0 or G1 must be active for G53
+#define STAT_GCODE_AXIS_IS_MISSING 134                  // command requires at least one axis present
+#define STAT_GCODE_AXIS_CANNOT_BE_PRESENT 135           // error if G80 has axis words
+#define STAT_GCODE_AXIS_IS_INVALID 136                  // an axis is specified that is illegal for the command
+#define STAT_GCODE_AXIS_IS_NOT_CONFIGURED 137           // WARNING: attempt to program an axis that is disabled
+#define STAT_GCODE_AXIS_NUMBER_IS_MISSING 138           // axis word is missing its value
+#define STAT_GCODE_AXIS_NUMBER_IS_INVALID 139           // axis word value is illegal
+
+#define STAT_GCODE_ACTIVE_PLANE_IS_MISSING 140          // active plane is not programmed
+#define STAT_GCODE_ACTIVE_PLANE_IS_INVALID 141          // active plane selected is not valid for this command
+#define STAT_GCODE_FEEDRATE_NOT_SPECIFIED 142           // move has no feedrate
+#define STAT_GCODE_INVERSE_TIME_MODE_CANNOT_BE_USED 143 // G38.2 and some canned cycles cannot accept inverse time mode
+#define STAT_GCODE_ROTARY_AXIS_CANNOT_BE_USED 144       // G38.2 and some other commands cannot have rotary axes
+#define STAT_GCODE_G53_WITHOUT_G0_OR_G1 145             // G0 or G1 must be active for G53
 #define STAT_REQUESTED_VELOCITY_EXCEEDS_LIMITS 146
 #define STAT_CUTTER_COMPENSATION_CANNOT_BE_ENABLED 147
 #define STAT_PROGRAMMED_POINT_SAME_AS_CURRENT_POINT 148
@@ -351,11 +335,11 @@ char *get_status_message(stat_t status);
 #define STAT_ARC_RADIUS_OUT_OF_TOLERANCE 158            // WARNING - radius arc is too small or too large - accuracy in question
 #define STAT_ARC_ENDPOINT_IS_STARTING_POINT 159
 
-#define STAT_P_WORD_IS_MISSING 160                        // P must be present for dwells and other functions
-#define STAT_P_WORD_IS_INVALID 161                        // generic P value error
+#define STAT_P_WORD_IS_MISSING 160                      // P must be present for dwells and other functions
+#define STAT_P_WORD_IS_INVALID 161                      // generic P value error
 #define STAT_P_WORD_IS_ZERO 162
-#define STAT_P_WORD_IS_NEGATIVE 163                        // dwells require positive P values
-#define STAT_P_WORD_IS_NOT_AN_INTEGER 164                // G10s and other commands require integer P numbers
+#define STAT_P_WORD_IS_NEGATIVE 163                     // dwells require positive P values
+#define STAT_P_WORD_IS_NOT_AN_INTEGER 164               // G10s and other commands require integer P numbers
 #define STAT_P_WORD_IS_NOT_VALID_TOOL_NUMBER 165
 #define STAT_D_WORD_IS_MISSING 166
 #define STAT_D_WORD_IS_INVALID 167
@@ -373,7 +357,7 @@ char *get_status_message(stat_t status);
 #define STAT_T_WORD_IS_MISSING 178
 #define STAT_T_WORD_IS_INVALID 179
 
-#define STAT_ERROR_180 180                                    // reserved for Gcode errors
+#define STAT_ERROR_180 180                              // reserved for Gcode errors
 #define STAT_ERROR_181 181
 #define STAT_ERROR_182 182
 #define STAT_ERROR_183 183
@@ -396,13 +380,12 @@ char *get_status_message(stat_t status);
 #define STAT_ERROR_199 199
 
 // TinyG errors and warnings
-
 #define STAT_GENERIC_ERROR 200
 #define STAT_MINIMUM_LENGTH_MOVE 201                    // move is less than minimum length
-#define STAT_MINIMUM_TIME_MOVE 202                        // move is less than minimum time
+#define STAT_MINIMUM_TIME_MOVE 202                      // move is less than minimum time
 #define STAT_MACHINE_ALARMED 203                        // machine is alarmed. Command not processed
-#define STAT_LIMIT_SWITCH_HIT 204                        // a limit switch was hit causing shutdown
-#define STAT_PLANNER_FAILED_TO_CONVERGE 205                // trapezoid generator can through this exception
+#define STAT_LIMIT_SWITCH_HIT 204                       // a limit switch was hit causing shutdown
+#define STAT_PLANNER_FAILED_TO_CONVERGE 205             // trapezoid generator can through this exception
 #define STAT_ERROR_206 206
 #define STAT_ERROR_207 207
 #define STAT_ERROR_208 208
@@ -420,19 +403,19 @@ char *get_status_message(stat_t status);
 #define STAT_ERROR_219 219
 
 #define STAT_SOFT_LIMIT_EXCEEDED 220                    // soft limit error - axis unspecified
-#define STAT_SOFT_LIMIT_EXCEEDED_XMIN 221                // soft limit error - X minimum
-#define STAT_SOFT_LIMIT_EXCEEDED_XMAX 222                // soft limit error - X maximum
-#define STAT_SOFT_LIMIT_EXCEEDED_YMIN 223                // soft limit error - Y minimum
-#define STAT_SOFT_LIMIT_EXCEEDED_YMAX 224                // soft limit error - Y maximum
-#define STAT_SOFT_LIMIT_EXCEEDED_ZMIN 225                // soft limit error - Z minimum
-#define STAT_SOFT_LIMIT_EXCEEDED_ZMAX 226                // soft limit error - Z maximum
-#define STAT_SOFT_LIMIT_EXCEEDED_AMIN 227                // soft limit error - A minimum
-#define STAT_SOFT_LIMIT_EXCEEDED_AMAX 228                // soft limit error - A maximum
-#define STAT_SOFT_LIMIT_EXCEEDED_BMIN 229                // soft limit error - B minimum
-
-#define STAT_SOFT_LIMIT_EXCEEDED_BMAX 220                // soft limit error - B maximum
-#define STAT_SOFT_LIMIT_EXCEEDED_CMIN 231                // soft limit error - C minimum
-#define STAT_SOFT_LIMIT_EXCEEDED_CMAX 232                // soft limit error - C maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_XMIN 221               // soft limit error - X minimum
+#define STAT_SOFT_LIMIT_EXCEEDED_XMAX 222               // soft limit error - X maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_YMIN 223               // soft limit error - Y minimum
+#define STAT_SOFT_LIMIT_EXCEEDED_YMAX 224               // soft limit error - Y maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_ZMIN 225               // soft limit error - Z minimum
+#define STAT_SOFT_LIMIT_EXCEEDED_ZMAX 226               // soft limit error - Z maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_AMIN 227               // soft limit error - A minimum
+#define STAT_SOFT_LIMIT_EXCEEDED_AMAX 228               // soft limit error - A maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_BMIN 229               // soft limit error - B minimum
+
+#define STAT_SOFT_LIMIT_EXCEEDED_BMAX 220               // soft limit error - B maximum
+#define STAT_SOFT_LIMIT_EXCEEDED_CMIN 231               // soft limit error - C minimum
+#define STAT_SOFT_LIMIT_EXCEEDED_CMAX 232               // soft limit error - C maximum
 #define STAT_ERROR_233 233
 #define STAT_ERROR_234 234
 #define STAT_ERROR_235 235
@@ -452,10 +435,10 @@ char *get_status_message(stat_t status);
 #define STAT_ERROR_248 248
 #define STAT_ERROR_249 249
 
-#define STAT_PROBE_CYCLE_FAILED 250                        // probing cycle did not complete
+#define STAT_PROBE_CYCLE_FAILED 250                     // probing cycle did not complete
 #define STAT_PROBE_ENDPOINT_IS_STARTING_POINT 251
-#define STAT_JOGGING_CYCLE_FAILED 252                    // jogging cycle did not complete
+#define STAT_JOGGING_CYCLE_FAILED 252                   // jogging cycle did not complete
 
 // !!! Do not exceed 255 without also changing stat_t typedef
 
-#endif // End of include guard: TINYG2_H_ONCE
+#endif // TINYG2_H_ONCE
index 62270e9f6ebb9655cf30ca898e6cad3acff1136c..a254506a071095874b2a9e3c4e2cf46880e106bf 100644 (file)
@@ -190,7 +190,17 @@ char_t fntoa(char_t *str, float n, uint8_t precision) {
     return 3;
   }
 
-  return (char_t)sprintf((char *)str, "%0.*f", (int)precision, (double)n);
+  switch (precision) {
+  case 0: return (char_t)sprintf((char *)str, "%0.0f", (double)n);
+  case 1: return (char_t)sprintf((char *)str, "%0.1f", (double)n);
+  case 2: return (char_t)sprintf((char *)str, "%0.2f", (double)n);
+  case 3: return (char_t)sprintf((char *)str, "%0.3f", (double)n);
+  case 4: return (char_t)sprintf((char *)str, "%0.4f", (double)n);
+  case 5: return (char_t)sprintf((char *)str, "%0.5f", (double)n);
+  case 6: return (char_t)sprintf((char *)str, "%0.6f", (double)n);
+  case 7: return (char_t)sprintf((char *)str, "%0.7f", (double)n);
+  default: return (char_t)sprintf((char *)str, "%f", (double)n);
+  }
 }