- Fixed zeroing with non-zero offset when unhomed. #211
- Handle file paths uploaded from Windows correctly. #212
- Don't retain estop state through reboot.
+ - Log when RPi gets hot.
+ - Support Modbus multi-write mode.
+ - Added support for Nowforever VFDs.
## v0.4.6
- Fixed a rare ``Negative s-curve time`` error.
version = json.load(f)['version']
if latest_beta.startswith(version + '-rc'):
- print(int(latest_beta[len(version) + 3]) + 1)
+ print(int(latest_beta[len(version) + 3:]) + 1)
else:
print(1)
// Called by exec.c from low-level interrupt
bool command_exec() {
if (!cmd.count) {
- // TODO If MIN_VELOCITY < velocity then we have a potential buffer underrun
cmd.last_empty = rtc_get_time();
- exec_set_velocity(0);
state_idle();
return false;
}
// On restart wait a bit to give queue a chance to fill
- if (!exec_get_velocity() && cmd.count < EXEC_FILL_TARGET &&
+ if (cmd.count < EXEC_FILL_TARGET &&
!rtc_expired(cmd.last_empty + EXEC_DELAY)) return false;
uint8_t *data = command_next();
static bool _driver_fault(drv8711_driver_t *drv) {return drv->flags & 0x1f;}
-static bool _driver_enabled(drv8711_driver_t *drv) {
- return drv->state != DRV8711_DISABLED;
-}
-
-
static bool _driver_active(drv8711_driver_t *drv) {
return drv->state == DRV8711_ACTIVE;
}
static uint16_t _driver_spi_command(drv8711_driver_t *drv) {
- if (!_driver_enabled(drv)) return 0;
-
switch (drv->spi_state) {
case SS_WRITE_OFF: return DRV8711_WRITE(DRV8711_OFF_REG, DRV8711_OFF);
case SS_WRITE_BLANK: return DRV8711_WRITE(DRV8711_BLANK_REG, DRV8711_BLANK);
static spi_state_t _driver_spi_next(drv8711_driver_t *drv) {
- if (!_driver_enabled(drv)) return SS_WRITE_OFF;
-
// Process response
switch (drv->spi_state) {
case SS_READ_OFF:
// NOTE If there is a power fault and the drivers are not powered
// then the status flags will read 0xff but the motor fault line will
// not be asserted. So, fault flags are not valid with out motor fault.
- // A real stall cannot occur if the driver is inactive.
+ // Also, a real stall cannot occur if the driver is inactive.
bool active = _driver_active(drv);
uint8_t mask =
((motor_fault && !drv->reset_flags) ? 0xff : 0) | (active ? 0xc0 : 0);
// EStop on fatal driver faults
if (_driver_fault(drv)) estop_trigger(STAT_MOTOR_FAULT);
-
- // Enable motors when last driver has been fully configured
- if (drv == &drivers[DRIVERS - 1])
- SET_PIN(MOTOR_ENABLE_PIN, !estop_triggered()); // Active high
break;
}
if (spi.advance) {
spi.advance = false;
+ // Handle response and set next state
drv->spi_state = _driver_spi_next(drv);
// Next driver
OUTSET_PIN(SPI_MOSI_PIN); // High
DIRSET_PIN(SPI_MOSI_PIN); // Output
- // Motor enable
- OUTCLR_PIN(MOTOR_ENABLE_PIN); // Lo (disabled)
+ // Motor driver enable
+ OUTSET_PIN(MOTOR_ENABLE_PIN); // Active high
DIRSET_PIN(MOTOR_ENABLE_PIN); // Output
for (int i = 0; i < DRIVERS; i++) {
uint16_t get_driver_flags(int driver) {return drivers[driver].flags;}
-
-
-void print_status_flags(uint16_t flags) {
- bool first = true;
-
- putchar('"');
-
- if (DRV8711_STATUS_OTS_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("temp"));
- first = false;
- }
-
- if (DRV8711_STATUS_AOCP_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("current a"));
- first = false;
- }
-
- if (DRV8711_STATUS_BOCP_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("current b"));
- first = false;
- }
-
- if (DRV8711_STATUS_APDF_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("fault a"));
- first = false;
- }
-
- if (DRV8711_STATUS_BPDF_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("fault b"));
- first = false;
- }
-
- if (DRV8711_STATUS_UVLO_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("uvlo"));
- first = false;
- }
-
- if ((DRV8711_STATUS_STD_bm | DRV8711_STATUS_STDLAT_bm) & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("stall"));
- first = false;
- }
-
- if (DRV8711_COMM_ERROR_bm & flags) {
- if (!first) printf_P(PSTR(", "));
- printf_P(PSTR("comm"));
- first = false;
- }
-
- putchar('"');
-}
-
-
-uint16_t get_status_strings(int driver) {return get_driver_flags(driver);}
bool get_driver_stalled(int driver) {return drivers[driver].stalled;}
uint32_t last_read;
uint8_t retry;
uint8_t status;
+ uint16_t crc_errs;
bool write_ready;
bool response_ready;
bool transmit_complete;
_read_word(state.response + state.response_length - 2, true);
if (computed != expected) {
- char sent[state.command_length * 2 + 1];
- char response[state.response_length * 2 + 1];
- format_hex_buf(sent, state.command, state.command_length);
- format_hex_buf(response, state.response, state.response_length);
-
- STATUS_WARNING(STAT_OK, "modbus: invalid CRC, received=0x%04x "
- "computed=0x%04x sent=0x%s received=0x%s",
- expected, computed, sent, response);
+ if (cfg.debug) {
+ char sent[state.command_length * 2 + 1];
+ char response[state.response_length * 2 + 1];
+ format_hex_buf(sent, state.command, state.command_length);
+ format_hex_buf(response, state.response, state.response_length);
+
+ STATUS_WARNING(STAT_OK, "modbus: invalid CRC, received=0x%04x "
+ "computed=0x%04x sent=0x%s received=0x%s",
+ expected, computed, sent, response);
+ }
+
+ state.crc_errs++;
state.status = MODBUS_CRC;
return false;
}
static void _write_cb(uint8_t func, uint8_t bytes, const uint8_t *data) {
- if (func == MODBUS_WRITE_OUTPUT_REG && bytes == 4 &&
+ if ((func == MODBUS_WRITE_OUTPUT_REG ||
+ func == MODBUS_WRITE_OUTPUT_REGS) && bytes == 4 &&
_read_word(data, false) == state.addr) {
if (state.rw_cb)
state.rw_cb(true, state.addr, _read_word(state.command + 4, false));
}
+void modbus_multi_write(uint16_t addr, uint16_t value, modbus_rw_cb_t cb) {
+ state.rw_cb = cb;
+ state.addr = addr;
+ uint8_t cmd[7];
+ _write_word(cmd, addr, false); // Start address
+ _write_word(cmd + 2, 1, false); // Number of regs
+ cmd[4] = 2; // Number of bytes
+ _write_word(cmd + 5, value, false); // Value
+ modbus_func(MODBUS_WRITE_OUTPUT_REGS, 7, cmd, 4, _write_cb);
+}
+
+
void modbus_callback() {
if (state.transmit_complete) {
state.last_write = rtc_get_time();
// Variable callbacks
-bool get_modbus_debug() {return cfg.debug;}
-void set_modbus_debug(bool value) {cfg.debug = value;}
-uint8_t get_modbus_id() {return cfg.id;}
-void set_modbus_id(uint8_t id) {cfg.id = id;}
-uint8_t get_modbus_baud() {return cfg.baud;}
+bool get_mb_debug() {return cfg.debug;}
+void set_mb_debug(bool value) {cfg.debug = value;}
+uint8_t get_mb_id() {return cfg.id;}
+void set_mb_id(uint8_t id) {cfg.id = id;}
+uint8_t get_mb_baud() {return cfg.baud;}
-void set_modbus_baud(uint8_t baud) {
+void set_mb_baud(uint8_t baud) {
cfg.baud = (baud_t)baud;
usart_set_baud(&RS485_PORT, cfg.baud);
}
-uint8_t get_modbus_parity() {return cfg.parity;}
+uint8_t get_mb_parity() {return cfg.parity;}
-void set_modbus_parity(uint8_t parity) {
+void set_mb_parity(uint8_t parity) {
cfg.parity = (parity_t)parity;
usart_set_parity(&RS485_PORT, cfg.parity);
usart_set_stop(&RS485_PORT, _get_stop());
}
-uint8_t get_modbus_status() {return state.status;}
+uint8_t get_mb_status() {return state.status;}
+uint16_t get_mb_crc_errs() {return state.crc_errs;}
uint8_t receive, modbus_cb_t cb);
void modbus_read(uint16_t addr, uint16_t count, modbus_rw_cb_t cb);
void modbus_write(uint16_t addr, uint16_t value, modbus_rw_cb_t cb);
+void modbus_multi_write(uint16_t addr, uint16_t value, modbus_rw_cb_t cb);
void modbus_callback();
if (m->enabled) {
bool timedout = rtc_expired(m->power_timeout);
- // NOTE, we have ~5ms to enable the motor
+ // NOTE, we have ~5ms to update the driver config
drv8711_set_state(motor, timedout ? DRV8711_IDLE : DRV8711_ACTIVE);
} else drv8711_set_state(motor, DRV8711_DISABLED);
SPINDLE_TYPE_HUANYANG,
SPINDLE_TYPE_CUSTOM,
SPINDLE_TYPE_AC_TECH,
+ SPINDLE_TYPE_NOWFOREVER,
SPINDLE_TYPE_DELTA_VFD015M21A,
SPINDLE_TYPE_YL600,
SPINDLE_TYPE_FR_D700,
float prep_dwell;
power_update_t prep_powers[POWER_MAX_UPDATES];
- uint32_t underflow;
+ uint32_t underrun;
} stepper_t;
switch (status) {
case STAT_NOP: // No move executed, idle
- if (!st.busy) spindle_idle();
+ if (!st.busy) {
+ if (MIN_VELOCITY < exec_get_velocity()) st.underrun++;
+ exec_set_velocity(0); // Velocity is zero if there are no moves
+
+ spindle_idle();
+ }
break;
case STAT_AGAIN: continue; // No command executed, try again
// If the next move is not ready try to load it
if (!st.move_ready) {
- if (exec_get_velocity()) st.underflow++;
_request_exec_move();
_end_move();
tick = 0; // Try again in 1ms
// Var callbacks
-uint32_t get_underflow() {return st.underflow;}
+uint32_t get_underrun() {return st.underrun;}
float get_dwell_time() {
const char *type_parse_pstr(const char *value, stat_t *) {return value;}
-// Flags
-bool type_eq_flags(flags a, flags b) {return a == b;}
-
-
-void type_print_flags(flags x) {
- extern void print_status_flags(flags x);
- print_status_flags(x);
-}
-
-flags type_parse_flags(const char *s, stat_t *) {return 0;} // Not used
-
-
// Float
bool type_eq_f32(float a, float b) {return a == b || (isnan(a) && isnan(b));}
\******************************************************************************/
// TYPE DEF
-TYPEDEF(flags, uint16_t)
TYPEDEF(str, const char *)
TYPEDEF(pstr, PGM_P)
TYPEDEF(f32, float)
VAR(max_soft_limit, tm, f32, MOTORS, 1, 1) // Max soft limit
VAR(homed, h, b8, MOTORS, 1, 1) // Motor homed status
-VAR(active_current, ac, f32, MOTORS, 0, 1) // Motor current now
+VAR(active_current, ac, f32, MOTORS, 0, 0) // Motor current now
VAR(driver_flags, df, u16, MOTORS, 1, 1) // Motor driver flags
-VAR(status_strings, ds, flags, MOTORS, 0, 1) // Motor driver status
-VAR(driver_stalled, sl, b8, MOTORS, 0, 1) // Motor driver status
+VAR(driver_stalled, sl, b8, MOTORS, 0, 0) // Motor driver status
VAR(encoder, en, s32, MOTORS, 0, 0) // Motor encoder
-VAR(error, ee, s32, MOTORS, 0, 1) // Motor position error
+VAR(error, ee, s32, MOTORS, 0, 0) // Motor position error
VAR(motor_fault, fa, b8, 0, 0, 1) // Motor fault status
VAR(pwm_invert, pi, b8, 0, 1, 1) // Inverted spindle PWM
VAR(pwm_min_duty, nd, f32, 0, 1, 1) // Minimum PWM duty cycle
VAR(pwm_max_duty, md, f32, 0, 1, 1) // Maximum PWM duty cycle
-VAR(pwm_duty, pd, f32, 0, 0, 1) // Current PWM duty cycle
-VAR(pwm_freq, sf, f32, 0, 1, 1) // Spindle PWM frequency in Hz
+VAR(pwm_duty, pd, f32, 0, 0, 0) // Current PWM duty cycle
+VAR(pwm_freq, sf, f32, 0, 1, 0) // Spindle PWM frequency in Hz
// Modbus spindle
-VAR(modbus_debug, hb, b8, 0, 1, 1) // Modbus debugging
-VAR(modbus_id, hi, u8, 0, 1, 1) // Modbus ID
-VAR(modbus_baud, mb, u8, 0, 1, 1) // Modbus BAUD rate
-VAR(modbus_parity, ma, u8, 0, 1, 1) // Modbus parity
-VAR(modbus_status, mx, u8, 0, 0, 1) // Modbus status
+VAR(mb_debug, hb, b8, 0, 1, 1) // Modbus debugging
+VAR(mb_id, hi, u8, 0, 1, 1) // Modbus ID
+VAR(mb_baud, mb, u8, 0, 1, 1) // Modbus BAUD rate
+VAR(mb_parity, ma, u8, 0, 1, 1) // Modbus parity
+VAR(mb_status, mx, u8, 0, 0, 1) // Modbus status
+VAR(mb_crc_errs, cr, u16, 0, 0, 1) // Modbus CRC error counter
// VFD spindle
VAR(vfd_max_freq, vf, u16, 0, 1, 1) // VFD maximum frequency
+VAR(vfd_multi_write, mw, b8, 0, 1, 1) // Use Modbus multi write mode
VAR(vfd_status, vs, u16, 0, 0, 1) // VFD status
VAR(vfd_reg_type, vt, u8, VFDREG, 1, 1) // VFD register type
VAR(vfd_reg_addr, va, u16, VFDREG, 1, 1) // VFD register address
VAR(vfd_reg_fails, vr, u8, VFDREG, 1, 1) // VFD register fail count
// Huanyang spindle
-VAR(hy_freq, hz, f32, 0, 0, 1) // Huanyang actual freq
-VAR(hy_current, hc, f32, 0, 0, 1) // Huanyang actual current
-VAR(hy_temp, ht, u16, 0, 0, 1) // Huanyang temperature
+VAR(hy_freq, hz, f32, 0, 0, 0) // Huanyang actual freq
+VAR(hy_current, hc, f32, 0, 0, 0) // Huanyang actual current
+VAR(hy_temp, ht, u16, 0, 0, 0) // Huanyang temperature
VAR(hy_max_freq, hx, f32, 0, 0, 1) // Huanyang max freq
VAR(hy_min_freq, hm, f32, 0, 0, 1) // Huanyang min freq
VAR(hy_rated_rpm, hq, u16, 0, 0, 1) // Huanyang rated RPM
// System
VAR(velocity, v, f32, 0, 0, 1) // Current velocity
-VAR(acceleration, ax, f32, 0, 0, 1) // Current acceleration
-VAR(jerk, j, f32, 0, 0, 1) // Current jerk
+VAR(acceleration, ax, f32, 0, 0, 0) // Current acceleration
+VAR(jerk, j, f32, 0, 0, 0) // Current jerk
VAR(peak_vel, pv, f32, 0, 1, 1) // Peak velocity, set to clear
VAR(peak_accel, pa, f32, 0, 1, 1) // Peak accel, set to clear
VAR(dynamic_power, dp, b8, 0, 1, 1) // Dynamic power
VAR(estop_reason, er, pstr, 0, 0, 1) // Emergency stop reason
VAR(state, xx, pstr, 0, 0, 1) // Machine state
VAR(hold_reason, pr, pstr, 0, 0, 1) // Machine pause reason
-VAR(underflow, un, u32, 0, 0, 1) // Stepper underflow count
+VAR(underrun, un, u32, 0, 0, 1) // Stepper buffer underrun count
VAR(dwell_time, dt, f32, 0, 0, 1) // Dwell timer
};
+const vfd_reg_t nowforever_regs[] PROGMEM = {
+ {REG_MAX_FREQ_READ, 7, 0}, // Max frequency
+ {REG_FREQ_SET, 2305, 0}, // Frequency
+ {REG_STOP_WRITE, 2304, 0}, // Stop drive
+ {REG_FWD_WRITE, 2304, 1}, // Forward
+ {REG_REV_WRITE, 2304, 3}, // Reverse
+ {REG_FREQ_READ, 1282, 0}, // Output freq
+ {REG_STATUS_READ, 768, 0}, // Status
+ {REG_DISABLED},
+};
+
+
const vfd_reg_t delta_vfd015m21a_regs[] PROGMEM = {
{REG_CONNECT_WRITE, 0x2002, 2}, // Reset fault
{REG_MAX_FREQ_READ, 3, 0}, // Max frequency
float power;
uint16_t max_freq;
+ bool user_multi_write;
float actual_power;
uint16_t status;
}
+static bool _use_multi_write() {
+ switch (spindle_get_type()) {
+ case SPINDLE_TYPE_CUSTOM: return vfd.user_multi_write;
+ case SPINDLE_TYPE_NOWFOREVER: return true;
+ default: return false;
+ }
+}
+
+
static bool _exec_command() {
if (vfd.wait) return true;
}
if (read) modbus_read(reg.addr, words, _modbus_cb);
- else if (write) modbus_write(reg.addr, reg.value, _modbus_cb);
+ else if (write) (_use_multi_write() ? modbus_multi_write : modbus_write)
+ (reg.addr, reg.value, _modbus_cb);
else return false;
return true;
switch (spindle_get_type()) {
case SPINDLE_TYPE_CUSTOM: memcpy(regs, custom_regs, sizeof(regs)); break;
- case SPINDLE_TYPE_AC_TECH: _load(ac_tech_regs); break;
- case SPINDLE_TYPE_DELTA_VFD015M21A: _load(delta_vfd015m21a_regs); break;
- case SPINDLE_TYPE_YL600: _load(yl600_regs); break;
- case SPINDLE_TYPE_FR_D700: _load(fr_d700_regs); break;
+ case SPINDLE_TYPE_AC_TECH: _load(ac_tech_regs); break;
+ case SPINDLE_TYPE_NOWFOREVER: _load(nowforever_regs); break;
+ case SPINDLE_TYPE_DELTA_VFD015M21A: _load(delta_vfd015m21a_regs); break;
+ case SPINDLE_TYPE_YL600: _load(yl600_regs); break;
+ case SPINDLE_TYPE_FR_D700: _load(fr_d700_regs); break;
default: break;
}
// Variable callbacks
uint16_t get_vfd_max_freq() {return vfd.max_freq;}
void set_vfd_max_freq(uint16_t max_freq) {vfd.max_freq = max_freq;}
+bool get_vfd_multi_write() {return vfd.user_multi_write;}
+void set_vfd_multi_write(bool value) {vfd.user_multi_write = value;}
uint16_t get_vfd_status() {return vfd.status;}
uint8_t get_vfd_reg_type(int reg) {return regs[reg].type;}
{x: false, y: false, z: false, a: false, b: false, c: false},
axis_position: 0,
jog_adjust: 100,
- video_url: '/api/video?nocache=' + Math.random(),
deleteGCode: false,
tab: 'auto'
}
},
+ show_modbus_field: function (key) {
+ return key != 'regs' &&
+ (key != 'multi-write' || this.tool_type == 'CUSTOM MODBUS VFD');
+ },
+
+
read: function (e) {
e.preventDefault();
api.put('modbus/read', {address: this.address});
tt {{modbus_status}}
templated-input(v-for="templ in template['modbus-spindle']",
:name="$key", :model.sync="config['modbus-spindle'][$key]",
- :template="templ", v-if="$key != 'regs'")
+ :template="templ", v-if="show_modbus_field($key)")
fieldset.modbus-program(
v-if="is_modbus && this.tool_type != 'HUANYANG VFD'")
import serial
import time
import traceback
+import ctypes
import bbctrl
import bbctrl.Cmd as Cmd
+class serial_struct(ctypes.Structure):
+ _fields_ = [
+ ('type', ctypes.c_int),
+ ('line', ctypes.c_int),
+ ('port', ctypes.c_uint),
+ ('irq', ctypes.c_int),
+ ('flags', ctypes.c_int),
+ ('xmit_fifo_size', ctypes.c_int),
+ ('custom_divisor', ctypes.c_int),
+ ('baud_base', ctypes.c_int),
+ ('close_delay', ctypes.c_ushort),
+ ('io_type', ctypes.c_byte),
+ ('reserved', ctypes.c_byte),
+ ('hub6', ctypes.c_int),
+ ('closing_wait', ctypes.c_ushort),
+ ('closing_wait2', ctypes.c_ushort),
+ ('iomem_base', ctypes.c_char_p),
+ ('iomem_reg_shift', ctypes.c_ushort),
+ ('port_high', ctypes.c_uint),
+ ('iomap_base', ctypes.c_ulong),
+ ]
+
+
+def serial_set_low_latency(sp):
+ import fcntl
+ import termios
+
+ ASYNCB_LOW_LATENCY = 13
+
+ ss = serial_struct()
+ fcntl.ioctl(sp, termios.TIOCGSERIAL, ss)
+ ss.flags |= 1 << ASYNCB_LOW_LATENCY
+ fcntl.ioctl(sp, termios.TIOCSSERIAL, ss)
+
class AVR(object):
def __init__(self, ctrl):
self.sp = serial.Serial(self.ctrl.args.serial, self.ctrl.args.baud,
rtscts = 1, timeout = 0, write_timeout = 0)
self.sp.nonblocking()
+ serial_set_low_latency(self.sp)
except Exception as e:
self.sp = None
import pyudev
import base64
import socket
+import ctypes
from tornado import gen, web, iostream
import bbctrl
import bbctrl.v4l2 as v4l2
-def array_to_string(a): return ''.join([chr(i) for i in a])
+def array_to_string(a):
+ def until_zero(a):
+ for c in a:
+ if c == 0: return
+ yield c
+
+ return ''.join([chr(i) for i in until_zero(a)])
def fourcc_to_string(i):
else:
for line in sys.stdin:
- decode_and_print(line)
+ decode_and_print(str(line).strip())
import bbctrl.Cmd as Cmd
+# Must be kept in sync with drv8711.h
+DRV8711_STATUS_OTS_bm = 1 << 0
+DRV8711_STATUS_AOCP_bm = 1 << 1
+DRV8711_STATUS_BOCP_bm = 1 << 2
+DRV8711_STATUS_APDF_bm = 1 << 3
+DRV8711_STATUS_BPDF_bm = 1 << 4
+DRV8711_STATUS_UVLO_bm = 1 << 5
+DRV8711_STATUS_STD_bm = 1 << 6
+DRV8711_STATUS_STDLAT_bm = 1 << 7
+DRV8711_COMM_ERROR_bm = 1 << 8
+
+# Ignoring stall and stall latch flags for now
+DRV8711_MASK = ~(DRV8711_STATUS_STD_bm | DRV8711_STATUS_STDLAT_bm)
+
+
+def _driver_flags_to_string(flags):
+ if DRV8711_STATUS_OTS_bm & flags: yield 'over temp'
+ if DRV8711_STATUS_AOCP_bm & flags: yield 'over current a'
+ if DRV8711_STATUS_BOCP_bm & flags: yield 'over current b'
+ if DRV8711_STATUS_APDF_bm & flags: yield 'driver fault a'
+ if DRV8711_STATUS_BPDF_bm & flags: yield 'driver fault b'
+ if DRV8711_STATUS_UVLO_bm & flags: yield 'undervoltage'
+ if DRV8711_STATUS_STD_bm & flags: yield 'stall'
+ if DRV8711_STATUS_STDLAT_bm & flags: yield 'stall latch'
+ if DRV8711_COMM_ERROR_bm & flags: yield 'comm error'
+
+
+def driver_flags_to_string(flags):
+ return ', '.join(_driver_flags_to_string(flags))
+
+
class Comm(object):
def __init__(self, ctrl, avr):
self.ctrl = ctrl
self.queue = deque()
self.in_buf = ''
self.command = None
+ self.last_motor_flags = [0] * 4
avr.set_handlers(self._read, self._write)
self.flush()
- def _write(self, write):
+ def _write(self, write_cb):
# Finish writing current command
if self.command is not None:
try:
- count = write(self.command)
+ count = write_cb(self.command)
except Exception as e:
self.command = None
self.comm_error()
+ def _log_motor_flags(self, update):
+ for motor in range(3):
+ var = '%ddf' % motor
+
+ if var in update:
+ flags = update[var] & DRV8711_MASK
+
+ if self.last_motor_flags[motor] == flags: continue
+ self.last_motor_flags[motor] = flags
+
+ flags = driver_flags_to_string(flags)
+ self.log.info('Motor %d flags: %s' % (motor, flags))
+
+
+ def _update_state(self, update):
+ self.ctrl.state.update(update)
+
+ if 'xx' in update: # State change
+ self.ctrl.ready() # We've received data from AVR
+ self.flush() # May have more data to send now
+
+ self._log_motor_flags(update)
+
+
def _read(self, data):
self.in_buf += data.decode('utf-8')
self.log.info('AVR firmware rebooted')
self.connect()
- else:
- self.ctrl.state.update(msg)
- if 'xx' in msg: # State change
- self.ctrl.ready() # We've received data from AVR
- self.flush() # May have more data to send now
+ else: self._update_state(msg)
def estop(self):
################################################################################
import os
+import time
import bbctrl
self.args = args
self.ioloop = bbctrl.IOLoop(ioloop)
self.id = id
- self.timeout = None
+ self.timeout = None # Used in demo mode
+ self.last_temp_warn = 0
+ self.temp_thresh = 80
if id and not os.path.exists(id): os.mkdir(id)
self.lcd.add_new_page(bbctrl.MainLCDPage(self))
self.lcd.add_new_page(bbctrl.IPLCDPage(self.lcd))
+ if not args.demo: self.check_temp()
+
except Exception: self.log.get('Ctrl').exception()
self.timeout = self.ioloop.call_later(t, cb, *args, **kwargs)
+ def check_temp(self):
+ with open('/sys/class/thermal/thermal_zone0/temp', 'r') as f:
+ temp = round(int(f.read()) / 1000)
+
+ # Reset temperature warning threshold after timeout
+ if time.time() < self.last_temp_warn + 60: self.temp_thresh = 80
+
+ if self.temp_thresh < temp:
+ self.last_temp_warn = time.time()
+ self.temp_thresh = temp
+
+ log = self.log.get('Ctrl')
+ log.info('Hot RaspberryPi at %d°C' % temp)
+
+ self.ioloop.call_later(15, self.check_temp)
+
+
def get_path(self, dir = None, filename = None):
path = './' + self.id if self.id else '.'
path = path if dir is None else (path + '/' + dir)
self.cmdq.enqueue(id, self.ctrl.log.broadcast, msg)
if name in ['line', 'tool']: self._enqueue_set_cmd(id, name, value)
- if name == 'speed': return Cmd.speed(value)
+
+ if name == 'speed':
+ self._enqueue_set_cmd(id, name, value)
+ return Cmd.speed(value)
if len(name) and name[0] == '_':
# Don't queue axis positions, can be triggered by new position
check_add_basename(path + '.1')
check_add_basename(path + '.2')
check_add_basename(path + '.3')
+ check_add_basename('/var/log/syslog')
check_add('config.json')
check_add(ctrl.get_upload(ctrl.state.get('selected', '')))
else: log = self.get_ctrl().log
self.camera = bbctrl.Camera(ioloop, args, log)
-
handlers = [
(r'/websocket', WSConnection),
(r'/api/log', LogHandler),
"tool-type": {
"type": "enum",
"values": ["Disabled", "PWM Spindle", "Huanyang VFD", "Custom Modbus VFD",
- "AC-Tech VFD", "Delta VFD015M21A (Beta)", "YL600 VFD (Beta)",
- "FR-D700 (Beta)"],
+ "AC-Tech VFD", "Nowforever VFD", "Delta VFD015M21A (Beta)",
+ "YL600 VFD (Beta)", "FR-D700 (Beta)"],
"default": "Disabled",
"code": "st"
},
"default": "None",
"code": "ma"
},
+ "multi-write": {
+ "help": "Use Modbus multi register write. Function 16 vs. 6.",
+ "type": "bool",
+ "default": false,
+ "code": "mw"
+ },
"regs": {
"type": "list",
"index": "0123456789abcdefghijklmnopqrstuv",