diff --git a/scripts/Xresources b/scripts/Xresources new file mode 100644 index 0000000..e700215 --- /dev/null +++ b/scripts/Xresources @@ -0,0 +1,2 @@ +xterm*faceSize: 12 +xterm*faceName: DejaVu Sans Mono diff --git a/scripts/bbctrl-logrotate b/scripts/bbctrl-logrotate new file mode 100644 index 0000000..906336d --- /dev/null +++ b/scripts/bbctrl-logrotate @@ -0,0 +1,8 @@ +/var/log/bbctrl.log { + rotate 4 + weekly + compress + missingok + notifempty + copytruncate +} diff --git a/scripts/cron_d_reboot b/scripts/cron_d_reboot new file mode 100644 index 0000000..7fc7455 --- /dev/null +++ b/scripts/cron_d_reboot @@ -0,0 +1 @@ +@reboot root run-parts /etc/cron.reboot diff --git a/scripts/cron_reboot_logrotate b/scripts/cron_reboot_logrotate new file mode 100644 index 0000000..f4f56a9 --- /dev/null +++ b/scripts/cron_reboot_logrotate @@ -0,0 +1,4 @@ +#!/bin/sh + +test -x /usr/sbin/logrotate || exit 0 +/usr/sbin/logrotate /etc/logrotate.conf diff --git a/scripts/install.sh b/scripts/install.sh index 0363384..3fb429e 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -93,7 +93,9 @@ if [ $? -ne 0 ]; then REBOOT=true fi -# Install xinitrc +# Install .Xresources & .xinitrc +cp scripts/Xresources ~pi/.Xresources +chown pi:pi ~pi/.Xresources cp scripts/xinitrc ~pi/.xinitrc chmod +x ~pi/.xinitrc chown pi:pi ~pi/.xinitrc @@ -133,6 +135,54 @@ if $UPDATE_PY; then chmod 777 $HTTP_DIR fi +# Expand the file system if necessary +chmod +x ./scripts/resize_root_fs.sh +./scripts/resize_root_fs.sh +if [ $? -eq 0 ]; then + REBOOT=true +fi + +# Install our logrotate config +cp ./scripts/bbctrl-logrotate /etc/logrotate.d/bbctrl +chown root:root /etc/logrotate.d/bbctrl + +# Ensure logrotate runs on every boot (for systems with no network, thus bad clock) +if [ ! -e /etc/cron.d/reboot ]; then + cp ./scripts/cron_d_reboot /etc/cron.d/reboot + mkdir -p /etc/cron.reboot + cp ./scripts/cron_reboot_logrotate /etc/cron.reboot/logrotate +fi + +########################################## +# Begin one-time cleanup tasks for 1.0.7 +########################################## + +# Delete the entire local Chromium configuration. Start clean. +rm -rf /home/pi/.config/chromium + +# Get rid of some old files that were left behind +rm -rf /home/pi/hostinfo.txt +rm -rf /home/pi/ssidinfo.txt +rm -rf /home/bbmc/bbctrl-1.0.0.tar.bz2 +rm -rf /home/bbmc/hostinfo.sh +rm -rf /home/bbmc/index.html +rm -rf /home/bbmc/favicon.ico + +# Force a logrotate to get everything into a known state +logrotate -f /etc/logrotate.conf + +# Clean up the log directory - get rid of everything old +rm -rf /var/log/*.gz +rm -rf /var/log/*.1 +rm -rf /var/log/*.old +rm -rf /var/log/bbctrl.2019*.install +rm -rf /var/log/bbctrl.2020*.install +rm -rf /var/log/bbctrl.log.* + +########################################## +# End one-time cleanup tasks for 1.0.7 +########################################## + sync if $REBOOT; then diff --git a/scripts/ratpoisonrc b/scripts/ratpoisonrc index 98b5e1d..6f4219a 100644 --- a/scripts/ratpoisonrc +++ b/scripts/ratpoisonrc @@ -4,3 +4,4 @@ set fgcolor white unbind c bind c exec x-terminal-emulator -fg white -bg black +bind C-c exec x-terminal-emulator -fg white -bg black diff --git a/scripts/resize2fs_once b/scripts/resize2fs_once new file mode 100644 index 0000000..38a4d47 --- /dev/null +++ b/scripts/resize2fs_once @@ -0,0 +1,25 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: resize2fs_once +# Required-Start: +# Required-Stop: +# Default-Start: 3 +# Default-Stop: +# Short-Description: Resize the root filesystem to fill partition +# Description: +### END INIT INFO +. /lib/lsb/init-functions +case "$1" in + start) + log_daemon_msg "Starting resize2fs_once" + ROOT_DEV=$(findmnt / -o source -n) && + resize2fs $ROOT_DEV && + update-rc.d resize2fs_once remove && + rm /etc/init.d/resize2fs_once && + log_end_msg $? + ;; + *) + echo "Usage: $0 start" >&2 + exit 3 + ;; +esac diff --git a/scripts/resize_root_fs.sh b/scripts/resize_root_fs.sh new file mode 100755 index 0000000..16a4619 --- /dev/null +++ b/scripts/resize_root_fs.sh @@ -0,0 +1,79 @@ +#!/bin/bash + +# Used by the OneFinity firmware to determine if the root filesystem +# needs to be enlarged to maximize usage of the SD card. +# +# The majority of this code originates from /usr/lib/raspi-config/init_resize.sh + +get_fs_resize_variables () { + ROOT_PART_DEV=$(findmnt / -o source -n) + ROOT_PART_NAME=$(echo "$ROOT_PART_DEV" | cut -d "/" -f 3) + ROOT_DEV_NAME=$(echo /sys/block/*/"${ROOT_PART_NAME}" | cut -d "/" -f 4) + ROOT_DEV="/dev/${ROOT_DEV_NAME}" + ROOT_PART_NUM=$(cat "/sys/block/${ROOT_DEV_NAME}/${ROOT_PART_NAME}/partition") + BOOT_PART_DEV=$(findmnt /boot -o source -n) + BOOT_PART_NAME=$(echo "$BOOT_PART_DEV" | cut -d "/" -f 3) + BOOT_DEV_NAME=$(echo /sys/block/*/"${BOOT_PART_NAME}" | cut -d "/" -f 4) + ROOT_DEV_SIZE=$(cat "/sys/block/${ROOT_DEV_NAME}/size") + TARGET_END=$((ROOT_DEV_SIZE - 1)) + PARTITION_TABLE=$(parted -m "$ROOT_DEV" unit s print | tr -d 's') + LAST_PART_NUM=$(echo "$PARTITION_TABLE" | tail -n 1 | cut -d ":" -f 1) + ROOT_PART_LINE=$(echo "$PARTITION_TABLE" | grep -e "^${ROOT_PART_NUM}:") + ROOT_PART_END=$(echo "$ROOT_PART_LINE" | cut -d ":" -f 3) +} + +should_resize_root_partition() { + get_fs_resize_variables + + if [ "$BOOT_DEV_NAME" != "$ROOT_DEV_NAME" ]; then + FAIL_REASON="Boot and root partitions are on different devices" + return 1 + fi + + if [ "$ROOT_PART_NUM" -ne "$LAST_PART_NUM" ]; then + FAIL_REASON="Root partition should be last partition" + return 1 + fi + + if [ "$ROOT_PART_END" -gt "$TARGET_END" ]; then + FAIL_REASON="Root partition runs past the end of device" + echo $FAIL_REASON + return 1 + fi + + if [ ! -b "$ROOT_DEV" ] || [ ! -b "$ROOT_PART_DEV" ] || [ ! -b "$BOOT_PART_DEV" ] ; then + FAIL_REASON="Could not determine partitions" + return 1 + fi + + if [ "$ROOT_PART_END" -eq "$TARGET_END" ]; then + FAIL_REASON="Root partition is already expanded" + return 1 + fi +} + +if should_resize_root_partition; then + grep "init_resize" /boot/cmdline.txt >/dev/null + if [ $? -ne 0 ]; then + # On the next boot, init_resize.sh will: + # Resize the root partition to use the rest of the SD card + # Remove itself from /boot/cmdline.txt + # Reboot the machine + sudo mount /boot -o rw,remount + sed -i 's/\(.*\)/\1 init=\/usr\/lib\/raspi-config\/init_resize.sh/' /boot/cmdline.txt + fi + + # On the first boot after init_resize, resize2fs_once will: + # Resize the root fs to fill its partition + # Remove itself from the registered systemd services + # Delete itself from the filesystem + # Therefore, never run again + cp scripts/resize2fs_once /etc/init.d/resize2fs_once + chmod +x /etc/init.d/resize2fs_once + systemctl enable resize2fs_once + + exit 0 +else + echo "Not resizing root partition: $FAIL_REASON" + exit 1 +fi diff --git a/scripts/xinitrc b/scripts/xinitrc index 69360a8..08af117 100644 --- a/scripts/xinitrc +++ b/scripts/xinitrc @@ -14,6 +14,8 @@ while true; do sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' $PREFS sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' $PREFS + xrdb /home/pi/.Xresources + # Start browser /usr/local/bin/browser --no-first-run --disable-infobars \ --noerrdialogs --disable-3d-apis http://localhost/ diff --git a/src/js/app.js b/src/js/app.js index 175ed11..b32ce2d 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -114,7 +114,11 @@ module.exports = new Vue({ motors: [{}, {}, {}, {}], version: '' }, - state: {messages: []}, + state: { + messages: [], + wait_for_probing_complete: false, + show_probe_complete_modal: false + }, video_size: cookie.get('video-size', 'small'), crosshair: cookie.get('crosshair', 'false') != 'false', errorTimeout: 30, diff --git a/src/js/message.js b/src/js/message.js index a720511..57c1fae 100644 --- a/src/js/message.js +++ b/src/js/message.js @@ -36,6 +36,12 @@ module.exports = { type: Boolean, required: true, twoWay: true + }, + + class: { + type: String, + required: false, + twoWay: false } } } diff --git a/src/js/path-viewer.js b/src/js/path-viewer.js index 3cd1d01..03d4d0b 100644 --- a/src/js/path-viewer.js +++ b/src/js/path-viewer.js @@ -27,23 +27,12 @@ var orbit = require('./orbit'); var cookie = require('./cookie')('bbctrl-'); -var api = require('./api'); var font = require('./helvetiker_regular.typeface.json') - -function get(obj, name, defaultValue) { - return typeof obj[name] == 'undefined' ? defaultValue : obj[name]; -} - - -var surfaceModes = ['cut', 'wire', 'solid', 'off']; - - module.exports = { template: '#path-viewer-template', props: ['toolpath'], - data: function () { return { enabled: false, @@ -62,7 +51,22 @@ module.exports = { computed: { - target: function () {return $(this.$el).find('.path-viewer-content')[0]} + target: function () { + return $(this.$el).find('.path-viewer-content')[0] + }, + + webglAvailable: function() { + // Create canvas element. The canvas is not added to the + // document itself, so it is never displayed in the + // browser window. + const canvas = document.createElement("canvas"); + + // Get WebGLRenderingContext from canvas element. + const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + + // Report the result. + return gl && gl instanceof WebGLRenderingContext; + } }, @@ -122,6 +126,10 @@ module.exports = { methods: { update: function () { + if (!this.webglAvailable) { + return; + } + if (!this.state.selected) { this.dirty = true; this.scene = new THREE.Scene(); @@ -269,6 +277,10 @@ module.exports = { graphics: function () { + if (!this.webglAvailable) { + return; + } + try { // Renderer this.renderer = new THREE.WebGLRenderer({antialias: true, alpha: true}); @@ -280,6 +292,7 @@ module.exports = { console.log('WebGL not supported: ', e); return; } + this.enabled = true; // Camera diff --git a/src/pug/templates/control-view.pug b/src/pug/templates/control-view.pug index fdeb438..d17e791 100644 --- a/src/pug/templates/control-view.pug +++ b/src/pug/templates/control-view.pug @@ -311,55 +311,54 @@ script#control-view-template(type="text/x-template") label {{(progress || 0) | percent}} .bar(:style="'width:' + (progress || 0) * 100 + '%'") tr + message(:show.sync=`show_probe_test_modal`) - td(style="white-space: nowrap;text-align:center") - message(:show.sync=`show_probe_test_modal`) + h3(slot="header") Test probe connection - h3(slot="header") Test probe connection + div(slot="body") + .pure-form + p Attach the probe magnet to the collet. + p Touch the probe block to the bit. - div(slot="body") - .pure-form - p Attach the probe magnet to the collet. - p Touch the probe block to the bit. + div(slot="footer") + button.pure-button(@click=`show_probe_test_modal = false`) + | Cancel - div(slot="footer") - button.pure-button(@click=`show_probe_test_modal = false`) - | Cancel + button.pure-button.button-success( + :disabled=`!state.saw_probe_connected` + @click=`finish_probe_test()`) Continue - button.pure-button.button-success( - :disabled=`!state.saw_probe_connected` - @click=`finish_probe_test()`) Continue + message(:show.sync=`show_tool_diameter_modal`) + h3(slot="header") Enter probe tool information - message(:show.sync=`show_tool_diameter_modal`) - h3(slot="header") Enter probe tool information + div(slot="body") + .pure-form + .pure-control-group + label="{{metric ? 'Diameter (mm)' : 'Diameter (inches)'}}" + input(v-model="tool_diameter",size="8", + @keyup.enter=`set_tool_diameter(tool_diameter)`) + p - div(slot="body") - .pure-form - .pure-control-group - label="{{metric ? 'Diameter (mm)' : 'Diameter (inches)'}}" - input(v-model="tool_diameter",size="8", - @keyup.enter=`set_tool_diameter(tool_diameter)`) - p + div(slot="footer") + button.pure-button(@click=`show_tool_diameter_modal = false`) + | Cancel - div(slot="footer") - button.pure-button(@click=`show_tool_diameter_modal = false`) - | Cancel + button.pure-button.button-success( + @click=`set_tool_diameter(tool_diameter)`) + | Set - button.pure-button.button-success( - @click=`set_tool_diameter(tool_diameter)`) - | Set + message(:show.sync=`state.show_probe_complete_modal`) + h3(slot="header") Probing complete! - message(:show.sync=`state.show_probe_complete_modal`) - h3(slot="header") Probing complete! + div(slot="body") + .pure-form + p Don't forget to put away the probe! - div(slot="body") - .pure-form - p Don't forget to put away the probe! - - div(slot="footer") - button.pure-button.button-success(@click=`state.show_probe_complete_modal = false`) - | Done + div(slot="footer") + button.pure-button.button-success(@click=`state.show_probe_complete_modal = false`) + | Done + td.control-buttons(style="white-space: nowrap;text-align:center") button(:class="state['pw'] ? '' : 'load-on'", style="height:100px;width:200px", @click=`start_probe_test(() => { show_tool_diameter_modal = true })`) diff --git a/src/pug/templates/message.pug b/src/pug/templates/message.pug index 2b724ad..7257547 100644 --- a/src/pug/templates/message.pug +++ b/src/pug/templates/message.pug @@ -26,7 +26,7 @@ //-///////////////////////////////////////////////////////////////////////////// script#message-template(type="text/x-template") - .modal-mask(v-if="show") + .modal-mask(v-if="show", :class="class") .modal-wrapper .modal-container .modal-header diff --git a/src/py/bbctrl/Config.py b/src/py/bbctrl/Config.py index 9dc3685..5dc39ac 100644 --- a/src/py/bbctrl/Config.py +++ b/src/py/bbctrl/Config.py @@ -151,7 +151,7 @@ class Config(object): if motor['axis'] == 'X' or motor['axis'] == 'Y': motor['search-velocity'] = 1.688 motor['max-velocity'] = 10 - motor['max-jerk'] = 15000 + motor['max-jerk'] = 1000 motor['zero-backoff'] = 1.5 if motor['axis'] == 'Z': motor['search-velocity'] = 0.675 diff --git a/src/py/bbctrl/Log.py b/src/py/bbctrl/Log.py index 0436375..6e1226f 100644 --- a/src/py/bbctrl/Log.py +++ b/src/py/bbctrl/Log.py @@ -170,7 +170,7 @@ class Log(object): if self.path is None: return if self.f is not None: self.f.close() self._rotate(self.path) - self.f = open(self.path, 'w') + self.f = open(self.path, 'a') self.bytes_written = 0