From 46f1cdc34f0ddaea32f52166e57d38e2a85199bf Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Tue, 6 Sep 2016 01:58:34 -0700 Subject: [PATCH] Fixed jogging, AVR state strings are now all caps, Retry i2c on fail --- src/jade/templates/control-view.jade | 20 ++++++++-------- src/js/app.js | 2 +- src/js/control-view.js | 4 ++-- src/py/bbctrl/AVR.py | 36 +++++++++++++++++++++------- src/py/bbctrl/Jog.py | 5 +++- src/py/bbctrl/LCD.py | 8 +++---- src/py/inevent/Event.py | 10 ++++---- src/py/inevent/EventStream.py | 3 +-- src/py/inevent/Format.py | 32 ------------------------- src/py/inevent/InEvent.py | 2 +- 10 files changed, 56 insertions(+), 66 deletions(-) delete mode 100644 src/py/inevent/Format.py diff --git a/src/jade/templates/control-view.jade b/src/jade/templates/control-view.jade index 7c085e1..3ba8b5a 100644 --- a/src/jade/templates/control-view.jade +++ b/src/jade/templates/control-view.jade @@ -75,25 +75,25 @@ script#control-view-template(type="text/x-template") .toolbar button.pure-button(title="Home the machine.", @click="home", - :disabled="state.x != 'ready'") + :disabled="state.x != 'READY'") .fa.fa-home button.pure-button( - title="{{state.x == 'running' ? 'Pause' : 'Start'}} program.", + title="{{state.x == 'RUNNING' ? 'Pause' : 'Start'}} program.", @click="start_pause", - :disabled="state.c == 'homing'") - .fa(:class="state.x == 'running' ? 'fa-pause' : 'fa-play'") + :disabled="state.c == 'HOMING'") + .fa(:class="state.x == 'RUNNING' ? 'fa-pause' : 'fa-play'") button.pure-button(title="Stop program.", @click="stop", - :disabled="state.x == 'ready'") + :disabled="state.x == 'READY'") .fa.fa-stop button.pure-button(title="Pause program at next optional stop (M1).", - @click="optional_pause", :disabled="state.c == 'homing'") + @click="optional_pause", :disabled="state.c == 'HOMING'") .fa.fa-stop-circle-o button.pure-button(title="Execute one program step.", @click="step", - :disabled="(state.x != 'ready' && state.x != 'holding') || !file") + :disabled="(state.x != 'READY' && state.x != 'HOLDING') || !file") .fa.fa-step-forward .tabs @@ -109,7 +109,7 @@ script#control-view-template(type="text/x-template") section#content1.tab-content .toolbar button.pure-button(title="Upload a new program file.", @click="open", - :disabled="state.x == 'running' || state.x == 'stopping'") + :disabled="state.x == 'RUNNING' || state.x == 'STOPPING'") .fa.fa-folder-open input.gcode-file-input(type="file", @change="upload", @@ -121,7 +121,7 @@ script#control-view-template(type="text/x-template") select(title="Select previously uploaded program files.", v-model="file", @change="load", - :disabled="state.x == 'running' || state.x == 'stopping'") + :disabled="state.x == 'RUNNING' || state.x == 'STOPPING'") option(v-for="file in files", :value="file") {{file}} .gcode(:class="{placeholder: !gcode}") @@ -132,7 +132,7 @@ script#control-view-template(type="text/x-template") fieldset button.pure-button.pure-button-primary( title="Manually execute instructions.", @click="submit_mdi", - :disabled="state.x != 'ready'") MDI + :disabled="state.x != 'READY'") MDI input(v-model="mdi", @keyup.enter="submit_mdi") .history(:class="{placeholder: !history}") diff --git a/src/js/app.js b/src/js/app.js index c92cd4b..c676bca 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -58,7 +58,7 @@ module.exports = new Vue({ methods: { estop: function () { - if (this.state.x == 'estopped') api.put('clear'); + if (this.state.x == 'ESTOPPED') api.put('clear'); else api.put('estop'); }, diff --git a/src/js/control-view.js b/src/js/control-view.js index 3337c29..f958b0a 100644 --- a/src/js/control-view.js +++ b/src/js/control-view.js @@ -137,9 +137,9 @@ module.exports = { start_pause: function () { - if (this.state.x == 'running') this.pause(); + if (this.state.x == 'RUNNING') this.pause(); - else if (this.state.x == 'stopping' || this.state.x == 'holding') + else if (this.state.x == 'STOPPING' || this.state.x == 'HOLDING') this.unpause(); else this.start(); diff --git a/src/py/bbctrl/AVR.py b/src/py/bbctrl/AVR.py index 4e9bc52..cb4a799 100644 --- a/src/py/bbctrl/AVR.py +++ b/src/py/bbctrl/AVR.py @@ -1,6 +1,7 @@ import re import serial import json +import time import logging from collections import deque @@ -44,10 +45,12 @@ class AVR(): self.sp.nonblocking() except Exception as e: + self.sp = None log.warning('Failed to open serial port: %s', e) - return - ctrl.ioloop.add_handler(self.sp, self.serial_handler, ctrl.ioloop.READ) + if self.sp is not None: + ctrl.ioloop.add_handler(self.sp, self.serial_handler, + ctrl.ioloop.READ) try: self.i2c_bus = smbus.SMBus(ctrl.args.avr_port) @@ -75,13 +78,29 @@ class AVR(): def _i2c_command(self, cmd, word = None): - if not hasattr(self, 'i2c_bus'): return + if self.i2c_bus is None: return log.info('I2C: %d' % cmd) + retry = 5 - if word is not None: - self.i2c_bus.write_word_data(self.i2c_addr, cmd, word) - self.i2c_bus.write_byte(self.i2c_addr, cmd) + while True: + try: + if word is not None: + self.i2c_bus.write_word_data(self.i2c_addr, cmd, word) + self.i2c_bus.write_byte(self.i2c_addr, cmd) + break + + except IOError as e: + retry -= 1 + + if retry: + log.error('I2C communication failed, retrying: %s' % e) + self.i2c_bus.close() + time.sleep(0.1) + self.i2c_bus = smbus.SMBus(self.ctrl.args.avr_port) + continue + + else: raise e def report(self): self._i2c_command(I2C_REPORT) @@ -93,7 +112,7 @@ class AVR(): def set_write(self, enable): - if not hasattr(self, 'sp'): return + if self.sp is None: return flags = self.ctrl.ioloop.READ if enable: flags |= self.ctrl.ioloop.WRITE @@ -157,13 +176,14 @@ class AVR(): except Exception as e: log.error('%s, data: %s', e, line) + return if 'firmware' in msg: log.error('AVR rebooted') self._stop_sending_gcode() self.report() - if 'x' in msg and msg['x'] == 'estopped': + if 'x' in msg and msg['x'] == 'ESTOPPED': self._stop_sending_gcode() self.vars.update(msg) diff --git a/src/py/bbctrl/Jog.py b/src/py/bbctrl/Jog.py index 6ca5db6..f4c48a6 100644 --- a/src/py/bbctrl/Jog.py +++ b/src/py/bbctrl/Jog.py @@ -19,16 +19,19 @@ class Jog(inevent.JogHandler): self.v = [0.0] * 4 self.lastV = self.v + self.callback() self.processor = inevent.InEvent(ctrl.ioloop, self, types = "js kbd".split()) - def processed_events(self): + def callback(self): if self.v != self.lastV: self.lastV = self.v self.ctrl.avr.jog(self.v) + self.ctrl.ioloop.call_later(0.25, self.callback) + def changed(self): if self.speed == 1: scale = 1.0 / 128.0 diff --git a/src/py/bbctrl/LCD.py b/src/py/bbctrl/LCD.py index bc4e80f..1209e7f 100644 --- a/src/py/bbctrl/LCD.py +++ b/src/py/bbctrl/LCD.py @@ -15,17 +15,17 @@ class LCD: if has('x') or has('c'): v = self.ctrl.avr.vars - state = v.get('x', 'init') - if 'c' in v and state == 'running': state = v['c'] + state = v.get('x', 'INIT') + if 'c' in v and state == 'RUNNING': state = v['c'] - self.lcd.text('%-9s' % state.upper(), 0, 0) + self.lcd.text('%-9s' % state, 0, 0) if has('xp'): self.lcd.text('% 10.4fX' % msg['xp'], 9, 0) if has('yp'): self.lcd.text('% 10.4fY' % msg['yp'], 9, 1) if has('zp'): self.lcd.text('% 10.4fZ' % msg['zp'], 9, 2) if has('ap'): self.lcd.text('% 10.4fA' % msg['ap'], 9, 3) if has('t'): self.lcd.text('%2uT' % msg['t'], 6, 1) - if has('u'): self.lcd.text('%s' % msg['u'].upper(), 0, 1) + if has('u'): self.lcd.text('%s' % msg['u'], 0, 1) if has('f'): self.lcd.text('%8uF' % msg['f'], 0, 2) if has('s'): self.lcd.text('%8dS' % msg['s'], 0, 3) diff --git a/src/py/inevent/Event.py b/src/py/inevent/Event.py index c14e9d4..336ceb4 100644 --- a/src/py/inevent/Event.py +++ b/src/py/inevent/Event.py @@ -28,10 +28,12 @@ import struct -from inevent import Format from inevent.Constants import * +_format = 'llHHi' +size = struct.calcsize(_format) + class Event(object): """ @@ -97,8 +99,7 @@ class Event(object): tint = long(self.time) tfrac = long((self.time - tint) * 1000000) - return \ - struct.pack(Format.Event, tsec, tfrac, self.type, self.code, self.value) + return struct.pack(_format, tsec, tfrac, self.type, self.code, self.value) def decode(self, s): @@ -109,7 +110,6 @@ class Event(object): *s* A binary structure packed into a string. """ - tsec, tfrac, self.type, self.code, self.value = \ - struct.unpack(Format.Event, s) + tsec, tfrac, self.type, self.code, self.value = struct.unpack(_format, s) self.time = tsec + tfrac / 1000000.0 diff --git a/src/py/inevent/EventStream.py b/src/py/inevent/EventStream.py index 408e5ec..3a4cf6b 100644 --- a/src/py/inevent/EventStream.py +++ b/src/py/inevent/EventStream.py @@ -34,7 +34,6 @@ from inevent.Constants import * from inevent import ioctl from inevent.AbsAxisScaling import AbsAxisScaling from inevent import Event -from inevent import Format from inevent.EventState import EventState @@ -155,7 +154,7 @@ class EventStream(object): Read and return the next waiting event. """ try: - s = os.read(self.filehandle, Format.EventSize) + s = os.read(self.filehandle, Event.size) if s: event = Event.Event(self) event.decode(s) diff --git a/src/py/inevent/Format.py b/src/py/inevent/Format.py deleted file mode 100644 index d91665e..0000000 --- a/src/py/inevent/Format.py +++ /dev/null @@ -1,32 +0,0 @@ -# The inevent Python module was adapted from pi3d.event from the pi3d -# project. -# -# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC. -# Copyright (c) 2015, Tim Skillman. -# Copyright (c) 2015, Paddy Gaunt. -# Copyright (c) 2015, Tom Ritchford. -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 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. - -import struct - -Event = 'llHHi' -EventSize = struct.calcsize(Event) diff --git a/src/py/inevent/InEvent.py b/src/py/inevent/InEvent.py index c98ae24..261a5d6 100644 --- a/src/py/inevent/InEvent.py +++ b/src/py/inevent/InEvent.py @@ -157,7 +157,7 @@ class InEvent(object): for stream in self.streams: if stream.filehandle == fd: while True: - event = stream.read() + event = stream.next() if event: self.handler.event(event, self.cb) else: break -- 2.27.0