From fe61e2fa3e00e21147e6c426c8cef94e851e015a Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Sat, 31 Aug 2019 14:55:21 -0700 Subject: [PATCH] Show power shutdown on indicators page, Show all motors in shutdown when in power shutdown, Improved GCode error messages, Put controller into estop when in power shutdown --- CHANGELOG.md | 4 + src/avr/src/command.def | 1 + src/avr/src/estop.c | 6 + src/avr/src/messages.def | 1 + src/avr/src/motor.c | 2 +- src/js/axis-vars.js | 14 +- src/pug/templates/indicators.pug | 5 +- src/pwr/config.h | 26 +-- src/pwr/main.c | 270 ++++++++++++++++--------------- src/py/bbctrl/Cmd.py | 16 +- src/py/bbctrl/Planner.py | 5 + src/py/bbctrl/Pwr.py | 24 +-- 12 files changed, 209 insertions(+), 165 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6aac928..06863c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ Buildbotics CNC Controller Firmware Changelog - Fix demo password check - Fix bug were fast clicks could cause jog commands to arrive out of order. - Fix bug bug where planner position may not sync after jog. + - Show power shutdown on indicators page. + - Show all motors in shutdown when in power shutdown. + - Improved GCode error messages. + - Don't reset global offsets on M2. ## v0.4.9 - Enforce 6A per motor channel peak current limit. diff --git a/src/avr/src/command.def b/src/avr/src/command.def index 7296df3..c413a90 100644 --- a/src/avr/src/command.def +++ b/src/avr/src/command.def @@ -43,6 +43,7 @@ CMD('r', report, 0) // <0|1>[var] Enable or disable var reporting CMD('R', reboot, 0) // Reboot the controller CMD('c', resume, 0) // Continue processing after a flush CMD('E', estop, 0) // Emergency stop +CMD('X', shutdown, 0) // Power shutdown CMD('C', clear, 0) // Clear estop CMD('F', flush, 0) // Flush command queue CMD('D', dump, 0) // Report all variables diff --git a/src/avr/src/estop.c b/src/avr/src/estop.c index d111c0b..1e9bacb 100644 --- a/src/avr/src/estop.c +++ b/src/avr/src/estop.c @@ -117,4 +117,10 @@ stat_t command_estop(char *cmd) { } +stat_t command_shutdown(char *cmd) { + estop_trigger(STAT_POWER_SHUTDOWN); + return STAT_OK; +} + + stat_t command_clear(char *cmd) {estop_clear(); return STAT_OK;} diff --git a/src/avr/src/messages.def b/src/avr/src/messages.def index 8f1be68..2f9aa33 100644 --- a/src/avr/src/messages.def +++ b/src/avr/src/messages.def @@ -31,6 +31,7 @@ STAT_MSG(NOP, "No op") STAT_MSG(INTERNAL_ERROR, "Internal error") STAT_MSG(ESTOP_USER, "User triggered EStop") STAT_MSG(ESTOP_SWITCH, "Switch triggered EStop") +STAT_MSG(POWER_SHUTDOWN, "Power shutdown") STAT_MSG(UNRECOGNIZED_NAME, "Unrecognized command or variable name") STAT_MSG(INVALID_COMMAND, "Invalid command") STAT_MSG(INVALID_ARGUMENTS, "Invalid arguments") diff --git a/src/avr/src/motor.c b/src/avr/src/motor.c index b032568..2edc42c 100644 --- a/src/avr/src/motor.c +++ b/src/avr/src/motor.c @@ -427,7 +427,7 @@ void set_motor_axis(int motor, uint8_t axis) { set_travel(motor, motors[m].travel_rev); set_microstep(motor, motors[m].microsteps); set_motor_enabled(motor, motors[m].enabled); - motors[motor].slave = true; + motors[motor].slave = true; // Must be last break; } } diff --git a/src/js/axis-vars.js b/src/js/axis-vars.js index 6f0b7c4..40ddf43 100644 --- a/src/js/axis-vars.js +++ b/src/js/axis-vars.js @@ -78,10 +78,11 @@ module.exports = { var state = 'UNHOMED'; var icon = 'question-circle'; var fault = this.state[motor_id + 'df'] & 0x1f; + var shutdown = this.state.power_shutdown; var title; - if (fault) { - state = 'FAULT'; + if (fault || shutdown) { + state = shutdown ? 'SHUTDOWN' : 'FAULT'; klass += ' error'; icon = 'exclamation-circle'; @@ -102,7 +103,7 @@ module.exports = { } switch (state) { - case 'UNHOMED': title = 'Click the home button to home axis.'; break; + case 'UNHOMED': title = 'Click the home button to home axis.'; break; case 'HOMED': title = 'Axis successfuly homed.'; break; case 'OVER': @@ -124,9 +125,14 @@ module.exports = { title = 'Motor driver fault. A potentially damaging electrical ' + 'condition was detected and the motor driver was shutdown. ' + 'Please power down the controller and check your motor cabling. ' + - 'See the "Motor Faults" table on the "Indicators" for more ' + + 'See the "Motor Faults" table on the "Indicators" tab for more ' + 'information.'; break; + + case 'SHUTDOWN': + title = 'Motor power fault. All motors in shutdown. ' + + 'See the "Power Faults" table on the "Indicators" tab for more ' + + 'information. Reboot controller to reset.'; } return { diff --git a/src/pug/templates/indicators.pug b/src/pug/templates/indicators.pug index 70821c5..500ab48 100644 --- a/src/pug/templates/indicators.pug +++ b/src/pug/templates/indicators.pug @@ -167,8 +167,9 @@ script#indicators-template(type="text/x-template") td(:class="{error: state.motor_under_voltage}") | {{state.motor_under_voltage ? 'True' : 'False'}} th.separator - th - td + th(:class="{error: state.power_shutdown}") Power shutdown + td(:class="{error: state.power_shutdown}") + | {{state.power_shutdown ? 'True' : 'False'}} table.motor_fault tr diff --git a/src/pwr/config.h b/src/pwr/config.h index 132f540..b90f48b 100644 --- a/src/pwr/config.h +++ b/src/pwr/config.h @@ -30,7 +30,7 @@ #include "pins.h" -#define VERSION 3 +#define VERSION 4 // Pins @@ -133,17 +133,17 @@ typedef enum { enum { // Fatal - UNDER_VOLTAGE_FLAG = 1 << 0, - OVER_VOLTAGE_FLAG = 1 << 1, - OVER_CURRENT_FLAG = 1 << 2, - SENSE_ERROR_FLAG = 1 << 3, - SHUNT_OVERLOAD_FLAG = 1 << 4, - MOTOR_OVERLOAD_FLAG = 1 << 5, + UNDER_VOLTAGE_FLAG = 1 << 0, + OVER_VOLTAGE_FLAG = 1 << 1, + OVER_CURRENT_FLAG = 1 << 2, + SENSE_ERROR_FLAG = 1 << 3, + SHUNT_OVERLOAD_FLAG = 1 << 4, + MOTOR_OVERLOAD_FLAG = 1 << 5, // Non fatal - LOAD1_SHUTDOWN_FLAG = 1 << 6, - LOAD2_SHUTDOWN_FLAG = 1 << 7, - MOTOR_UNDER_VOLTAGE_FLAG = 1 << 8, + LOAD1_SHUTDOWN_FLAG = 1 << 6, + LOAD2_SHUTDOWN_FLAG = 1 << 7, + MOTOR_UNDER_VOLTAGE_FLAG = 1 << 8, // Sense errors MOTOR_VOLTAGE_SENSE_ERROR_FLAG = 1 << 9, @@ -151,7 +151,11 @@ enum { LOAD1_SENSE_ERROR_FLAG = 1 << 11, LOAD2_SENSE_ERROR_FLAG = 1 << 12, VDD_CURRENT_SENSE_ERROR_FLAG = 1 << 13, + + // State flags + POWER_SHUTDOWN_FLAG = 1 << 14, }; -#define FATAL_FLAG_MASK ((1 << 6) - 1) +#define FATAL_FLAGS 0x003f +#define SENSE_ERROR_FLAGS 0x3e00 diff --git a/src/pwr/main.c b/src/pwr/main.c index 01160e7..7ea387a 100644 --- a/src/pwr/main.c +++ b/src/pwr/main.c @@ -30,7 +30,6 @@ #include #include #include -#include #include @@ -41,13 +40,13 @@ typedef struct { const regs_t reg; const uint8_t pin; volatile uint8_t overtemp; - volatile bool shutdown; + volatile uint16_t shutdown_flag; } load_t; load_t loads[2] = { - {LOAD1_REG, LOAD1_PIN, 0, false}, - {LOAD2_REG, LOAD2_PIN, 0, false}, + {LOAD1_REG, LOAD1_PIN, 0, LOAD1_SHUTDOWN_FLAG}, + {LOAD2_REG, LOAD2_PIN, 0, LOAD2_SHUTDOWN_FLAG}, }; @@ -66,13 +65,31 @@ static volatile uint16_t reg_avg[NUM_REGS][BUCKETS] = {{0}}; static volatile uint16_t reg_index[NUM_REGS] = {0}; static volatile uint64_t time = 0; // ms static volatile uint8_t motor_overload = 0; -static volatile bool shunt_overload = false; static volatile float shunt_joules = 0; static volatile float vnom = 0; -void i2c_ack() {TWSCRB = (1 << TWCMD1) | (1 << TWCMD0);} -void i2c_nack() {TWSCRB = (1 << TWAA) | (1 << TWCMD1) | (1 << TWCMD0);} +static void shutdown(); + + +static uint16_t flags_get(uint16_t flags) {return regs[FLAGS_REG] & flags;} +static void flags_clear(uint16_t flags) {regs[FLAGS_REG] &= ~flags;} + + +static void flags_set(uint16_t flags) { + regs[FLAGS_REG] |= flags; + if (flags & FATAL_FLAGS) shutdown(); +} + + +static void flags(uint16_t flags, bool enable) { + if (enable) flags_set(flags); + else flags_clear(flags); +} + + +static void i2c_ack() {TWSCRB = (1 << TWCMD1) | (1 << TWCMD0);} +static void i2c_nack() {TWSCRB = (1 << TWAA) | (1 << TWCMD1) | (1 << TWCMD0);} ISR(TWI_SLAVE_vect) { @@ -117,16 +134,6 @@ ISR(TWI_SLAVE_vect) { } -static float get_total_current() { - cli(); - float current = - regs[MOTOR_REG] + regs[VDD_REG] + regs[LOAD1_REG] + regs[LOAD2_REG]; - sei(); - - return current / 100; -} - - static float get_reg(int reg) { cli(); float value = regs[reg]; @@ -137,27 +144,32 @@ static float get_reg(int reg) { static void update_shunt() { + if (flags_get(POWER_SHUTDOWN_FLAG)) return; + static float joules = SHUNT_JOULES; // Power disipation budget // Add power dissipation credit for the 1ms that elapsed joules += SHUNT_JOULES_PER_MS; if (SHUNT_JOULES < joules) joules = SHUNT_JOULES; // Max - if (joules < shunt_joules) shunt_overload = true; + if (joules < shunt_joules) flags_set(SHUNT_OVERLOAD_FLAG); else joules -= shunt_joules; // Subtract power dissipated } -static void update_shunt_power(float vout, float vnom) { +static void update_shunt_power() { + if (flags_get(POWER_SHUTDOWN_FLAG)) return; + + float vout = get_reg(VOUT_REG); + if (vnom + SHUNT_MIN_V < vout) { // Compute joules shunted this cycle: J = V^2 / RT shunt_joules = vout * vout / (SHUNT_OHMS * 1000.0); - IO_DDR_SET(SHUNT_PIN); // Enable - IO_PORT_CLR(SHUNT_PIN); // Lo + IO_PORT_CLR(SHUNT_PIN); // Enable (lo) } else { shunt_joules = 0; - IO_DDR_CLR(SHUNT_PIN); // Disable + IO_PORT_SET(SHUNT_PIN); // Disable (hi) } } @@ -173,20 +185,6 @@ static void measure_nominal_voltage() { } -static void check_load(load_t *load) { - if (load->shutdown) return; - - bool overtemp = CURRENT_OVERTEMP * 100 < regs[load->reg]; - if (overtemp) { - if (++load->overtemp == LOAD_OVERTEMP_MAX) { - load->shutdown = true; - IO_PORT_CLR(load->pin); // Lo - IO_DDR_SET(load->pin); // Output - } - } else if (load->overtemp) load->overtemp--; -} - - ISR(TIMER0_OVF_vect) { static uint8_t tick = 0; @@ -200,24 +198,18 @@ ISR(TIMER0_OVF_vect) { } -static void delay_ms(uint16_t ms) { - uint64_t start = time; - while (time < start + ms) continue; -} - - -inline static uint16_t convert_voltage(uint16_t sample) { +static uint16_t convert_voltage(uint16_t sample) { return sample * (VOLTAGE_REF / 1024.0 * (VOLTAGE_REF_R1 + VOLTAGE_REF_R2) / VOLTAGE_REF_R2 * 100); } -inline static uint16_t convert_current(uint16_t sample) { +static uint16_t convert_current(uint16_t sample) { return sample * (VOLTAGE_REF / 1024.0 * CURRENT_REF_MUL); } -inline static void update_current(int reg, uint16_t sample) { +static void update_current(int reg, uint16_t sample) { reg_avg[reg][reg_index[reg]] = convert_current(sample); if (++reg_index[reg] == BUCKETS) reg_index[reg] = 0; @@ -226,43 +218,82 @@ inline static void update_current(int reg, uint16_t sample) { sum += reg_avg[reg][i]; regs[reg] = sum >> AVG_SCALE; + + // Check total current + uint16_t total_current = + regs[MOTOR_REG] + regs[VDD_REG] + regs[LOAD1_REG] + regs[LOAD2_REG]; + if (CURRENT_MAX * 100 < total_current) flags_set(OVER_CURRENT_FLAG); } -static void read_conversion(uint8_t ch) { - uint16_t data = ADC; +static void update_vin(uint16_t sample) { + uint16_t vin = regs[VIN_REG] = convert_voltage(sample); - switch (ch) { - case TEMP_ADC: regs[TEMP_REG] = data; break; // in Kelvin - case VIN_ADC: regs[VIN_REG] = convert_voltage(data); break; - - case VOUT_ADC: - regs[VOUT_REG] = convert_voltage(data); - update_shunt_power(regs[VOUT_REG] / 100.0, vnom); - break; - - case CS1_ADC: { - update_current(MOTOR_REG, data); - bool overtemp = CURRENT_OVERTEMP * 100 < regs[MOTOR_REG]; - - if (overtemp) { - if (motor_overload < MOTOR_SHUTDOWN_THRESH) motor_overload++; - } else if (motor_overload != MOTOR_SHUTDOWN_THRESH && motor_overload) - motor_overload--; - break; - } + // Check voltage + if (vin < (VOLTAGE_MIN * 100)) flags_set(UNDER_VOLTAGE_FLAG); + if ((VOLTAGE_MAX * 100) < vin) flags_set(OVER_VOLTAGE_FLAG); +} - case CS2_ADC: update_current(VDD_REG, data); break; - case CS3_ADC: - update_current(LOAD2_REG, data); - check_load(&loads[1]); - break; +static void update_vout(uint16_t sample) { + uint16_t vout = regs[VOUT_REG] = convert_voltage(sample); - case CS4_ADC: - update_current(LOAD1_REG, data); - check_load(&loads[0]); - break; + update_shunt_power(); + + // Check voltage + if ((VOLTAGE_MAX * 100) < vout) flags_set(OVER_VOLTAGE_FLAG); + flags(MOTOR_UNDER_VOLTAGE_FLAG, + vout < (VOLTAGE_MIN * 100) && !flags_get(POWER_SHUTDOWN_FLAG)); +} + + +static void update_motor_current(uint16_t sample) { + update_current(MOTOR_REG, sample); + + if (flags_get(MOTOR_OVERLOAD_FLAG)) return; + + bool overtemp = CURRENT_OVERTEMP * 100 < regs[MOTOR_REG]; + + if (overtemp) { + if (motor_overload < MOTOR_SHUTDOWN_THRESH) motor_overload++; + if (motor_overload == MOTOR_SHUTDOWN_THRESH) flags_set(MOTOR_OVERLOAD_FLAG); + + } else if (motor_overload != MOTOR_SHUTDOWN_THRESH && motor_overload) + motor_overload--; +} + + +static void load_shutdown(load_t *load) { + flags_set(load->shutdown_flag); + IO_PORT_CLR(load->pin); // Lo + IO_DDR_SET(load->pin); // Output +} + + +static void update_load_current(load_t *load, uint16_t sample) { + update_current(load->reg, sample); + + if (flags_get(load->shutdown_flag)) return; + + bool overtemp = CURRENT_OVERTEMP * 100 < regs[load->reg]; + + if (overtemp) { + if (++load->overtemp == LOAD_OVERTEMP_MAX) load_shutdown(load); + } else if (load->overtemp) load->overtemp--; +} + + +static void read_conversion(uint8_t ch) { + uint16_t sample = ADC; + + switch (ch) { + case TEMP_ADC: regs[TEMP_REG] = sample; break; // in Kelvin + case VIN_ADC: update_vin(sample); break; + case VOUT_ADC: update_vout(sample); break; + case CS1_ADC: update_motor_current(sample); break; + case CS2_ADC: update_current(VDD_REG, sample); break; + case CS3_ADC: update_load_current(&loads[1], sample); break; + case CS4_ADC: update_load_current(&loads[0], sample); break; } } @@ -292,12 +323,10 @@ static void validate_input_voltage() { float vlast = 0; while (settle < VOLTAGE_SETTLE_COUNT) { - wdt_reset(); - delay_ms(VOLTAGE_SETTLE_PERIOD); - - float vin = get_reg(VIN_REG); + _delay_ms(VOLTAGE_SETTLE_PERIOD); // Check that voltage is with in range and settled + float vin = get_reg(VIN_REG); if (VOLTAGE_MIN < vin && vin < VOLTAGE_MAX && is_within(vlast, vin, VOLTAGE_SETTLE_TOLERANCE)) settle++; else settle = 0; @@ -308,10 +337,9 @@ static void validate_input_voltage() { static void charge_caps() { - uint64_t now = time; - + IO_PORT_SET(SHUNT_PIN); // Disable shunt (hi) IO_PORT_SET(MOTOR_PIN); // Motor voltage on - while (time < now + CAP_CHARGE_TIME) continue; + _delay_ms(CAP_CHARGE_TIME); } @@ -319,9 +347,9 @@ void init() { cli(); // CPU Clock, disable CKOUT - CCP = 0xd8; + CCP = 0xd8; CLKSR = (1 << CSTR) | (1 << CKOUT_IO) | 0b0010; // 8Mhz internal clock - CCP = 0xd8; + CCP = 0xd8; CLKPR = 0; // div 1 while (!((1 << 7) & CLKSR)) continue; // Wait for clock to stabilize @@ -335,6 +363,8 @@ void init() { IO_DDR_CLR(LOAD1_PIN); // Tri-state IO_DDR_CLR(LOAD2_PIN); // Tri-state IO_PUE_SET(PWR_RESET); // Pull up reset line + IO_PORT_CLR(SHUNT_PIN); // Enable shunt + IO_DDR_SET(SHUNT_PIN); // Output // Disable digital IO on ADC lines DIDR0 = (1 << ADC4D) | (1 << ADC3D) | (1 << ADC2D) | (1 << ADC1D) | @@ -343,7 +373,7 @@ void init() { // ADC internal 1.1v, enable, with interrupt, prescale 64 // Note, a conversion takes ~200uS - ADMUX = (1 << REFS1) | (0 << REFS0); + ADMUX = (1 << REFS1) | (0 << REFS0); ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); ADCSRB = 0; @@ -351,78 +381,56 @@ void init() { // Timer 0 (Fast PWM, clk/1) TCCR0A = (1 << WGM01) | (1 << WGM00); TCCR0B = (0 << WGM02) | (0 << CS02) | (0 << CS01) | (1 << CS00); - TIMSK = 1 << TOIE0; // Enable overflow interrupt + TIMSK = 1 << TOIE0; // Enable overflow interrupt // I2C, enable, enable address/stop interrupt TWSCRA = (1 << TWEN) | (1 << TWASIE) | (1 << TWDIE); - TWSA = I2C_ADDR << 1; - TWSAM = I2C_MASK << 1; + TWSA = I2C_ADDR << 1; + TWSAM = I2C_MASK << 1; sei(); } static void shutdown() { - // Disable outputs - IO_DDR_CLR(MOTOR_PIN); // Input - IO_PORT_CLR(LOAD1_PIN); // Lo - IO_PORT_CLR(LOAD2_PIN); // Lo - IO_DDR_SET(LOAD1_PIN); // Output - IO_DDR_SET(LOAD2_PIN); // Output + if (flags_get(POWER_SHUTDOWN_FLAG)) return; + flags_set(POWER_SHUTDOWN_FLAG); + + // Disable loads + load_shutdown(&loads[0]); + load_shutdown(&loads[1]); + + // Motor power off + IO_PORT_CLR(MOTOR_PIN); // Lo + + // Turn shunt on + IO_PORT_CLR(SHUNT_PIN); // Lo } -static uint16_t validate_measurements() { +static void validate_measurements() { const float max_voltage = 0.99 * convert_voltage(0x3ff); const float max_current = 0.99 * convert_current(0x3ff); - uint16_t flags = 0; - - if (max_voltage < regs[VOUT_REG]) flags |= MOTOR_VOLTAGE_SENSE_ERROR_FLAG; - if (max_current < regs[MOTOR_REG]) flags |= MOTOR_CURRENT_SENSE_ERROR_FLAG; - if (max_current < regs[LOAD1_REG]) flags |= LOAD1_SENSE_ERROR_FLAG; - if (max_current < regs[LOAD2_REG]) flags |= LOAD2_SENSE_ERROR_FLAG; - if (max_current < regs[VDD_REG]) flags |= VDD_CURRENT_SENSE_ERROR_FLAG; - return flags ? SENSE_ERROR_FLAG | flags : 0; + if (max_voltage < regs[VOUT_REG]) flags_set(MOTOR_VOLTAGE_SENSE_ERROR_FLAG); + if (max_current < regs[MOTOR_REG]) flags_set(MOTOR_CURRENT_SENSE_ERROR_FLAG); + if (max_current < regs[LOAD1_REG]) flags_set(LOAD1_SENSE_ERROR_FLAG); + if (max_current < regs[LOAD2_REG]) flags_set(LOAD2_SENSE_ERROR_FLAG); + if (max_current < regs[VDD_REG]) flags_set(VDD_CURRENT_SENSE_ERROR_FLAG); + if (flags_get(SENSE_ERROR_FLAGS)) flags_set(SENSE_ERROR_FLAG); } int main() { - wdt_enable(WDTO_8S); - regs[VERSION_REG] = VERSION; init(); adc_conversion(); // Start ADC validate_input_voltage(); charge_caps(); - uint16_t fatal = validate_measurements(); - - while (true) { - wdt_reset(); + validate_measurements(); - float vin = get_reg(VIN_REG); - float vout = get_reg(VOUT_REG); - - //update_shunt_power(vout, vnom); - - // Fatal conditions - if (vin < VOLTAGE_MIN) fatal |= UNDER_VOLTAGE_FLAG; - if (VOLTAGE_MAX < vin || VOLTAGE_MAX < vout) fatal |= OVER_VOLTAGE_FLAG; - if (CURRENT_MAX < get_total_current()) fatal |= OVER_CURRENT_FLAG; - if (shunt_overload) fatal |= SHUNT_OVERLOAD_FLAG; - if (motor_overload == MOTOR_SHUTDOWN_THRESH) fatal |= MOTOR_OVERLOAD_FLAG; - if (fatal) shutdown(); - - // Nonfatal conditions - uint16_t nonfatal = 0; - if (loads[0].shutdown) nonfatal |= LOAD1_SHUTDOWN_FLAG; - if (loads[1].shutdown) nonfatal |= LOAD2_SHUTDOWN_FLAG; - if (vout < VOLTAGE_MIN) nonfatal |= MOTOR_UNDER_VOLTAGE_FLAG; - - // Update flags - regs[FLAGS_REG] = fatal | nonfatal; - } + while (true) continue; return 0; } diff --git a/src/py/bbctrl/Cmd.py b/src/py/bbctrl/Cmd.py index 169f923..7413760 100755 --- a/src/py/bbctrl/Cmd.py +++ b/src/py/bbctrl/Cmd.py @@ -51,6 +51,7 @@ REPORT = 'r' REBOOT = 'R' RESUME = 'c' ESTOP = 'E' +SHUTDOWN = 'X' CLEAR = 'C' FLUSH = 'F' DUMP = 'D' @@ -239,13 +240,14 @@ def decode_command(cmd): if name in 'xyzabcuvw': data['target'][name] = value else: data['times'][int(name)] = value - elif cmd[0] == REPORT: data['type'] = 'report' - elif cmd[0] == PAUSE: data['type'] = 'pause' - elif cmd[0] == UNPAUSE: data['type'] = 'unpause' - elif cmd[0] == ESTOP: data['type'] = 'estop' - elif cmd[0] == CLEAR: data['type'] = 'clear' - elif cmd[0] == FLUSH: data['type'] = 'flush' - elif cmd[0] == RESUME: data['type'] = 'resume' + elif cmd[0] == REPORT: data['type'] = 'report' + elif cmd[0] == PAUSE: data['type'] = 'pause' + elif cmd[0] == UNPAUSE: data['type'] = 'unpause' + elif cmd[0] == ESTOP: data['type'] = 'estop' + elif cmd[0] == SHUTDOWN: data['type'] = 'shutdown' + elif cmd[0] == CLEAR: data['type'] = 'clear' + elif cmd[0] == FLUSH: data['type'] = 'flush' + elif cmd[0] == RESUME: data['type'] = 'resume' return data diff --git a/src/py/bbctrl/Planner.py b/src/py/bbctrl/Planner.py index fcb19af..abd223c 100644 --- a/src/py/bbctrl/Planner.py +++ b/src/py/bbctrl/Planner.py @@ -362,6 +362,11 @@ class Planner(): cmd = self._encode(cmd) if cmd is not None: return cmd + except RuntimeError as e: + # Pass on the planner message + self.log.error(str(e)); + self.stop() + except: self.log.exception() self.stop() diff --git a/src/py/bbctrl/Pwr.py b/src/py/bbctrl/Pwr.py index ded8aac..b2ec945 100644 --- a/src/py/bbctrl/Pwr.py +++ b/src/py/bbctrl/Pwr.py @@ -26,6 +26,7 @@ ################################################################################ import bbctrl +import bbctrl.Cmd as Cmd # Must match regs in pwr firmware @@ -40,20 +41,21 @@ FLAGS_REG = 7 VERSION_REG = 8 # Must be kept in sync with pwr firmware -UNDER_VOLTAGE_FLAG = 1 << 0 -OVER_VOLTAGE_FLAG = 1 << 1 -OVER_CURRENT_FLAG = 1 << 2 -SENSE_ERROR_FLAG = 1 << 3 -SHUNT_OVERLOAD_FLAG = 1 << 4 -MOTOR_OVERLOAD_FLAG = 1 << 5 -LOAD1_SHUTDOWN_FLAG = 1 << 6 -LOAD2_SHUTDOWN_FLAG = 1 << 7 -MOTOR_UNDER_VOLTAGE_FLAG = 1 << 8 +UNDER_VOLTAGE_FLAG = 1 << 0 +OVER_VOLTAGE_FLAG = 1 << 1 +OVER_CURRENT_FLAG = 1 << 2 +SENSE_ERROR_FLAG = 1 << 3 +SHUNT_OVERLOAD_FLAG = 1 << 4 +MOTOR_OVERLOAD_FLAG = 1 << 5 +LOAD1_SHUTDOWN_FLAG = 1 << 6 +LOAD2_SHUTDOWN_FLAG = 1 << 7 +MOTOR_UNDER_VOLTAGE_FLAG = 1 << 8 MOTOR_VOLTAGE_SENSE_ERROR_FLAG = 1 << 9 MOTOR_CURRENT_SENSE_ERROR_FLAG = 1 << 10 LOAD1_SENSE_ERROR_FLAG = 1 << 11 LOAD2_SENSE_ERROR_FLAG = 1 << 12 VDD_CURRENT_SENSE_ERROR_FLAG = 1 << 13 +POWER_SHUTDOWN_FLAG = 1 << 14 reg_names = 'temp vin vout motor load1 load2 vdd pwr_flags pwr_version'.split() @@ -132,6 +134,10 @@ class Pwr(): flags & VDD_CURRENT_SENSE_ERROR_FLAG): self.log.error('Vdd current sense error') + if self.check_fault('power_shutdown', flags & POWER_SHUTDOWN_FLAG): + self.log.error('Power shutdown') + self.ctrl.mach.i2c_command(Cmd.SHUTDOWN) + def _update_cb(self, now = True): if now: self._update() -- 2.27.0