Added non-Sockjs websocket support, don't jog disabled axes, save and restore gcode...
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Sun, 14 May 2017 22:48:39 +0000 (15:48 -0700)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Sun, 14 May 2017 22:48:39 +0000 (15:48 -0700)
13 files changed:
avr/src/command.c
avr/src/gcode_state.c
avr/src/gcode_state.h
avr/src/machine.c
avr/src/machine.h
avr/src/plan/jog.c
avr/src/varcb.c
avr/src/vars.c
avr/src/vars.def
src/js/app.js
src/py/bbctrl/AVR.py
src/py/bbctrl/LCD.py
src/py/bbctrl/Web.py

index 1df7e56ded048d748aa8fe26579c61e4c6c5cf52..4c4f14f0208f7025284797d5772391b6e7d83d3f 100644 (file)
@@ -170,6 +170,48 @@ int command_exec(int argc, char *argv[]) {
 }
 
 
+char *_parse_arg(char **p) {
+  char *start = *p;
+  char *next = *p;
+
+  bool inQuote = false;
+  bool escape = false;
+
+  while (**p) {
+    char c = *(*p)++;
+
+    switch (c) {
+    case '\\':
+      if (!escape) {
+        escape = true;
+        continue;
+      }
+      break;
+
+    case ' ': case '\t':
+      if (!inQuote && !escape) goto done;
+      break;
+
+    case '"':
+      if (!escape) {
+        inQuote = !inQuote;
+        continue;
+      }
+      break;
+
+    default: break;
+    }
+
+    *next++ = c;
+    escape = false;
+  }
+
+ done:
+  *next = 0;
+  return start;
+}
+
+
 int command_parser(char *cmd) {
   // Parse line
   char *p = cmd + 1; // Skip `$`
@@ -186,10 +228,8 @@ int command_parser(char *cmd) {
     while (*p && isspace(*p)) *p++ = 0;
 
     // Start of token
-    if (*p) argv[argc++] = p;
-
-    // Find end
-    while (*p && !isspace(*p)) p++;
+    char *arg = _parse_arg(&p);
+    if (*arg) argv[argc++] = arg;
   }
 
   // Exec command
index 2a005557c702fec81946abd43f544870bc5e3017..7807e5615d1dc710e310a0fd3e6f258adbafd3fa 100644 (file)
 #include "gcode_state.h"
 
 
+static const char INVALID_PGMSTR[] PROGMEM = "INVALID";
+
+static const char INCHES_PGMSTR[]      PROGMEM = "IN";
+static const char MILLIMETERS_PGMSTR[] PROGMEM = "MM";
+static const char DEGREES_PGMSTR[]     PROGMEM = "DEG";
+
+static const char INVERSE_TIME_MODE_PGMSTR[] PROGMEM         = "INVERSE TIME";
+static const char UNITS_PER_MINUTE_MODE_PGMSTR[] PROGMEM     = "PER MIN";
+static const char UNITS_PER_REVOLUTION_MODE_PGMSTR[] PROGMEM = "PER REV";
+
+static const char PLANE_XY_PGMSTR[] PROGMEM = "XY";
+static const char PLANE_XZ_PGMSTR[] PROGMEM = "XZ";
+static const char PLANE_YZ_PGMSTR[] PROGMEM = "YZ";
+
+static const char ABSOLUTE_COORDS_PGMSTR[] PROGMEM = "ABS";
+static const char G54_PGMSTR[] PROGMEM = "G54";
+static const char G55_PGMSTR[] PROGMEM = "G55";
+static const char G56_PGMSTR[] PROGMEM = "G56";
+static const char G57_PGMSTR[] PROGMEM = "G57";
+static const char G58_PGMSTR[] PROGMEM = "G58";
+static const char G59_PGMSTR[] PROGMEM = "G59";
+
+static const char PATH_EXACT_PATH_PGMSTR[] PROGMEM = "EXACT PATH";
+static const char PATH_EXACT_STOP_PGMSTR[] PROGMEM = "EXACT STOP";
+static const char PATH_CONTINUOUS_PGMSTR[] PROGMEM = "CONTINUOUS";
+
+static const char ABSOLUTE_MODE_PGMSTR[] PROGMEM    = "ABSOLUTE";
+static const char INCREMENTAL_MODE_PGMSTR[] PROGMEM = "INCREMENTAL";
+
+
 PGM_P gs_get_units_pgmstr(units_t mode) {
   switch (mode) {
-  case INCHES:      return PSTR("IN");
-  case MILLIMETERS: return PSTR("MM");
-  case DEGREES:     return PSTR("DEG");
+  case INCHES:      return INCHES_PGMSTR;
+  case MILLIMETERS: return MILLIMETERS_PGMSTR;
+  case DEGREES:     return DEGREES_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+units_t gs_parse_units(const char *s) {
+  if (!strcmp_P(s, INCHES_PGMSTR)) return INCHES;
+  if (!strcmp_P(s, MILLIMETERS_PGMSTR)) return MILLIMETERS;
+  if (!strcmp_P(s, DEGREES_PGMSTR)) return DEGREES;
+  return -1;
 }
 
 
 PGM_P gs_get_feed_mode_pgmstr(feed_mode_t mode) {
   switch (mode) {
-  case INVERSE_TIME_MODE:         return PSTR("INVERSE TIME");
-  case UNITS_PER_MINUTE_MODE:     return PSTR("PER MIN");
-  case UNITS_PER_REVOLUTION_MODE: return PSTR("PER REV");
+  case INVERSE_TIME_MODE:         return INVERSE_TIME_MODE_PGMSTR;
+  case UNITS_PER_MINUTE_MODE:     return UNITS_PER_MINUTE_MODE_PGMSTR;
+  case UNITS_PER_REVOLUTION_MODE: return UNITS_PER_REVOLUTION_MODE_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+feed_mode_t gs_parse_feed_mode(const char *s) {
+  if (!strcmp_P(s, INVERSE_TIME_MODE_PGMSTR)) return INVERSE_TIME_MODE;
+  if (!strcmp_P(s, UNITS_PER_MINUTE_MODE_PGMSTR)) return UNITS_PER_MINUTE_MODE;
+  if (!strcmp_P(s, UNITS_PER_REVOLUTION_MODE_PGMSTR))
+    return UNITS_PER_REVOLUTION_MODE;
+  return -1;
 }
 
 
 PGM_P gs_get_plane_pgmstr(plane_t plane) {
   switch (plane) {
-  case PLANE_XY: return PSTR("XY");
-  case PLANE_XZ: return PSTR("XZ");
-  case PLANE_YZ: return PSTR("YZ");
+  case PLANE_XY: return PLANE_XY_PGMSTR;
+  case PLANE_XZ: return PLANE_XZ_PGMSTR;
+  case PLANE_YZ: return PLANE_YZ_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+plane_t gs_parse_plane(const char *s) {
+  if (!strcmp_P(s, PLANE_XY_PGMSTR)) return PLANE_XY;
+  if (!strcmp_P(s, PLANE_XZ_PGMSTR)) return PLANE_XZ;
+  if (!strcmp_P(s, PLANE_YZ_PGMSTR)) return PLANE_YZ;
+  return -1;
 }
 
 
 PGM_P gs_get_coord_system_pgmstr(coord_system_t cs) {
   switch (cs) {
-  case ABSOLUTE_COORDS: return PSTR("ABS");
-  case G54: return PSTR("G54");
-  case G55: return PSTR("G55");
-  case G56: return PSTR("G56");
-  case G57: return PSTR("G57");
-  case G58: return PSTR("G58");
-  case G59: return PSTR("G59");
+  case ABSOLUTE_COORDS: return ABSOLUTE_COORDS_PGMSTR;
+  case G54: return G54_PGMSTR;
+  case G55: return G55_PGMSTR;
+  case G56: return G56_PGMSTR;
+  case G57: return G57_PGMSTR;
+  case G58: return G58_PGMSTR;
+  case G59: return G59_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+coord_system_t gs_parse_coord_system(const char *s) {
+  if (!strcmp_P(s, ABSOLUTE_COORDS_PGMSTR)) return ABSOLUTE_COORDS;
+  if (!strcmp_P(s, G54_PGMSTR)) return G54;
+  if (!strcmp_P(s, G55_PGMSTR)) return G55;
+  if (!strcmp_P(s, G56_PGMSTR)) return G56;
+  if (!strcmp_P(s, G57_PGMSTR)) return G57;
+  if (!strcmp_P(s, G58_PGMSTR)) return G58;
+  if (!strcmp_P(s, G59_PGMSTR)) return G59;
+  return -1;
 }
 
 
 PGM_P gs_get_path_mode_pgmstr(path_mode_t mode) {
   switch (mode) {
-  case PATH_EXACT_PATH: return PSTR("EXACT PATH");
-  case PATH_EXACT_STOP: return PSTR("EXACT STOP");
-  case PATH_CONTINUOUS: return PSTR("CONTINUOUS");
+  case PATH_EXACT_PATH: return PATH_EXACT_PATH_PGMSTR;
+  case PATH_EXACT_STOP: return PATH_EXACT_STOP_PGMSTR;
+  case PATH_CONTINUOUS: return PATH_CONTINUOUS_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+path_mode_t gs_parse_path_mode(const char *s) {
+  if (!strcmp_P(s, PATH_EXACT_PATH_PGMSTR)) return PATH_EXACT_PATH;
+  if (!strcmp_P(s, PATH_EXACT_STOP_PGMSTR)) return PATH_EXACT_STOP;
+  if (!strcmp_P(s, PATH_CONTINUOUS_PGMSTR)) return PATH_CONTINUOUS;
+  return -1;
 }
 
 
 PGM_P gs_get_distance_mode_pgmstr(distance_mode_t mode) {
   switch (mode) {
-  case ABSOLUTE_MODE:    return PSTR("ABSOLUTE");
-  case INCREMENTAL_MODE: return PSTR("INCREMENTAL");
+  case ABSOLUTE_MODE:    return ABSOLUTE_MODE_PGMSTR;
+  case INCREMENTAL_MODE: return INCREMENTAL_MODE_PGMSTR;
   }
 
-  return PSTR("INVALID");
+  return INVALID_PGMSTR;
+}
+
+
+distance_mode_t gs_parse_distance_mode(const char *s) {
+  if (!strcmp_P(s, ABSOLUTE_MODE_PGMSTR)) return ABSOLUTE_MODE;
+  if (!strcmp_P(s, INCREMENTAL_MODE_PGMSTR)) return INCREMENTAL_MODE;
+  return -1;
 }
index 8e154165f0c8132f4837bcbfdfe225c0b7da9430..214469be55cd044a157fd5fe095af0f0a6d02a69 100644 (file)
@@ -189,8 +189,14 @@ typedef struct {
 
 
 PGM_P gs_get_units_pgmstr(units_t mode);
+units_t gs_parse_units(const char *units);
 PGM_P gs_get_feed_mode_pgmstr(feed_mode_t mode);
+feed_mode_t gs_parse_feed_mode(const char *mode);
 PGM_P gs_get_plane_pgmstr(plane_t plane);
+plane_t gs_parse_plane(const char *plane);
 PGM_P gs_get_coord_system_pgmstr(coord_system_t cs);
+coord_system_t gs_parse_coord_system(const char *cs);
 PGM_P gs_get_path_mode_pgmstr(path_mode_t mode);
+path_mode_t gs_parse_path_mode(const char *mode);
 PGM_P gs_get_distance_mode_pgmstr(distance_mode_t mode);
+distance_mode_t gs_parse_distance_mode(const char *mode);
index dae65272b62b8b3f574f1ba27a00e7c17e82f1aa..bf8a4fc4924f97806deddfb1ed4277417370cb45 100644 (file)
@@ -366,22 +366,26 @@ void machine_init() {
 // These functions assume input validation occurred upstream.
 
 /// G17, G18, G19 select axis plane
-void mach_set_plane(plane_t plane) {mach.gm.plane = plane;}
+void mach_set_plane(plane_t plane) {
+  if (plane != (plane_t)-1) mach.gm.plane = plane;
+}
 
 
 /// G20, G21
-void mach_set_units(units_t mode) {mach.gm.units = mode;}
+void mach_set_units(units_t mode) {
+  if (mode != (units_t)-1) mach.gm.units = mode;
+}
 
 
 /// G90, G91
 void mach_set_distance_mode(distance_mode_t mode) {
-  mach.gm.distance_mode = mode;
+  if (mode != (distance_mode_t)-1) mach.gm.distance_mode = mode;
 }
 
 
 /// G90.1, G91.1
 void mach_set_arc_distance_mode(distance_mode_t mode) {
-  mach.gm.arc_distance_mode = mode;
+  if (mode != (distance_mode_t)-1) mach.gm.arc_distance_mode = mode;
 }
 
 
@@ -400,8 +404,8 @@ void mach_set_coord_offsets(coord_system_t coord_system, float offset[],
 
 
 /// G54-G59
-void mach_set_coord_system(coord_system_t coord_system) {
-  mach.gm.coord_system = coord_system;
+void mach_set_coord_system(coord_system_t cs) {
+  if (cs != (coord_system_t)-1) mach.gm.coord_system = cs;
 }
 
 
@@ -614,7 +618,7 @@ void mach_set_feed_rate(float feed_rate) {
 
 /// G93, G94
 void mach_set_feed_mode(feed_mode_t mode) {
-  if (mach.gm.feed_mode == mode) return;
+  if (mode == (feed_mode_t)-1 || mach.gm.feed_mode == mode) return;
   mach.gm.feed_rate = 0; // Force setting feed rate after changing modes
   mach.gm.feed_mode = mode;
 }
@@ -622,7 +626,7 @@ void mach_set_feed_mode(feed_mode_t mode) {
 
 /// G61, G61.1, G64
 void mach_set_path_mode(path_mode_t mode) {
-  mach.gm.path_mode = mode;
+  if (mode != (path_mode_t)-1) mach.gm.path_mode = mode;
 }
 
 
@@ -705,6 +709,18 @@ void mach_flood_coolant_control(bool flood_coolant) {
  * http://www.linuxcnc.org/docs/2.4/html/gcode_main.html#sec:M50:-Feed-Override
  */
 
+void mach_set_feed_override(float value) {
+  mach.gm.feed_override = value;
+  mach.gm.feed_override_enable = !fp_ZERO(value);
+}
+
+
+void mach_set_spindle_override(float value) {
+  mach.gm.spindle_override = value;
+  mach.gm.spindle_override_enable = !fp_ZERO(value);
+}
+
+
 /// M48, M49
 void mach_override_enables(bool flag) {
   mach.gm.feed_override_enable = flag;
index ba8591b6264980d71fc80456d77c4d5b19b28f53..d3b09a26ea755d7ab59195c2d9b031a8139fbf7b 100644 (file)
@@ -123,6 +123,8 @@ void mach_change_tool(bool x);
 void mach_mist_coolant_control(bool mist_coolant);
 void mach_flood_coolant_control(bool flood_coolant);
 
+void mach_set_feed_override(float override);
+void mach_set_spindle_override(float override);
 void mach_override_enables(bool flag);
 void mach_feed_override_enable(bool flag);
 void mach_spindle_override_enable(bool flag);
index af5a8af057c26d19e0f93b3ab441c9f976dbd9f3..e2a968262eb8aa3318b649846a9b0ba0a5b057cc 100644 (file)
@@ -68,6 +68,8 @@ static stat_t _exec_jog(mp_buffer_t *bf) {
   bool done = true;
   if (!jr.writing)
     for (int axis = 0; axis < AXES; axis++) {
+      if (!axis_is_enabled(axis)) continue;
+
       float Vn = jr.next_velocity[axis] * axis_get_velocity_max(axis);
       float Vi = jr.velocity[axis];
       float Vt = jr.target_velocity[axis];
@@ -90,6 +92,8 @@ static stat_t _exec_jog(mp_buffer_t *bf) {
 
   // Compute per axis velocities
   for (int axis = 0; axis < AXES; axis++) {
+    if (!axis_is_enabled(axis)) continue;
+
     float V = fabs(jr.velocity[axis]);
     float Vt = fabs(jr.target_velocity[axis]);
 
index cb3a076166fce8b1df29cc3b6975d34b0d2e36ee..ecbd56af3b4cd854986e92ea812a70f3c6bd8be9 100644 (file)
@@ -42,19 +42,13 @@ void set_position(int axis, float position) {
 }
 
 
-// GCode
+// GCode getters
 int32_t get_line() {return mp_runtime_get_line();}
 PGM_P get_unit() {return gs_get_units_pgmstr(mach_get_units());}
 float get_speed() {return spindle_get_speed();}
 float get_feed() {return mach_get_feed_rate();} // TODO get runtime value
 uint8_t get_tool() {return mp_runtime_get_tool();}
-
-
-PGM_P get_feed_mode() {
-  return gs_get_feed_mode_pgmstr(mach_get_feed_mode());
-}
-
-
+PGM_P get_feed_mode() {return gs_get_feed_mode_pgmstr(mach_get_feed_mode());}
 PGM_P get_plane() {return gs_get_plane_pgmstr(mach_get_plane());}
 
 
@@ -82,6 +76,56 @@ float get_speed_override() {return mach_get_spindle_override();}
 bool get_mist_coolant() {return coolant_get_mist();}
 bool get_flood_coolant() {return coolant_get_flood();}
 
+
+// GCode setters
+void set_unit(const char *units) {mach_set_units(gs_parse_units(units));}
+void set_speed(float speed) {spindle_set_speed(speed);}
+void set_feed(float feed) {mach_set_feed_rate(feed);}
+
+
+void set_tool(uint8_t tool) {
+  mp_runtime_set_tool(tool);
+  mach_select_tool(tool);
+}
+
+
+void set_feed_mode(const char *mode) {
+  mach_set_feed_mode(gs_parse_feed_mode(mode));
+}
+
+
+void set_plane(const char *plane) {mach_set_plane(gs_parse_plane(plane));}
+
+
+void set_coord_system(const char *cs) {
+  mach_set_coord_system(gs_parse_coord_system(cs));
+}
+
+
+void set_abs_override(bool enable) {mach_set_absolute_mode(enable);}
+
+
+void set_path_mode(const char *mode) {
+  mach_set_path_mode(gs_parse_path_mode(mode));
+}
+
+
+void set_distance_mode(const char *mode) {
+  mach_set_distance_mode(gs_parse_distance_mode(mode));
+}
+
+
+void set_arc_dist_mode(const char *mode) {
+  mach_set_arc_distance_mode(gs_parse_distance_mode(mode));
+}
+
+
+void set_feed_override(float value) {mach_set_feed_override(value);}
+void set_speed_override(float value) {mach_set_spindle_override(value);}
+void set_mist_coolant(bool enable) {coolant_set_mist(enable);}
+void set_flood_coolant(bool enable) {coolant_set_flood(enable);}
+
+
 // System
 float get_velocity() {return mp_runtime_get_velocity();}
 bool get_echo() {return usart_is_set(USART_ECHO);}
index d1dfe573f2be99387b7f2d3579d3583e85674bc9..2af5d46b19b0aa5d2bff5d0f0c229d2613035d56 100644 (file)
@@ -72,6 +72,7 @@ static void var_print_string(string s) {printf_P(PSTR("\"%s\""), s);}
 
 // Program string
 static void var_print_pstring(pstring s) {printf_P(PSTR("\"%"PRPSTR"\""), s);}
+static const char *var_parse_pstring(const char *value) {return value;}
 
 
 // Flags
index 763d5d2746979abb325d10428f2797c61c1d4287..15e88a269c83d265525d51a5a3fb2f555771010e 100644 (file)
@@ -100,21 +100,21 @@ VAR(huanyang_connected, he, bool,     0,  0, 1, "Huanyang connected")
 
 // GCode
 VAR(line,           ln, int32_t,  0,      0, 1, "Last GCode line executed")
-VAR(unit,            u, pstring,  0,      0, 1, "Current unit of measure")
-VAR(speed,           s, float,    0,      0, 1, "Current spindle speed")
-VAR(feed,            f, float,    0,      0, 1, "Current feed rate")
-VAR(tool,            t, uint8_t,  0,      0, 1, "Current tool")
-VAR(feed_mode,      fm, pstring,  0,      0, 1, "Current feed rate mode")
-VAR(plane,          pa, pstring,  0,      0, 1, "Current plane")
-VAR(coord_system,   cs, pstring,  0,      0, 1, "Current coordinate system")
-VAR(abs_override,   ao, bool,     0,      0, 1, "Absolute override enabled")
-VAR(path_mode,      pc, pstring,  0,      0, 1, "Current path control mode")
-VAR(distance_mode,  dm, pstring,  0,      0, 1, "Current distance mode")
-VAR(arc_dist_mode,  ad, pstring,  0,      0, 1, "Current arc distance mode")
-VAR(mist_coolant,   mc, bool,     0,      0, 1, "Mist coolant enabled")
-VAR(flood_coolant,  fc, bool,     0,      0, 1, "Flood coolant enabled")
-VAR(feed_override,  fo, float,    0,      0, 1, "Feed rate override")
-VAR(speed_override, so, float,    0,      0, 1, "Spindle speed override")
+VAR(unit,            u, pstring,  0,      1, 1, "Current unit of measure")
+VAR(speed,           s, float,    0,      1, 1, "Current spindle speed")
+VAR(feed,            f, float,    0,      1, 1, "Current feed rate")
+VAR(tool,            t, uint8_t,  0,      1, 1, "Current tool")
+VAR(feed_mode,      fm, pstring,  0,      1, 1, "Current feed rate mode")
+VAR(plane,          pa, pstring,  0,      1, 1, "Current plane")
+VAR(coord_system,   cs, pstring,  0,      1, 1, "Current coordinate system")
+VAR(abs_override,   ao, bool,     0,      1, 1, "Absolute override enabled")
+VAR(path_mode,      pc, pstring,  0,      1, 1, "Current path control mode")
+VAR(distance_mode,  dm, pstring,  0,      1, 1, "Current distance mode")
+VAR(arc_dist_mode,  ad, pstring,  0,      1, 1, "Current arc distance mode")
+VAR(feed_override,  fo, float,    0,      1, 1, "Feed rate override")
+VAR(speed_override, so, float,    0,      1, 1, "Spindle speed override")
+VAR(mist_coolant,   mc, bool,     0,      1, 1, "Mist coolant enabled")
+VAR(flood_coolant,  fc, bool,     0,      1, 1, "Flood coolant enabled")
 
 // System
 VAR(velocity,        v, float,    0,      0, 1, "Current velocity")
index a5092ef32b7228b7758418269e0ab23542631daf..a4fc937d4789f545a78e1b4a890442935f43b19e 100644 (file)
@@ -77,7 +77,7 @@ module.exports = new Vue({
 
 
     connect: function () {
-      this.sock = new Sock('//' + window.location.host + '/ws');
+      this.sock = new Sock('//' + window.location.host + '/sockjs');
 
       this.sock.onmessage = function (e) {
         var msg = e.data;
index 824093bcc54c74e2c8cb35ceebce0cc4be1762c6..a238b5364f15da567ac96807074c0abbe723e3a4 100644 (file)
@@ -30,6 +30,11 @@ I2C_REBOOT         = 10
 I2C_ZERO           = 11
 
 
+machine_state_vars = '''
+  xp yp zp ap bp cp u s f t fm pa cs ao pc dm ad fo so mc fc
+'''.split()
+
+
 class AVR():
     def __init__(self, ctrl):
         self.ctrl = ctrl
@@ -81,6 +86,7 @@ class AVR():
             # Reset AVR communication
             self.stop();
             self.ctrl.config.config_avr()
+            self._restore_machine_state()
             self.report()
 
         except Exception as e:
@@ -121,6 +127,16 @@ class AVR():
                     raise
 
 
+    def _restore_machine_state(self):
+        for var in machine_state_vars:
+            if var in self.vars:
+                value = self.vars[var]
+                if isinstance(value, str): value = '"' + value + '"'
+                if isinstance(value, bool): value = int(value)
+
+                self.queue_command('${}={}'.format(var, value))
+
+
     def report(self): self._i2c_command(I2C_REPORT)
 
 
@@ -157,7 +173,7 @@ class AVR():
             self.command = None
 
         # Load next command from queue
-        if len(self.queue): self.load_next_command(self.queue.pop())
+        if len(self.queue): self.load_next_command(self.queue.popleft())
 
         # Load next GCode command, if running or paused
         elif self.stream is not None:
index ec9eebaefb27e0798289cc7993dd83a132bb1ce2..e3f015d933f9792acdd4791e502e5e2bdd21d482 100644 (file)
@@ -112,12 +112,12 @@ class LCD:
 
             self.text('%-9s' % state, 0, 0)
 
-        if 'xp' in msg: self.text('% 10.4fX' % msg['xp'], 9, 0)
-        if 'yp' in msg: self.text('% 10.4fY' % msg['yp'], 9, 1)
-        if 'zp' in msg: self.text('% 10.4fZ' % msg['zp'], 9, 2)
-        if 'ap' in msg: self.text('% 10.4fA' % msg['ap'], 9, 3)
+        if 'xp' in msg: self.text('% 10.3fX' % msg['xp'], 9, 0)
+        if 'yp' in msg: self.text('% 10.3fY' % msg['yp'], 9, 1)
+        if 'zp' in msg: self.text('% 10.3fZ' % msg['zp'], 9, 2)
+        if 'ap' in msg: self.text('% 10.3fA' % msg['ap'], 9, 3)
         if 't' in msg:  self.text('%2uT'     % msg['t'],  6, 1)
-        if 'u' in msg:  self.text('%s'       % msg['u'],  0, 1)
+        if 'u' in msg:  self.text('%-6s'     % msg['u'],  0, 1)
         if 'f' in msg:  self.text('%8uF'     % msg['f'],  0, 2)
         if 's' in msg:  self.text('%8dS'     % msg['s'],  0, 3)
 
index 001509af16b990ed3c0e2b861a7094bbdfa3b9de..6bcf721818718f0264d5576eee00c58361a28589 100644 (file)
@@ -92,7 +92,38 @@ class OverrideSpeedHandler(bbctrl.APIHandler):
     def put_ok(self, value): self.ctrl.avr.override_speed(float(value))
 
 
-class Connection(sockjs.tornado.SockJSConnection):
+class WSConnection(tornado.websocket.WebSocketHandler):
+    def __init__(self, app, request, **kwargs):
+        super(WSConnection, self).__init__(app, request, **kwargs)
+        self.ctrl = app.ctrl
+        self.timer = None
+
+
+    def heartbeat(self):
+        self.timer = self.ctrl.ioloop.call_later(3, self.heartbeat)
+        self.write_message({'heartbeat': self.count})
+        self.count += 1
+
+
+    def open(self):
+        self.clients = self.ctrl.web.ws_clients
+
+        self.timer = self.ctrl.ioloop.call_later(3, self.heartbeat)
+        self.count = 0;
+
+        self.clients.append(self)
+        self.write_message(self.ctrl.avr.vars)
+
+
+    def on_close(self):
+        if self.timer is not None: self.ctrl.ioloop.remove_timeout(self.timer)
+        self.clients.remove(self)
+
+
+    def on_message(self, msg): pass
+
+
+class SockJSConnection(sockjs.tornado.SockJSConnection):
     def heartbeat(self):
         self.timer = self.ctrl.ioloop.call_later(3, self.heartbeat)
         self.send({'heartbeat': self.count})
@@ -101,7 +132,7 @@ class Connection(sockjs.tornado.SockJSConnection):
 
     def on_open(self, info):
         self.ctrl = self.session.server.ctrl
-        self.clients = self.ctrl.web.clients
+        self.clients = self.ctrl.web.sockjs_clients
 
         self.timer = self.ctrl.ioloop.call_later(3, self.heartbeat)
         self.count = 0;
@@ -128,9 +159,11 @@ class StaticFileHandler(tornado.web.StaticFileHandler):
 class Web(tornado.web.Application):
     def __init__(self, ctrl):
         self.ctrl = ctrl
-        self.clients = []
+        self.ws_clients = []
+        self.sockjs_clients = []
 
         handlers = [
+            (r'/websocket', WSConnection),
             (r'/api/config/load', ConfigLoadHandler),
             (r'/api/config/download', ConfigDownloadHandler),
             (r'/api/config/save', ConfigSaveHandler),
@@ -154,7 +187,7 @@ class Web(tornado.web.Application):
               "default_filename": "index.html"}),
             ]
 
-        router = sockjs.tornado.SockJSRouter(Connection, '/ws')
+        router = sockjs.tornado.SockJSRouter(SockJSConnection, '/sockjs')
         router.ctrl = ctrl
 
         tornado.web.Application.__init__(self, router.urls + handlers)
@@ -171,5 +204,7 @@ class Web(tornado.web.Application):
 
 
     def broadcast(self, msg):
-        if len(self.clients):
-            self.clients[0].broadcast(self.clients, msg)
+        if len(self.sockjs_clients):
+            self.sockjs_clients[0].broadcast(self.sockjs_clients, msg)
+
+        for client in self.ws_clients: client.write_message(msg)