From: Joseph Coffland Date: Fri, 14 Jun 2019 16:51:05 +0000 (-0700) Subject: + - Respect offsets in canned cycle moves. #219 X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=6202919521d0cbdf42b0f401d8a0e9c7064c440b;p=bbctrl-firmware + - Respect offsets in canned cycle moves. #219 + - Fixed G53 warning. + - Fixed delayed offset update after M2 or M30 end of program. + - Handle multiple consecutive config resets correctly. + - Fixed log CPU usage problem introduced in v0.4.6. + - Show RPi temp on indicators page. + - Show red thermometer if RPi temp exceeds 80°C. + - Enforce 6A per motor channel peak current limit. + - Adjust config values above max or below min instead of resetting to default. --- diff --git a/CHANGELOG.md b/CHANGELOG.md index c97aa73..c70a282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Buildbotics CNC Controller Firmware Changelog ============================================= +## v0.4.9 + - Enforce 6A per motor channel peak current limit. + - Adjust config values above max or below min instead of resetting to default. + ## v0.4.8 - Fixed log rotating. - Use systemd serivce instead of init.d. @@ -11,6 +15,13 @@ Buildbotics CNC Controller Firmware Changelog - Rewrote RPi serial driver. - Automatically scale max CPU speed to reduce RPi temp. - Disable USB camera if RPi temperature above 80°C, back on at 75°C. + - Respect offsets in canned cycle moves. #219 + - Fixed G53 warning. + - Fixed delayed offset update after M2 or M30 end of program. + - Handle multiple consecutive config resets correctly. + - Fixed log CPU usage problem introduced in v0.4.6. + - Show RPi temp on indicators page. + - Show red thermometer if RPi temp exceeds 80°C. ## v0.4.7 - Fix homing switch to motor channel mapping with non-standard axis order. diff --git a/package.json b/package.json index 326139f..958ad19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bbctrl", - "version": "0.4.8", + "version": "0.4.9", "homepage": "http://buildbotics.com/", "repository": "https://github.com/buildbotics/bbctrl-firmware", "license": "GPL-3.0+", diff --git a/scripts/install.sh b/scripts/install.sh index 86f796e..eeacf8f 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -29,7 +29,7 @@ function update_config_txt() { if $UPDATE_PY; then - service bbctrl stop + systemctl stop bbctrl # Update service rm -f /etc/init.d/bbctrl @@ -130,11 +130,14 @@ cp scripts/rc.local /etc/ if $UPDATE_PY; then rm -rf /usr/local/lib/python*/dist-packages/bbctrl-* ./setup.py install --force - service bbctrl start + service bbctrl restart fi sync if $REBOOT; then + echo "Rebooting" reboot fi + +echo "Install complete" diff --git a/scripts/update-bbctrl b/scripts/update-bbctrl index 739203b..06433ed 100755 --- a/scripts/update-bbctrl +++ b/scripts/update-bbctrl @@ -7,13 +7,16 @@ if [ ! -e "$UPDATE" ]; then exit 1 fi +systemctl stop bbctrl + rm -rf /tmp/update mkdir /tmp/update cd /tmp/update +LOG=/var/log/bbctrl.$(date +%Y%m%d-%H%M%S).install tar xf "$UPDATE" cd * -./scripts/install.sh "$*" +./scripts/install.sh "$*" 2>&1 > $LOG cd - rm -rf /tmp/update $UPDATE diff --git a/scripts/upgrade-bbctrl b/scripts/upgrade-bbctrl index 44454f2..babd550 100755 --- a/scripts/upgrade-bbctrl +++ b/scripts/upgrade-bbctrl @@ -5,22 +5,18 @@ VERSION=$(curl -s https://buildbotics.com/bbctrl/latest.txt) PKG_NAME=bbctrl-$VERSION - PKG=$PKG_NAME.tar.bz2 - PKG_URL=https://buildbotics.com/bbctrl/$PKG + PKG=/var/lib/bbctrl/firmware/update.tar.bz2 + PKG_URL=https://buildbotics.com/bbctrl/$PKG_NAME.tar.bz2 logger Installing bbctrl firmware $VERSION + cd /var/lib/bbctrl + mkdir -p firmware + echo Downloading $PKG_URL curl -s $PKG_URL > $PKG - echo Unpacking $PKG - tar xf $PKG - - echo Installing $PKG - (cd $PKG_NAME; ./scripts/install.sh) - - echo Cleaning up - rm -rf $PKG_NAME $PKG + /usr/local/bin/update-bbctrl echo Success diff --git a/src/avr/src/config.h b/src/avr/src/config.h index 512b3f3..68df384 100644 --- a/src/avr/src/config.h +++ b/src/avr/src/config.h @@ -214,7 +214,7 @@ enum { #define MIN_VELOCITY 10 // mm/min #define CURRENT_SENSE_RESISTOR 0.05 // ohms #define CURRENT_SENSE_REF 2.75 // volts -#define MAX_CURRENT 10 // amps +#define MAX_CURRENT 6 // amps #define MAX_IDLE_CURRENT 2 // amps #define VELOCITY_MULTIPLIER 1000.0 #define ACCEL_MULTIPLIER 1000000.0 diff --git a/src/avr/src/drv8711.c b/src/avr/src/drv8711.c index 18a8fde..ca7a8f6 100644 --- a/src/avr/src/drv8711.c +++ b/src/avr/src/drv8711.c @@ -397,8 +397,8 @@ float get_drive_current(int driver) { void set_drive_current(int driver, float value) { - if (driver < 0 || DRIVERS <= driver || value < 0 || MAX_CURRENT < value) - return; + if (driver < 0 || DRIVERS <= driver || value < 0) return; + if (MAX_CURRENT < value) value = MAX_CURRENT; _current_set(&drivers[driver].drive, value); } diff --git a/src/avr/src/vars.def b/src/avr/src/vars.def index 45dda83..cfac5c9 100644 --- a/src/avr/src/vars.def +++ b/src/avr/src/vars.def @@ -25,9 +25,9 @@ \******************************************************************************/ -#define AXES_LABEL "xyzabc" +#define AXES_LABEL "xyzabc" #define MOTORS_LABEL "0123" -#define OUTS_LABEL "ed12ft" +#define OUTS_LABEL "ed12ft" #define ANALOG_LABEL "12" #define VFDREG_LABEL "0123456789abcdefghijklmnopqrstuv" diff --git a/src/bbserial/bbserial.c b/src/bbserial/bbserial.c index 8a5745f..0c00d5d 100644 --- a/src/bbserial/bbserial.c +++ b/src/bbserial/bbserial.c @@ -36,66 +36,27 @@ #include #include #include +#include #include +#include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Joseph Coffland"); MODULE_DESCRIPTION("Buildbotics controller serial port driver"); -MODULE_VERSION("0.2"); +MODULE_VERSION("0.3"); -#define DEVICE_NAME "ttyBB0" +#define DEVICE_NAME "ttyAMA0" #define BUF_SIZE (1 << 16) -enum { - REG_DR, - REG_ST_DMAWM, - REG_ST_TIMEOUT, - REG_FR, - REG_LCRH_RX, - REG_LCRH_TX, - REG_IBRD, - REG_FBRD, - REG_CR, - REG_IFLS, - REG_IMSC, - REG_RIS, - REG_MIS, - REG_ICR, - REG_DMACR, - REG_ST_XFCR, - REG_ST_XON1, - REG_ST_XON2, - REG_ST_XOFF1, - REG_ST_XOFF2, - REG_ST_ITCR, - REG_ST_ITIP, - REG_ST_ABCR, - REG_ST_ABIMSC, - REG_ARRAY_SIZE, -}; - +#define UART01x_LCRH_WLEN_bm 0x60 -static u16 _offsets[REG_ARRAY_SIZE] = { - [REG_DR] = UART01x_DR, - [REG_FR] = UART01x_FR, - [REG_LCRH_RX] = UART011_LCRH, - [REG_LCRH_TX] = UART011_LCRH, - [REG_IBRD] = UART011_IBRD, - [REG_FBRD] = UART011_FBRD, - [REG_CR] = UART011_CR, - [REG_IFLS] = UART011_IFLS, - [REG_IMSC] = UART011_IMSC, - [REG_RIS] = UART011_RIS, - [REG_MIS] = UART011_MIS, - [REG_ICR] = UART011_ICR, - [REG_DMACR] = UART011_DMACR, -}; +static int debug = 0; +module_param(debug, int, 0660); -static int _debug = 0; struct ring_buf { unsigned char *buf; @@ -110,14 +71,11 @@ static struct { spinlock_t lock; unsigned open; unsigned char __iomem *base; - wait_queue_head_t wait; - unsigned long req_events; + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; unsigned irq; unsigned im; // interrupt mask - unsigned rx_bytes; - unsigned tx_bytes; - unsigned brk_errs; unsigned parity_errs; unsigned frame_errs; @@ -126,6 +84,7 @@ static struct { int major; struct class *class; struct device *dev; + struct ktermios term; } _port; @@ -137,70 +96,55 @@ static struct { #define RING_BUF_PUSH(BUF, C) \ do { \ (BUF).buf[(BUF).head] = C; \ + mb(); \ RING_BUF_INC(BUF, head); \ } while (0) #define RING_BUF_POKE(BUF) (BUF).buf[(BUF).head] #define RING_BUF_PEEK(BUF) (BUF).buf[(BUF).tail] - -#define RING_BUF_MOVE(SRC, DST) \ - do { \ - RING_BUF_PUSH(DST, RING_BUF_PEEK(SRC)); \ - RING_BUF_POP(SRC); \ - } while (0) - - #define RING_BUF_SPACE(BUF) ((((BUF).tail) - ((BUF).head + 1)) & (BUF_SIZE - 1)) #define RING_BUF_FILL(BUF) ((((BUF).head) - ((BUF).tail)) & (BUF_SIZE - 1)) +#define RING_BUF_CLEAR(BUF) do {(BUF).head = (BUF).tail = 0;} while (0) -static unsigned _read(unsigned reg) { - return readw_relaxed(_port.base + _offsets[reg]); -} +static unsigned _read(unsigned reg) {return readw_relaxed(_port.base + reg);} static void _write(unsigned val, unsigned reg) { - writew_relaxed(val, _port.base + _offsets[reg]); + writew_relaxed(val, _port.base + reg); } -static unsigned _tx_chars(void) { - unsigned bytes = 0; +static void _tx_chars(void) { unsigned fill = RING_BUF_FILL(_port.tx_buf); - for (int i = 0; i < fill; i++) { + while (fill--) { // Check if UART FIFO full - if (_read(REG_FR) & UART01x_FR_TXFF) break; + if (_read(UART01x_FR) & UART01x_FR_TXFF) break; - _write(RING_BUF_PEEK(_port.tx_buf), REG_DR); - RING_BUF_POP(_port.tx_buf); + _write(RING_BUF_PEEK(_port.tx_buf), UART01x_DR); mb(); - _port.tx_bytes++; - bytes++; + RING_BUF_POP(_port.tx_buf); } // Stop TX when buffer is empty if (!RING_BUF_FILL(_port.tx_buf)) { _port.im &= ~UART011_TXIM; - _write(_port.im, REG_IMSC); + _write(_port.im, UART011_IMSC); } - - return bytes; } -static unsigned _rx_chars(void) { - unsigned bytes = 0; +static void _rx_chars(void) { unsigned space = RING_BUF_SPACE(_port.rx_buf); - for (int i = 0; i < space; i++) { + while (space--) { // Check if UART FIFO empty - unsigned status = _read(REG_FR); + unsigned status = _read(UART01x_FR); if (status & UART01x_FR_RXFE) break; // Read char from FIFO and update status - unsigned ch = _read(REG_DR); - _port.rx_bytes++; + unsigned ch = _read(UART01x_DR); // Record errors if (ch & UART011_DR_BE) _port.brk_errs++; @@ -210,45 +154,193 @@ static unsigned _rx_chars(void) { // Queue char RING_BUF_PUSH(_port.rx_buf, ch); - bytes++; } // Stop RX interrupts when buffer is full if (!RING_BUF_SPACE(_port.rx_buf)) { - _port.im &= ~(UART011_RXIM | UART011_RTIM | UART011_FEIM | UART011_PEIM | - UART011_BEIM | UART011_OEIM); - _write(_port.im, REG_IMSC); + _port.im &= ~(UART011_RXIM | UART011_RTIM); + _write(_port.im, UART011_IMSC); } +} + + +static int _read_status(void) { + int status = 0; + + unsigned fr = _read(UART01x_FR); + unsigned cr = _read(UART011_CR); - return bytes; + if (fr & UART01x_FR_DSR) status |= TIOCM_LE; // DSR (data set ready) + if (cr & UART011_CR_DTR) status |= TIOCM_DTR; // DTR (data terminal ready) + if (cr & UART011_CR_RTS) status |= TIOCM_RTS; // RTS (request to send) + // TODO What is TIOCM_ST - Secondary TXD (transmit)? + // TODO What is TIOCM_SR - Secondary RXD (receive)? + if (fr & UART01x_FR_CTS) status |= TIOCM_CTS; // CTS (clear to send) + if (fr & UART01x_FR_DCD) status |= TIOCM_CD; // DCD (data carrier detect) + if (fr & UART011_FR_RI) status |= TIOCM_RI; // RI (ring) + if (fr & UART01x_FR_DSR) status |= TIOCM_DSR; // DSR (data set ready) + + if (debug) printk(KERN_INFO "bbserial: _read_status() = %d\n", status); + + return status; } -static irqreturn_t _interrupt(int irq, void *id) { +static void _write_status(int status) { + if (debug) printk(KERN_INFO "bbserial: _write_status() = %d\n", status); + unsigned long flags; spin_lock_irqsave(&_port.lock, flags); - unsigned rBytes = 0; - unsigned wBytes = 0; + unsigned cr = _read(UART011_CR); + + // DTR (data terminal ready) + if (status & TIOCM_DTR) cr |= UART011_CR_DTR; + else cr &= ~UART011_CR_DTR; + + // RTS (request to send) + if (status & TIOCM_RTS) cr |= UART011_CR_RTS; + else cr &= ~UART011_CR_RTS; + + _write(cr, UART011_CR); + + spin_unlock_irqrestore(&_port.lock, flags); +} + - for (int pass = 0; pass < 256; pass++) { - unsigned status = _read(REG_MIS); - if (!status) break; +static struct ktermios *_get_term(void) { + unsigned lcrh = _read(UART011_LCRH); + unsigned cr = _read(UART011_CR); - // Clear interrupt status - _write(status, REG_ICR); + // Baud rate + unsigned brd = _read(UART011_IBRD) << 6 | _read(UART011_FBRD); + speed_t baud = clk_get_rate(_port.clk) * 4 / brd; + tty_termios_encode_baud_rate(&_port.term, baud, baud); - // Read and/or write - if (status & (UART011_RTIS | UART011_RXIS)) rBytes += _rx_chars(); - if (status & UART011_TXIS) wBytes += _tx_chars(); + // Data bits + unsigned cflag; + switch (lcrh & UART01x_LCRH_WLEN_bm) { + case UART01x_LCRH_WLEN_5: cflag = CS5; break; + case UART01x_LCRH_WLEN_6: cflag = CS6; break; + case UART01x_LCRH_WLEN_7: cflag = CS7; break; + default: cflag = CS8; break; } + // Stop bits + if (lcrh & UART01x_LCRH_STP2) cflag |= CSTOPB; + + // Parity + if (lcrh & UART01x_LCRH_PEN) { + cflag |= PARENB; + + if (!(UART01x_LCRH_EPS & lcrh)) cflag |= PARODD; + if (UART011_LCRH_SPS & lcrh) cflag |= CMSPAR; + } + + // Hardware flow control + if (cr & UART011_CR_CTSEN) cflag |= CRTSCTS; + + _port.term.c_cflag = cflag; + + return &_port.term; +} + + +static void _set_baud(speed_t baud) { + if (debug) printk(KERN_INFO "bbserial: baud=%d\n", baud); + + unsigned brd = clk_get_rate(_port.clk) * 16 / baud; + + if ((brd & 3) == 3) brd = (brd >> 2) + 1; // Round up + else brd >>= 2; + + _write(brd & 0x3f, UART011_FBRD); + _write(brd >> 6, UART011_IBRD); +} + + +static int _set_term(struct ktermios *term) { + unsigned lcrh = UART01x_LCRH_FEN; // Enable FIFOs + unsigned cflag = term->c_cflag; + + // Data bits + switch (cflag & CSIZE) { + case CS5: lcrh |= UART01x_LCRH_WLEN_5; break; + case CS6: lcrh |= UART01x_LCRH_WLEN_6; break; + case CS7: lcrh |= UART01x_LCRH_WLEN_7; break; + default: lcrh |= UART01x_LCRH_WLEN_8; break; + } + + // Stop bits + if (cflag & CSTOPB) lcrh |= UART01x_LCRH_STP2; + + // Parity + if (cflag & PARENB) { + lcrh |= UART01x_LCRH_PEN; + + if (!(cflag & PARODD)) lcrh |= UART01x_LCRH_EPS; + if (cflag & CMSPAR) lcrh |= UART011_LCRH_SPS; + } + + // Get baud rate + speed_t baud = tty_termios_baud_rate(term); + + // Set + unsigned long flags; + spin_lock_irqsave(&_port.lock, flags); + + // Hardware flow control + unsigned cr = _read(UART011_CR); + if (cflag & CRTSCTS) cr |= UART011_CR_CTSEN; + + _write(0, UART011_CR); // Disable + _set_baud(baud); // Baud + _write(lcrh, UART011_LCRH); // Must be after baud + _write(cr, UART011_CR); // Enable + + spin_unlock_irqrestore(&_port.lock, flags); + + return 0; +} + + +static void _flush_input(void) { + unsigned long flags; + spin_lock_irqsave(&_port.lock, flags); + + RING_BUF_CLEAR(_port.rx_buf); + + spin_unlock_irqrestore(&_port.lock, flags); +} + + +static void _flush_output(void) { + unsigned long flags; + spin_lock_irqsave(&_port.lock, flags); + + RING_BUF_CLEAR(_port.tx_buf); + + spin_unlock_irqrestore(&_port.lock, flags); +} + + +static irqreturn_t _interrupt(int irq, void *id) { + unsigned long flags; + spin_lock_irqsave(&_port.lock, flags); + + // Read and/or write + unsigned status = _read(UART011_MIS); + if (status & (UART011_RTIS | UART011_RXIS)) _rx_chars(); + if (status & UART011_TXIS) _tx_chars(); + + unsigned txSpace = RING_BUF_SPACE(_port.tx_buf); + unsigned rxFill = RING_BUF_FILL(_port.rx_buf); + spin_unlock_irqrestore(&_port.lock, flags); // Notify pollers - if ((rBytes && (_port.req_events & POLLIN)) || - (wBytes && (_port.req_events & POLLOUT))) - wake_up_interruptible(&_port.wait); + if (rxFill) wake_up_interruptible_poll(&_port.read_wait, POLLIN); + if (txSpace) wake_up_interruptible_poll(&_port.write_wait, POLLOUT); return IRQ_HANDLED; } @@ -259,26 +351,32 @@ static void _enable_tx(void) { spin_lock_irqsave(&_port.lock, flags); _port.im |= UART011_TXIM; - _write(_port.im, REG_IMSC); + _write(_port.im, UART011_IMSC); _tx_chars(); // Must prime the pump spin_unlock_irqrestore(&_port.lock, flags); } +static int _tx_enabled(void) {return _port.im & UART011_TXIM;} + + static void _enable_rx(void) { unsigned long flags; spin_lock_irqsave(&_port.lock, flags); _port.im |= UART011_RTIM | UART011_RXIM; - _write(_port.im, REG_IMSC); + _write(_port.im, UART011_IMSC); spin_unlock_irqrestore(&_port.lock, flags); } +static int _rx_enabled(void) {return _port.im & (UART011_RTIM | UART011_RXIM);} + + static int _dev_open(struct inode *inodep, struct file *filep) { - if (_debug) printk(KERN_INFO "bbserial: open()\n"); + if (debug) printk(KERN_INFO "bbserial: open()\n"); if (_port.open) return -EBUSY; _port.open = 1; return 0; @@ -287,41 +385,37 @@ static int _dev_open(struct inode *inodep, struct file *filep) { static ssize_t _dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) { - if (_debug) printk(KERN_INFO "bbserial: read() len=%d\n", len); + if (debug) printk(KERN_INFO "bbserial: read() len=%d overruns=%d\n", len, + _port.overruns); + ssize_t bytes = 0; - // TODO read whole blocks - while (len && RING_BUF_FILL(_port.rx_buf)) { + while (bytes < len && RING_BUF_FILL(_port.rx_buf)) { put_user(RING_BUF_PEEK(_port.rx_buf), buffer++); RING_BUF_POP(_port.rx_buf); - len--; bytes++; + if (!_rx_enabled()) _enable_rx(); } - if (bytes) _enable_rx(); - return bytes ? bytes : -EAGAIN; } static ssize_t _dev_write(struct file *filep, const char *buffer, size_t len, - loff_t *offset) { - if (_debug) + loff_t *offset) { + if (debug) printk(KERN_INFO "bbserial: write() len=%d tx=%d rx=%d\n", len, RING_BUF_FILL(_port.tx_buf), RING_BUF_FILL(_port.rx_buf)); ssize_t bytes = 0; - // TODO write whole blocks - while (len && RING_BUF_SPACE(_port.tx_buf)) { + while (bytes < len && RING_BUF_SPACE(_port.tx_buf)) { get_user(RING_BUF_POKE(_port.tx_buf), buffer++); RING_BUF_INC(_port.tx_buf, head); - len--; bytes++; + if (!_tx_enabled()) _enable_tx(); } - if (bytes) _enable_tx(); - return bytes ? bytes : -EAGAIN; } @@ -334,34 +428,76 @@ static int _dev_release(struct inode *inodep, struct file *filep) { static unsigned _dev_poll(struct file *file, poll_table *wait) { - if (_debug) printk(KERN_INFO "bbserial: poll(tx=%d rx=%d)\n", - RING_BUF_FILL(_port.tx_buf), RING_BUF_FILL(_port.rx_buf)); + if (debug) { + unsigned events = poll_requested_events(wait); + printk(KERN_INFO "bbserial: poll(in=%s, out=%s)\n", + (events & POLLIN) ? "true" : "false", + (events & POLLOUT) ? "true" : "false"); + } - _port.req_events = poll_requested_events(wait); - poll_wait(file, &_port.wait, wait); - _port.req_events = 0; + poll_wait(file, &_port.read_wait, wait); + poll_wait(file, &_port.write_wait, wait); unsigned ret = 0; - if (RING_BUF_SPACE(_port.tx_buf)) ret |= POLLOUT | POLLWRNORM; if (RING_BUF_FILL(_port.rx_buf)) ret |= POLLIN | POLLRDNORM; + if (RING_BUF_SPACE(_port.tx_buf)) ret |= POLLOUT | POLLWRNORM; + + if (debug) printk(KERN_INFO "bbserial: tx=%d rx=%d\n", + RING_BUF_FILL(_port.tx_buf), RING_BUF_FILL(_port.rx_buf)); return ret; } static long _dev_ioctl(struct file *file, unsigned cmd, unsigned long arg) { - if (_debug) printk(KERN_INFO "bbserial: ioctl() cmd=%d arg=%lu\n", cmd, arg); + if (debug) + printk(KERN_INFO "bbserial: ioctl() cmd=0x%04x arg=%lu\n", cmd, arg); int __user *ptr = (int __user *)arg; + int status; switch (cmd) { - case TCGETS: // TODO Get serial port settings - case TCSETS: // TODO Set serial port settings - case TIOCMBIS: // TODO Set modem control state + case TCGETS: { // Get serial port settings + struct ktermios *term = _get_term(); + if (copy_to_user((void __user *)arg, &term, sizeof(struct termios))) + return -EFAULT; return 0; + } + + case TCSETS: { // Set serial port settings + struct ktermios term; + if (copy_from_user(&term, (void __user *)arg, sizeof(struct termios))) + return -EFAULT; + return _set_term(&term); + } + + case TIOCMGET: // Get status of modem bits + put_user(_read_status(), ptr); + return 0; + + case TIOCMSET: // Set status of modem bits + get_user(status, ptr); + _write_status(status); + return 0; + + case TIOCMBIC: // Clear indicated modem bits + get_user(status, ptr); + _write_status(~status & _read_status()); + return 0; + + case TIOCMBIS: // Set indicated modem bits + get_user(status, ptr); + _write_status(status | _read_status()); + return 0; + + case TCFLSH: // Flush + if (arg == TCIFLUSH || arg == TCIOFLUSH) _flush_input(); + if (arg == TCOFLUSH || arg == TCIOFLUSH) _flush_output(); + return 0; + + case TIOCINQ: return put_user(RING_BUF_FILL(_port.rx_buf), ptr); + case TIOCOUTQ: return put_user(RING_BUF_FILL(_port.tx_buf), ptr); - case TCFLSH: return 0; - case FIONREAD: return put_user(RING_BUF_FILL(_port.rx_buf), ptr); default: return -ENOIOCTLCMD; } @@ -381,7 +517,7 @@ static struct file_operations _ops = { static int _probe(struct amba_device *dev, const struct amba_id *id) { - if (_debug) printk(KERN_INFO "bbserial: probing\n"); + if (debug) printk(KERN_INFO "bbserial: probing\n"); // Allocate buffers _port.tx_buf.buf = devm_kzalloc(&dev->dev, BUF_SIZE, GFP_KERNEL); @@ -392,7 +528,7 @@ static int _probe(struct amba_device *dev, const struct amba_id *id) { _port.base = devm_ioremap_resource(&dev->dev, &dev->res); if (IS_ERR(_port.base)) { dev_err(&dev->dev, "bbserial: failed to map IO memory\n"); - return PTR_ERR(_port.base); + return PTR_ERR(_port.base); } // Get and enable clock @@ -409,33 +545,28 @@ static int _probe(struct amba_device *dev, const struct amba_id *id) { } // Disable UART and mask interrupts - _write(0, REG_CR); - _write(0, REG_IMSC); + _write(0, UART011_CR); + _write(0, UART011_IMSC); - // Set baud rate - const unsigned baud = 230400; - unsigned brd = clk_get_rate(_port.clk) * 16 / baud; - if ((brd & 3) == 3) brd = (brd >> 2) + 1; - else brd >>= 2; - _write(brd & 0x3f, REG_FBRD); - _write(brd >> 6, REG_IBRD); + // Set default baud rate + _set_baud(38400); - // N81 & enable FIFOs - _write(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, REG_LCRH_RX); + // N81 & enable FIFOs, must be after baud + _write(UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN, UART011_LCRH); // Enable, TX, RX, RTS, DTR & CTS unsigned cr = UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE | UART011_CR_RTS | UART011_CR_DTR | UART011_CR_CTSEN; - _write(cr, REG_CR); + _write(cr, UART011_CR); // Set interrupt FIFO trigger levels - _write(UART011_IFLS_RX2_8 | UART011_IFLS_TX6_8, REG_IFLS); + _write(UART011_IFLS_RX2_8 | UART011_IFLS_TX6_8, UART011_IFLS); // Clear pending interrupts - _write(0x7ff, REG_ICR); + _write(0x7ff, UART011_ICR); // Enable read interrupts - _port.im = _read(REG_IMSC); + _port.im = 0; _enable_rx(); // Allocate IRQ @@ -461,7 +592,7 @@ static int _probe(struct amba_device *dev, const struct amba_id *id) { if (IS_ERR(_port.class)) { unregister_chrdev(_port.major, DEVICE_NAME); clk_disable_unprepare(_port.clk); - dev_err(&dev->dev, "bbserial: ailed to register device class\n"); + dev_err(&dev->dev, "bbserial: failed to register device class\n"); return PTR_ERR(_port.class); } @@ -480,17 +611,17 @@ static int _probe(struct amba_device *dev, const struct amba_id *id) { static int _remove(struct amba_device *dev) { - if (_debug) printk(KERN_INFO "bbserial: removing\n"); + if (debug) printk(KERN_INFO "bbserial: removing\n"); unsigned long flags; spin_lock_irqsave(&_port.lock, flags); // Mask and clear interrupts - _write(0, REG_IMSC); - _write(0x7ff, REG_ICR); + _write(0, UART011_IMSC); + _write(0x7ff, UART011_ICR); // Disable UART - _write(0, REG_CR); + _write(0, UART011_CR); spin_unlock_irqrestore(&_port.lock, flags); @@ -542,7 +673,8 @@ static int __init bbserial_init(void) { spin_lock_init(&_port.lock); // Init wait queues - init_waitqueue_head(&_port.wait); + init_waitqueue_head(&_port.read_wait); + init_waitqueue_head(&_port.write_wait); return amba_driver_register(&_driver); } diff --git a/src/js/indicators.js b/src/js/indicators.js index 0586673..0285784 100644 --- a/src/js/indicators.js +++ b/src/js/indicators.js @@ -80,17 +80,17 @@ module.exports = { }, - motor_fault_class: function (motor, fault) { + motor_fault_class: function (motor, bit) { if (typeof motor == 'undefined') { var status = this.state['fa']; if (typeof status == 'undefined') return 'fa-question'; return 'fa-thumbs-' + (status ? 'down error' : 'up success') } - var status = this.state[motor + 'ds']; - if (typeof status == 'undefined') return 'fa-question'; - return status.indexOf(fault) == -1 ? 'fa-thumbs-up success' : - 'fa-thumbs-down error'; + var flags = this.state[motor + 'df']; + if (typeof flags == 'undefined') return 'fa-question'; + return (flags & (1 << bit)) ? 'fa-thumbs-down error' : + 'fa-thumbs-up success'; }, diff --git a/src/pug/index.pug b/src/pug/index.pug index f960c0c..34e56b5 100644 --- a/src/pug/index.pug +++ b/src/pug/index.pug @@ -95,6 +95,9 @@ html(lang="en") .title span.left Build span.right botics + .fa.fa-thermometer-full(class="error", + v-if="80 <= state.rpi_temp", + title="Raspberry Pi temperature too high.") .subtitle | CNC Controller #[b {{state.demo ? 'Demo ' : ''}}] | v{{config.version}} diff --git a/src/pug/templates/admin-general-view.pug b/src/pug/templates/admin-general-view.pug index 37040dc..cbcfa24 100644 --- a/src/pug/templates/admin-general-view.pug +++ b/src/pug/templates/admin-general-view.pug @@ -52,7 +52,7 @@ script#admin-general-view-template(type="text/x-template") button.pure-button.pure-button-primary(@click="confirmReset = true") Reset message(:show.sync="confirmReset") h3(slot="header") Reset to default configuration? - p(slot="body") All configuration changes will be lost. + p(slot="body") Non-network configuration changes will be lost. div(slot="footer") button.pure-button(@click="confirmReset = false") Cancel button.pure-button.button-success(@click="reset") OK diff --git a/src/pug/templates/indicators.pug b/src/pug/templates/indicators.pug index 0569732..70821c5 100644 --- a/src/pug/templates/indicators.pug +++ b/src/pug/templates/indicators.pug @@ -191,17 +191,17 @@ script#indicators-template(type="text/x-template") tr(v-for="motor in [0, 1, 2, 3]") td {{motor}} - td: .fa(:class="motor_fault_class(motor, 'temp')", + td: .fa(:class="motor_fault_class(motor, 0)", title="Overtemperature fault") - td: .fa(:class="motor_fault_class(motor, 'current a')", + td: .fa(:class="motor_fault_class(motor, 1)", title="Overcurrent motor channel A") - td: .fa(:class="motor_fault_class(motor, 'fault a')", + td: .fa(:class="motor_fault_class(motor, 3)", title="Predriver fault motor channel A") - td: .fa(:class="motor_fault_class(motor, 'current b')", + td: .fa(:class="motor_fault_class(motor, 2)", title="Overcurrent motor channel B") - td: .fa(:class="motor_fault_class(motor, 'fault b')", + td: .fa(:class="motor_fault_class(motor, 4)", title="Predriver fault motor channel B") - td: .fa(:class="motor_fault_class(motor, 'comm')", + td: .fa(:class="motor_fault_class(motor, 8)", title="Driver communication failure") td(:title="'Reset motor ' + motor + ' flags'") .fa.fa-eraser(@click="motor_reset(motor)") @@ -221,8 +221,8 @@ script#indicators-template(type="text/x-template") td {{state.motor | fixed 2}} A th Motor th.separator - td {{state.temp | fixed 0}} ℃ - th Temp + td {{state.vdd | fixed 1}} V + th Low-side tr td {{state.load1 | fixed 2}} A @@ -231,6 +231,14 @@ script#indicators-template(type="text/x-template") td {{state.load2 | fixed 2}} A th Load 2 + tr + td {{state.temp | fixed 0}} ℃ + th Temp + th.separator + td(:class="{'error': 80 <= state.rpi_temp}") + | {{state.rpi_temp | fixed 0}} ℃ + th RPi Temp + tr td {{state['1ai'] | percent 0}} A th Analog 1 diff --git a/src/py/bbctrl/Config.py b/src/py/bbctrl/Config.py index 68004fc..0034cfe 100644 --- a/src/py/bbctrl/Config.py +++ b/src/py/bbctrl/Config.py @@ -94,9 +94,7 @@ class Config(object): except: return False - if (('min' in template and value < template['min']) or - ('max' in template and template['max'] < value) or - ('values' in template and value not in template['values'])): + if 'values' in template and value not in template['values']: return False return True @@ -108,6 +106,12 @@ class Config(object): not self._valid_value(template, config[name])): config[name] = template['default'] + elif 'max' in template and template['max'] < config[name]: + config[name] = template['max'] + + elif 'min' in template and config[name] < template['min']: + config[name] = template['min'] + if template['type'] == 'list': config = config[name] @@ -182,7 +186,7 @@ class Config(object): def reset(self): - os.unlink('config.json') + if os.path.exists('config.json'): os.unlink('config.json') self.reload() self.ctrl.preplanner.invalidate_all() diff --git a/src/py/bbctrl/Log.py b/src/py/bbctrl/Log.py index 090be36..6bcfbb3 100644 --- a/src/py/bbctrl/Log.py +++ b/src/py/bbctrl/Log.py @@ -27,6 +27,7 @@ import os import sys +import io import datetime import traceback import pkg_resources @@ -43,6 +44,10 @@ ERROR = 3 def get_level_name(level): return 'debug info warning error'.split()[level] +# Get this file's name +_srcfile = os.path.normcase(get_level_name.__code__.co_filename) + + class Logger(object): def __init__(self, log, name, level): self.log = log @@ -54,13 +59,29 @@ class Logger(object): def _enabled(self, level): return self.level <= level and level <= ERROR + def _find_caller(self): + f = sys._getframe() + if f is not None: f = f.f_back + + while hasattr(f, 'f_code'): + co = f.f_code + + filename = os.path.normcase(co.co_filename) + if filename == _srcfile: + f = f.f_back + continue + + return co.co_filename, f.f_lineno, co.co_name + + return '(unknown file)', 0, '(unknown function)' + + def _log(self, level, msg, *args, **kwargs): if not self._enabled(level): return if not 'where' in kwargs: - caller = getframeinfo(stack()[2][0]) - kwargs['where'] = '%s:%d' % ( - os.path.basename(caller.filename), caller.lineno) + filename, line, func = self._find_caller() + kwargs['where'] = '%s:%d' % (os.path.basename(filename), line) if len(args): msg %= args diff --git a/src/py/bbctrl/MonitorTemp.py b/src/py/bbctrl/MonitorTemp.py index 839b2e6..0d1501d 100644 --- a/src/py/bbctrl/MonitorTemp.py +++ b/src/py/bbctrl/MonitorTemp.py @@ -42,9 +42,9 @@ class MonitorTemp(object): def __init__(self, app): self.app = app - ctrl = app.get_ctrl() - self.log = ctrl.log.get('Mon') - self.ioloop = ctrl.ioloop + self.ctrl = app.get_ctrl() + self.log = self.ctrl.log.get('Mon') + self.ioloop = self.ctrl.ioloop self.last_temp_warn = 0 self.temp_thresh = 80 @@ -94,6 +94,7 @@ class MonitorTemp(object): try: temp = read_temp() + self.ctrl.state.set('rpi_temp', temp) self.scale_cpu(temp) self.update_camera(temp) self.log_warnings(temp) diff --git a/src/py/bbctrl/__init__.py b/src/py/bbctrl/__init__.py index 3f54b19..bf6dd24 100644 --- a/src/py/bbctrl/__init__.py +++ b/src/py/bbctrl/__init__.py @@ -126,7 +126,7 @@ def parse_args(): type = int, help = 'HTTP port') parser.add_argument('-a', '--addr', metavar = 'IP', default = '0.0.0.0', help = 'HTTP address to bind') - parser.add_argument('-s', '--serial', default = '/dev/ttyBB0', + parser.add_argument('-s', '--serial', default = '/dev/ttyAMA0', help = 'Serial device') parser.add_argument('-b', '--baud', default = 230400, type = int, help = 'Serial baud rate') diff --git a/src/resources/config-template.json b/src/resources/config-template.json index 591e18a..0b988b5 100644 --- a/src/resources/config-template.json +++ b/src/resources/config-template.json @@ -34,7 +34,7 @@ "drive-current": { "type": "float", "min": 0, - "max": 8, + "max": 6, "unit": "amps", "default": 1.5, "code": "dc"