Verison 1.0.3 Release
Based on Buildbotics 0.4.14
This commit is contained in:
25
.gitignore
vendored
Normal file
25
.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
.sconf_temp/
|
||||
.sconsign.dblite
|
||||
/build
|
||||
/dist
|
||||
/crap
|
||||
/pkg
|
||||
/mnt
|
||||
/demo
|
||||
/bbctrl-*
|
||||
node_modules
|
||||
*~
|
||||
\#*
|
||||
*.pyc
|
||||
__pycache__
|
||||
*.egg-info
|
||||
/upload
|
||||
/*.img
|
||||
*.so
|
||||
*.deb
|
||||
*.zip
|
||||
/rpi-share
|
||||
/package-lock.json
|
||||
|
||||
*.elf
|
||||
*.hex
|
||||
394
CHANGELOG.md
Normal file
394
CHANGELOG.md
Normal file
@@ -0,0 +1,394 @@
|
||||
Buildbotics CNC Controller Firmware Changelog
|
||||
=============================================
|
||||
|
||||
## v0.4.14
|
||||
- Handle file uploads with '#' or '?' in the name.
|
||||
- Added "step mode" to Web based jogging.
|
||||
- Fixed touch screen Web jogging.
|
||||
|
||||
## v0.4.13
|
||||
- Support for OMRON MX2 VFD.
|
||||
- Better error handling in WiFi configuration.
|
||||
- Fix open WiFi access.
|
||||
- Improved video camera performance.
|
||||
- Allow up to 4 camera clients at once.
|
||||
- Add axis bounds GCode variables ``#<_x_min>``, ``#<_x_max>``, etc.
|
||||
- Expose ``junction-accel`` planning parameter.
|
||||
- Fixed problem with manual firmware upload on OSX.
|
||||
- Ignore cameras that do not support MJPEG format video.
|
||||
|
||||
## v0.4.12
|
||||
- Segments straddle arc in linearization.
|
||||
- Control max-arc-error with GCode var.
|
||||
- Implemented path modes G61, G61.1 & G64 with naive CAM and basic blending.
|
||||
- Log GCode messages to "Messages" tab.
|
||||
- Acknowledging a message on one browser clears it for all.
|
||||
- Automatically reload Web view when file changes.
|
||||
- Added ``config-screen`` script. Web based screen config to come later.
|
||||
- Suppress message popup with (MSG,# No popup message).
|
||||
- Show latest GCode message in ``Message`` field on CONTROL page.
|
||||
- Marked several GCodes supported in cheat sheet.
|
||||
- Solved planner lookahead failure for most reasonable cases.
|
||||
- Prevent cutting off distant parts of 3D path view.
|
||||
- Raised default ``latch-backoff`` to 100mm and ``zero-backoff`` to 5mm.
|
||||
- Added ``max-deviation`` option.
|
||||
- Fixed problem with GCode boolean expression parsing. #232.
|
||||
- Ensure 2uS step pulse width.
|
||||
|
||||
## v0.4.11
|
||||
- Don't reset global offsets on M2.
|
||||
- Test shunt and show error on failure.
|
||||
- Report spindle status codes from Modbus.
|
||||
- Save more log files in bug report.
|
||||
- Fixed indicators low-side units.
|
||||
- Support for YL600, YL620 & YL620-A VFDs.
|
||||
- Move Modbus indicators to tool page.
|
||||
- Support for Sunfar E300 VFD.
|
||||
- Set GCODE_SCRIPT_PATH to support GCode file routines.
|
||||
- Fix pause bug introduced in v0.4.10.
|
||||
|
||||
## v0.4.10
|
||||
- Fix demo password check
|
||||
- Fix bug were fast clicks could cause jog commands to arrive out of order.
|
||||
- Fix 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.
|
||||
- Put controller into estop when in power shutdown.
|
||||
|
||||
## 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 service instead of init.d.
|
||||
- Fix planner terminate.
|
||||
- Changed AVR serial interrupt priorites.
|
||||
- Increased AVR serial and command buffers.
|
||||
- Boost HDMI signal.
|
||||
- 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.
|
||||
- Added ``switch-debounce`` and ``switch-lockout`` config options.
|
||||
- Handle corrupt GCode simulation data correctly.
|
||||
- Fixes for exception logging.
|
||||
- Always limit motor max-velocity. #209
|
||||
- Sync GCode and planner files to disk after write.
|
||||
- Added warning about reliability in a noisy environment on WiFi config page.
|
||||
- EStop on motor fault.
|
||||
- Fixed ETA line wrapping on Web interface.
|
||||
- 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.
|
||||
- Don't allow manual axis homing when soft limits are not set.
|
||||
- Right click to enable camera crosshair.
|
||||
- Demo mode.
|
||||
- Limit idle-current to 2A.
|
||||
- Removed dangerous ``power-mode`` in favor of simpler ``enabled`` option.
|
||||
- Fixed bug where motor driver could fail to disabled during estop.
|
||||
- Restored estop text.
|
||||
|
||||
## v0.4.5
|
||||
- Fix for random errors while running VFD.
|
||||
- Fix bug where planner would not continue after optional pause (M1).
|
||||
- Fix lockup on invalid no move probe G38.x. #183
|
||||
- Fix zeroing homed axis after jog.
|
||||
- Fix VFD communication at higher baud rates (> 9600). #184
|
||||
|
||||
## v0.4.4
|
||||
- Write version to log file.
|
||||
- Write time to log file periodically.
|
||||
- Show simulation progress with or with out 3D view.
|
||||
- Synchronize file list between browsers.
|
||||
- Increased max simulation time to 24hrs.
|
||||
- Added button to download current GCode file.
|
||||
- Blink play button to indicate pause.
|
||||
- Many layout tweaks/improvements.
|
||||
- Don't abort simulations when system time changes.
|
||||
- Only allow one camera stream at a time.
|
||||
|
||||
## v0.4.2
|
||||
- Suppress ``Auto-creating missing tool`` warning.
|
||||
- Prevent ``Stream is closed`` error.
|
||||
- Suppress ``WebGL not supported`` warning.
|
||||
- Fixed Web disconnect during simulation of large GCode.
|
||||
- Disable outputs on estop.
|
||||
- Improved switch debouncing for better homing.
|
||||
- Handle zero length dwell correctly.
|
||||
- Fixed problem with cached GCode file upload when file changed on disk.
|
||||
- Run simulation at low process priority.
|
||||
- Added ``Bug Report`` button to ``Admin`` -> ``General``.
|
||||
- Only render 3D view as needed to save CPU.
|
||||
- Prevent lockup due to browser causing out of memory condition.
|
||||
- Show error message when too large GCode upload fails.
|
||||
- Much faster 3D view loading.
|
||||
|
||||
## v0.4.1
|
||||
- Fix toolpath view axes bug.
|
||||
- Added LASER intensity view.
|
||||
- Fixed reverse path planner bug.
|
||||
- Video size and path view controls persistent over browser reload.
|
||||
- Fixed time and progress bugs.
|
||||
- Added PWM rapid auto off feature for LASER/Plasma.
|
||||
- Added dynamic PWM for LASER/Plasma.
|
||||
- Added motor faults table to indicators page.
|
||||
- Emit error and indicate FAULT on axis for motor driver faults.
|
||||
- Display axis motor FAULT on LCD.
|
||||
- Fixed bug with rapid repeated unpause.
|
||||
|
||||
## v0.4.0
|
||||
- Increased display precision of position and motor config.
|
||||
- Added support for 256 microstepping.
|
||||
- Smoother operation at 250k step rate by doubling clock as needed.
|
||||
- Indicators tab improvements.
|
||||
- Much improved camera support.
|
||||
- Camera hotpluging.
|
||||
- Move camera video to header.
|
||||
- Click to switch video size.
|
||||
- Automount/unmount USB drives.
|
||||
- Automatically install ``buildbotics.gc`` when no other GCode exists.
|
||||
- Preplan GCode and check for errors.
|
||||
- Display 3D view of program tool paths in browser.
|
||||
- Display accurate time remaining, ETA and progress during run.
|
||||
- Automatically collapse moves in planner which are too short in time.
|
||||
- Show IO status indicators on configuration pages.
|
||||
- Check that axis dimensions fit path plan dimensions.
|
||||
- Show machine working envelope in path plan viewer.
|
||||
- Don't reload browser view on reconnect unless controller has reloaded.
|
||||
- Increased max switch backoff search distance.
|
||||
- Major improvements for LASER raster GCodes.
|
||||
- Fixed major bug in command queuing.
|
||||
- Ignore Program Number O-Codes.
|
||||
- Improved planning of collinear line segments.
|
||||
- Allow PWM output up to 320kHz and no slower than 8Hz.
|
||||
|
||||
## v0.3.28
|
||||
- Show step rate on motor configuration page.
|
||||
- Limit motor max-velocity such that step rate cannot exceed 250k.
|
||||
- Fixed deceleration bug at full 250k step rate.
|
||||
|
||||
## v0.3.27
|
||||
- Fixed homing in imperial mode.
|
||||
|
||||
## v0.3.26
|
||||
- Removed VFD test.
|
||||
- Show VFD status on configuration page.
|
||||
- Show VFD commands fail counts.
|
||||
- Marked some VFD types as beta.
|
||||
|
||||
## v0.3.25
|
||||
- Error on home if max-soft-limit <= min-soft-limit + 1. #139
|
||||
- Decrease boot time networking delay.
|
||||
- Default to US keyboard layout. #145
|
||||
- Added configuration option to show metric or imperial units in browser. #74
|
||||
- Implemented fine jogging control in Web interface. #147
|
||||
|
||||
## v0.3.24
|
||||
- Added unhome button on axis position popup.
|
||||
- Ignore soft limits of max <= min.
|
||||
- Fixed problem with restarting program in imperial units mode.
|
||||
- Handle GCode with infinite or very long loops correctly.
|
||||
- Fixed Huanyang spindle restart after stop.
|
||||
|
||||
## v0.3.23
|
||||
- Fix for modbus read operation.
|
||||
- Finalized AC-Tech VFD support.
|
||||
- Preliminary FR-D700 VFD support.
|
||||
- Ignore leading zeros in modbus messages.
|
||||
- Handle older PWR firmwares.
|
||||
|
||||
## v0.3.22
|
||||
- Fix position loss after program pause. #130
|
||||
- Correctly handle disabled axes.
|
||||
- Fixed config checkbox not displaying defaulted enabled correctly.
|
||||
- Added Custom Modbus VFD programming.
|
||||
|
||||
## v0.3.21
|
||||
- Implemented M70-M73 modal state save/restore.
|
||||
- Added support for modbus VFDs.
|
||||
- Start Huanyang spindle with out first pressing Start button on VFD.
|
||||
- Faster switching of large GCode files in Web.
|
||||
- Fixed reported gcode line off by one.
|
||||
- Disable MDI input while running.
|
||||
- Stabilized direction pin output during slow moves.
|
||||
|
||||
## v0.3.20
|
||||
- Eliminated drift caused by miscounting half microsteps.
|
||||
- Fixed disappearing GCode in Web.
|
||||
- More efficient GCode scrolling with very large files.
|
||||
- Fully functional soft-limited jogging.
|
||||
- Added client and access-point Wifi configuration.
|
||||
- Fixed broken hostname Web redirect after change.
|
||||
- Split admin page -> General & Network.
|
||||
- Improved calculation of junction velocity limits.
|
||||
|
||||
## v0.3.19
|
||||
- Fixed stopping problems. #127
|
||||
- Fixed ``Negative s-curve time`` error.
|
||||
- Improved jogging with soft limits.
|
||||
- Added site favicon.
|
||||
- Fixed problems with offsets and imperial units.
|
||||
- Fixed ``All zero s-curve times`` caused by extremely short, non-zero moves.
|
||||
- Fixed position drift.
|
||||
|
||||
## v0.3.18
|
||||
- Don't enable any tool by default.
|
||||
|
||||
## v0.3.17
|
||||
- Fixed pausing fail near end of run bug.
|
||||
- Show "Upgrading firmware" when upgrading.
|
||||
- Log excessive pwr communication failures as errors.
|
||||
- Ensure we can still get out of non-idle cycles when there are errors.
|
||||
- Less frequent pwr variable updates.
|
||||
- Stop cancels seek and subsequent estop.
|
||||
- Fixed bug in AVR/Planner command synchronization.
|
||||
- Consistently display HOMING state during homing operation.
|
||||
- Homing zeros axis global offset.
|
||||
- Added zero all button. #126
|
||||
- Separate "Auto" and "MDI" play/pause & stop buttons. #126
|
||||
- Moved home all button. #126
|
||||
- Display "Video camera not found." instead of broken image icon.
|
||||
- Show offset positions not absolute on LCD.
|
||||
- Don't change gcode lines while homing.
|
||||
- Don't change button states while homing.
|
||||
- Adding warning about power cyclying during an upgrade.
|
||||
- Reset planner on AVR errors.
|
||||
- Fixed pausing with short moves.
|
||||
- Corrected s-curve accel increasing jogging velocities.
|
||||
|
||||
## v0.3.16
|
||||
- Fixed switch debounce bug.
|
||||
|
||||
## v0.3.15
|
||||
- Suppress warning missing config.json warning after config reset.
|
||||
- Fixed EStop reboot loop.
|
||||
- Removed AVR unexpected reboot error.
|
||||
|
||||
## v0.3.14
|
||||
- Fixed: Config fails silently after web disconnect #112
|
||||
- Always reload the page after a disconnect.
|
||||
- Honor soft limits #111 (but not when jogging)
|
||||
- Limit switch going active while moving causes estop. #54
|
||||
- Added more links to help page.
|
||||
- Fixed axis display on LCD. #122
|
||||
- Added GCode cheat sheet.
|
||||
- Fixed LCD boot splash screen. #121
|
||||
- Implemented tool change procedures and pause message box. #81
|
||||
- Implemented program start and end procedures.
|
||||
|
||||
## v0.3.13
|
||||
- Disable spindle and loads on stop.
|
||||
- Fixed several state transition (stop, pause, estop, etc.) problems.
|
||||
|
||||
## v0.3.12
|
||||
- Updated DB25 M2 breakout diagram.
|
||||
- Enabled AVR watchdog.
|
||||
- Fixed problem with selecting newly uploaded file.
|
||||
- More thorough shutdown of stepper driver in estop.
|
||||
- Fixed spindle type specific options.
|
||||
- No more ``Unexpected AVR firmware reboot`` errors on estop clear.
|
||||
- Downgraded ``Machine alarmed - Command not processed`` errors to warnings.
|
||||
- Suppress unnecessary axis homing warnings.
|
||||
- More details for axis homing errors.
|
||||
- Support GCode messages e.g. (MSG, Hello World!)
|
||||
- Support programmed pauses. i.e. M0
|
||||
|
||||
## v0.3.11
|
||||
- Suppressed ``firmware rebooted`` warning.
|
||||
- Error on unexpected AVR reboot.
|
||||
- Fixed pin fault output.
|
||||
- No longer using interrupts for switch inputs. Debouncing on clock tick.
|
||||
|
||||
## v0.3.10
|
||||
- Fixed "Flood" display, changed to "Load 1" and "Load 2". #108
|
||||
- Highlight loads when on.
|
||||
- Fixed axis zeroing.
|
||||
- Fixed bug in home position set after successful home. #109
|
||||
- Fixed ugly Web error dumps.
|
||||
- Allow access to log file from Web.
|
||||
- Rotate log so it does not grow too big.
|
||||
- Keep same GCode file through browser reload. #20
|
||||
|
||||
## v0.3.9
|
||||
- Fixed bug in move exec that was causing bumping between moves.
|
||||
- Fixed planner bug which could create negative s-curve times.
|
||||
- Hide step and optional pause buttons until they are implemented.
|
||||
- Fixed pausing problems.
|
||||
- Limit number of console messages.
|
||||
- Scrollbar on console view.
|
||||
- Log debug messages to console in developer mode.
|
||||
- Fixed AVR log message source.
|
||||
- Fixed step correction.
|
||||
- JOGGING, HOMMING and MDI states.
|
||||
- Fixed position problem with rapid MDI entry.
|
||||
|
||||
## v0.3.8
|
||||
- Fixed pwr flags display
|
||||
- Added pwr fault flags to indicators
|
||||
|
||||
## v0.3.7
|
||||
- Allow blocking error dialog for a period of time
|
||||
- Show actual error message on planner errors
|
||||
- Reset planner on serious error
|
||||
- Fixed console clear
|
||||
- Added helpful info to Video tab
|
||||
- Changed "Console" tab to "Messages"
|
||||
- Removed spin up/down velocity options, they don't do anything
|
||||
- Allow RS485 to work when wires are swapped
|
||||
- Allow setting VFD ID
|
||||
- Only show relevant spindle config items
|
||||
- More robust video camera reset
|
||||
- Added help page
|
||||
- Allow upgrade with out Internet
|
||||
- Limit power fault reporting
|
||||
- Added load over temp, load limiting and motor overload power faults
|
||||
|
||||
## v0.3.6
|
||||
- Set max_usb_current=1 in /boot/config.txt from installer #103
|
||||
|
||||
## v0.3.5
|
||||
- Fixed dwell (G4)
|
||||
- Always show limit switch indicators regardless of motor enable
|
||||
- Fixed feed rate display
|
||||
- Added current GCode unit display
|
||||
- Fixed homed axis zeroing
|
||||
- Fixed probe pin input
|
||||
- Added reload button to video tab
|
||||
- Don't open error dialog on repeat messages
|
||||
- Handle large GCode files in browser
|
||||
- Added max lookahead limit to planner
|
||||
- Fixed GCode stopping/pausing where ramp down needs more than is in the queue
|
||||
- Added breakout box diagram to indicators
|
||||
- Initialize axes offsets to zero on startup
|
||||
- Fixed conflict between ``x`` state variable and ``x`` axis variable
|
||||
- Don't show ipv6 addresses on LCD. They don't fit.
|
||||
|
||||
## v0.3.4
|
||||
- Added alternate units for motor parameters
|
||||
- Automatic config file upgrading
|
||||
- Fixed planner/jog sync
|
||||
- Fixed planner limits config
|
||||
- Accel units mm/min² -> m/min²
|
||||
- Search and latch velocity mm/min -> m/min
|
||||
- Fixed password update (broken in last version)
|
||||
- Start Web server earlier in case of Python coding errors
|
||||
|
||||
|
||||
Changelog not maintained in previous versions. See git commit log.
|
||||
22
CODE_TAG
Normal file
22
CODE_TAG
Normal file
@@ -0,0 +1,22 @@
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
377
LICENSE
Normal file
377
LICENSE
Normal file
@@ -0,0 +1,377 @@
|
||||
The Buildbotics firmware ("the software") is free software: you can
|
||||
redistribute it and/or modify it under the terms of the GNU General
|
||||
Public License, version 2 (with out any licensing exceptions) as
|
||||
published by the Free Software Foundation. See the full license terms
|
||||
below.
|
||||
|
||||
***********************************************************************
|
||||
|
||||
Substantial effort was made to give credit to all authors of this
|
||||
software and of the works it was derived from and to adhere to the
|
||||
terms of the applicable license agreements. If you belive any
|
||||
mistakes have been made in this regard please contact Joseph Coffland
|
||||
<joseph@buildbotics.com>.
|
||||
|
||||
Portions of this software are copyrighted by the following entities:
|
||||
|
||||
Copyright (c) 2015 - 2016 Buildbotics LLC
|
||||
Copyright (c) 2014 Thomas Nixon, Jonathan Heathcote (cpp_magic.h)
|
||||
All rights reserved.
|
||||
|
||||
Each source code file lists the entities which claim copyright to
|
||||
parts of those files.
|
||||
|
||||
Much of this software was originally written by Alden S. Hart, Jr. and
|
||||
Robert Giseburt as part of the TinyG project. The TinyG project was
|
||||
in turn derived from grbl/marlin firmwares. All of the original code
|
||||
has been reformatted and cleaned up to fit our coding standards.
|
||||
Functionality in many areas has been substantially modified.
|
||||
|
||||
The original TinyG firmware is licensed under the GPL v2 and includes
|
||||
an exception which allows use of the source code by non-GPLed
|
||||
libraires and potentially executables linked to those libraries. The
|
||||
TinyG project's license did not specify that this exception must be
|
||||
offered in derived works, therefore this software's license DOES NOT
|
||||
offer any exceptions to the GPL v2 license.
|
||||
|
||||
***********************************************************************
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
12
MANIFEST.in
Normal file
12
MANIFEST.in
Normal file
@@ -0,0 +1,12 @@
|
||||
recursive-include src/py/bbctrl/http *
|
||||
include package.json README.md scripts/install.sh
|
||||
include src/avr/bbctrl-avr-firmware.hex
|
||||
include src/bbserial/bbserial.ko
|
||||
include scripts/avr109-flash.py
|
||||
include scripts/buildbotics.gc
|
||||
include scripts/xinitrc
|
||||
include scripts/rc.local
|
||||
include scripts/bbctrl.service
|
||||
include scripts/11-automount.rules
|
||||
recursive-include src/py/camotics *
|
||||
global-exclude .gitignore
|
||||
142
Makefile
Normal file
142
Makefile
Normal file
@@ -0,0 +1,142 @@
|
||||
DIR := $(shell dirname $(lastword $(MAKEFILE_LIST)))
|
||||
|
||||
NODE_MODS := $(DIR)/node_modules
|
||||
PUG := $(NODE_MODS)/.bin/pug
|
||||
STYLUS := $(NODE_MODS)/.bin/stylus
|
||||
|
||||
TARGET_DIR := build/http
|
||||
HTML := index
|
||||
HTML := $(patsubst %,$(TARGET_DIR)/%.html,$(HTML))
|
||||
RESOURCES := $(shell find src/resources -type f)
|
||||
RESOURCES := $(patsubst src/resources/%,$(TARGET_DIR)/%,$(RESOURCES))
|
||||
TEMPLS := $(wildcard src/pug/templates/*.pug)
|
||||
|
||||
AVR_FIRMWARE := src/avr/bbctrl-avr-firmware.hex
|
||||
GPLAN_MOD := rpi-share/camotics/gplan.so
|
||||
GPLAN_TARGET := src/py/camotics/gplan.so
|
||||
GPLAN_IMG := gplan-dev.img
|
||||
|
||||
RSYNC_EXCLUDE := \*.pyc __pycache__ \*.egg-info \\\#* \*~ .\\\#\*
|
||||
RSYNC_EXCLUDE := $(patsubst %,--exclude %,$(RSYNC_EXCLUDE))
|
||||
RSYNC_OPTS := $(RSYNC_EXCLUDE) -rv --no-g --delete --force
|
||||
|
||||
VERSION := $(shell sed -n 's/^.*"version": "\([^"]*\)",.*$$/\1/p' package.json)
|
||||
PKG_NAME := bbctrl-$(VERSION)
|
||||
PUB_PATH := root@buildbotics.com:/var/www/buildbotics.com/bbctrl
|
||||
BETA_VERSION := $(VERSION)-rc$(shell ./scripts/next-rc)
|
||||
BETA_PKG_NAME := bbctrl-$(BETA_VERSION)
|
||||
|
||||
SUBPROJECTS := avr boot pwr jig
|
||||
WATCH := src/pug src/pug/templates src/stylus src/js src/resources Makefile
|
||||
WATCH += src/static
|
||||
|
||||
ifndef HOST
|
||||
HOST=bbctrl.local
|
||||
endif
|
||||
|
||||
ifndef PASSWORD
|
||||
PASSWORD=buildbotics
|
||||
endif
|
||||
|
||||
|
||||
all: $(HTML) $(RESOURCES)
|
||||
@for SUB in $(SUBPROJECTS); do $(MAKE) -C src/$$SUB; done
|
||||
|
||||
pkg: all $(AVR_FIRMWARE) bbserial
|
||||
./setup.py sdist
|
||||
|
||||
beta-pkg: pkg
|
||||
cp dist/$(PKG_NAME).tar.bz2 dist/$(BETA_PKG_NAME).tar.bz2
|
||||
|
||||
bbserial:
|
||||
$(MAKE) -C src/bbserial
|
||||
|
||||
gplan: $(GPLAN_TARGET)
|
||||
|
||||
$(GPLAN_TARGET): $(GPLAN_MOD)
|
||||
cp $< $@
|
||||
|
||||
$(GPLAN_MOD): $(GPLAN_IMG)
|
||||
./scripts/gplan-init-build.sh
|
||||
git -C rpi-share/cbang fetch
|
||||
git -C rpi-share/cbang reset --hard FETCH_HEAD
|
||||
git -C rpi-share/camotics fetch
|
||||
git -C rpi-share/camotics reset --hard FETCH_HEAD
|
||||
cp ./scripts/gplan-build.sh rpi-share/
|
||||
sudo ./scripts/rpi-chroot.sh $(GPLAN_IMG) /mnt/host/gplan-build.sh
|
||||
|
||||
$(GPLAN_IMG):
|
||||
./scripts/gplan-init-build.sh
|
||||
|
||||
.PHONY: $(AVR_FIRMWARE)
|
||||
$(AVR_FIRMWARE):
|
||||
$(MAKE) -C src/avr
|
||||
|
||||
publish: pkg
|
||||
echo -n $(VERSION) > dist/latest.txt
|
||||
rsync $(RSYNC_OPTS) dist/$(PKG_NAME).tar.bz2 dist/latest.txt $(PUB_PATH)/
|
||||
|
||||
publish-beta: beta-pkg
|
||||
echo -n $(BETA_VERSION) > dist/latest-beta.txt
|
||||
rsync $(RSYNC_OPTS) dist/$(BETA_PKG_NAME).tar.bz2 dist/latest-beta.txt \
|
||||
$(PUB_PATH)/
|
||||
|
||||
update: pkg
|
||||
http_proxy= curl -i -X PUT -H "Content-Type: multipart/form-data" \
|
||||
-F "firmware=@dist/$(PKG_NAME).tar.bz2" -F "password=$(PASSWORD)" \
|
||||
http://$(HOST)/api/firmware/update
|
||||
@-tput sgr0 && echo # Fix terminal output
|
||||
|
||||
build/templates.pug: $(TEMPLS)
|
||||
mkdir -p build
|
||||
cat $(TEMPLS) >$@
|
||||
|
||||
node_modules: package.json
|
||||
npm install && touch node_modules
|
||||
|
||||
$(TARGET_DIR)/%: src/resources/%
|
||||
install -D $< $@
|
||||
|
||||
$(TARGET_DIR)/index.html: build/templates.pug
|
||||
$(TARGET_DIR)/index.html: $(wildcard src/static/js/*)
|
||||
$(TARGET_DIR)/index.html: $(wildcard src/static/css/*)
|
||||
$(TARGET_DIR)/index.html: $(wildcard src/pug/templates/*)
|
||||
$(TARGET_DIR)/index.html: $(wildcard src/js/*)
|
||||
$(TARGET_DIR)/index.html: $(wildcard src/stylus/*)
|
||||
$(TARGET_DIR)/index.html: src/resources/config-template.json
|
||||
|
||||
$(TARGET_DIR)/%.html: src/pug/%.pug node_modules
|
||||
@mkdir -p $(shell dirname $@)
|
||||
$(PUG) -O pug-opts.js -P $< -o $(TARGET_DIR) || (rm -f $@; exit 1)
|
||||
|
||||
pylint:
|
||||
pylint3 -E $(shell find src/py -name \*.py | grep -v flycheck_)
|
||||
|
||||
jshint:
|
||||
./node_modules/jshint/bin/jshint --config jshint.json src/js/*.js
|
||||
|
||||
lint: pylint jshint
|
||||
|
||||
watch:
|
||||
@clear
|
||||
$(MAKE)
|
||||
@while sleep 1; do \
|
||||
inotifywait -qr -e modify -e create -e delete \
|
||||
--exclude .*~ --exclude \#.* $(WATCH); \
|
||||
clear; \
|
||||
$(MAKE); \
|
||||
done
|
||||
|
||||
tidy:
|
||||
rm -f $(shell find "$(DIR)" -name \*~)
|
||||
|
||||
clean: tidy
|
||||
rm -rf build html dist
|
||||
@for SUB in $(SUBPROJECTS); do \
|
||||
$(MAKE) -C src/$$SUB clean; \
|
||||
done
|
||||
|
||||
dist-clean: clean
|
||||
rm -rf node_modules
|
||||
|
||||
.PHONY: all install clean tidy pkg gplan lint pylint jshint bbserial
|
||||
62
README_buildbotics.md
Normal file
62
README_buildbotics.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Buildbotics CNC Controller Firmware
|
||||
This repository contains the source code for the Buildbotics CNC Controller.
|
||||
See [buildbotics.com](https://buildbotics.com/) for more information.
|
||||
|
||||

|
||||
|
||||
## Overview
|
||||

|
||||
|
||||
The main parts of the Buildbotics CNC Controller software and the technologies
|
||||
they are built with are as follows:
|
||||
|
||||
* Web App - Frontend user interface
|
||||
* [Javascript](https://www.w3schools.com/js/)
|
||||
* [HTML5](https://www.w3schools.com/html/)
|
||||
* [Stylus](http://stylus-lang.com/)
|
||||
* [Pug.js](https://pugjs.org/)
|
||||
* [Vue.js](https://vuejs.org/)
|
||||
|
||||
* Controller OS - RaspberryPi Operating System
|
||||
* [Raspbian](https://www.raspbian.org/)
|
||||
|
||||
* BBCtrl - Python App
|
||||
* [Python 3](https://www.python.org/)
|
||||
* [Tornado Web](https://www.tornadoweb.org/)
|
||||
|
||||
* GPlan - Path Planner Python Module
|
||||
* [C++](http://www.cplusplus.com/)
|
||||
* [CAMotics](https://camotics.org/)
|
||||
|
||||
* Main AVR Firmware + Bootloader - Real-time step generation, etc.
|
||||
* [ATxmega192a3u](https://www.microchip.com/wwwproducts/ATxmega192A3U)
|
||||
* [C](https://en.wikipedia.org/wiki/C_(programming_language))
|
||||
|
||||
* Pwr AVR Firmware - Power safety
|
||||
* [ATtiny1634](https://www.microchip.com/wwwproducts/ATtiny1634)
|
||||
* [C](https://en.wikipedia.org/wiki/C_(programming_language))
|
||||
|
||||
## Quickstart Guide
|
||||
|
||||
Be sure to read the [development guide](docs/development.md) for more detailed
|
||||
instructions.
|
||||
|
||||
On a Debian Linux (9.6.0 stable) system:
|
||||
|
||||
# Install the required packages
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential git wget binfmt-support qemu \
|
||||
parted gcc-avr avr-libc avrdude pylint3 python3 python3-tornado curl \
|
||||
unzip python3-setuptools
|
||||
curl -sL https://deb.nodesource.com/setup_11.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
# Get the source
|
||||
git clone https://github.com/buildbotics/bbctrl-firmware
|
||||
|
||||
# Build the Firmware
|
||||
cd bbctrl-firmware
|
||||
make pkg
|
||||
|
||||
The resulting package will be a ``.tar.bz2`` file in ``dist``. See the
|
||||
[development guide](docs/development.md) for more information.
|
||||
41
docs/bbdev-chroot.md
Normal file
41
docs/bbdev-chroot.md
Normal file
@@ -0,0 +1,41 @@
|
||||
This document describes how to setup a Buildbotics development environment
|
||||
on a Debian based system inside a chroot. Building in the chroot ensures that
|
||||
you have a clean and consistent build environment unaltered by other packages
|
||||
or manual changes.
|
||||
|
||||
# Install packages required to create chroot
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install binutils debootstrap
|
||||
|
||||
# Create chroot environment
|
||||
|
||||
mkdir bbdev
|
||||
sudo debootstrap --arch amd64 stable bbdev http://deb.debian.org/debian
|
||||
|
||||
# Copy downloaded files (optional)
|
||||
To speed things up you can copy to large downloads, if you already have them,
|
||||
into the chroot.
|
||||
|
||||
sudo mkdir -p bbdev/opt/bbctrl-firmware/src/bbserial/
|
||||
sudo cp 2017-11-29-raspbian-stretch-lite.zip bbdev/opt/bbctrl-firmware/
|
||||
sudo cp raspberrypi-kernel_1.20171029-1.tar.gz bbdev/opt/bbctrl-firmware/src/bbserial/
|
||||
|
||||
# Enter the chroot
|
||||
|
||||
sudo mount --bind /proc bbdev/proc
|
||||
sudo mount --rbind /sys bbdev/sys
|
||||
sudo mount --rbind /dev bbdev/dev
|
||||
sudo chroot bbdev
|
||||
cd /opt
|
||||
|
||||
Now, follow the instructions in [development.md](development.md) from with in
|
||||
the chroot.
|
||||
|
||||
# Exit the chroot
|
||||
To exit the chroot:
|
||||
|
||||
exit
|
||||
sudo umount bbdev/dev
|
||||
sudo umount bbdev/sys
|
||||
sudo umount bbdev/proc
|
||||
BIN
docs/buildbotics_architecture_overview.png
Normal file
BIN
docs/buildbotics_architecture_overview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 333 KiB |
BIN
docs/buildbotics_controller.png
Normal file
BIN
docs/buildbotics_controller.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 203 KiB |
68
docs/cross_compile_rpi_kernel_module.md
Normal file
68
docs/cross_compile_rpi_kernel_module.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Install the cross compiler
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-arm-linux-gnueabihf
|
||||
|
||||
# Determine the correct kernel version on the target pi
|
||||
|
||||
dpkg-query -l raspberrypi-kernel
|
||||
|
||||
# Get the kernel source for the correct kernel version
|
||||
|
||||
wget https://github.com/raspberrypi/linux/archive/raspberrypi-kernel_1.20171029-1.tar.gz
|
||||
tar xf raspberrypi-kernel_1.20171029-1.tar.gz
|
||||
cd linux-raspberrypi-kernel_1.20171029-1
|
||||
|
||||
# Prep the kernel source
|
||||
|
||||
KERNEL=kernel7
|
||||
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
|
||||
make -j 8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules_prepare
|
||||
|
||||
# Create hello.c module
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int hello_init(void) {
|
||||
printk(KERN_ALERT "Hello world!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hello_exit(void) {
|
||||
printk(KERN_ALERT "Goodbye cruel world!\n");
|
||||
}
|
||||
|
||||
module_init(hello_init);
|
||||
module_exit(hello_exit);
|
||||
|
||||
# Create a Makefile
|
||||
|
||||
CROSS := arm-linux-gnueabihf-
|
||||
DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
obj-m := hello.o
|
||||
|
||||
all:
|
||||
$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS) -C kernel M=$(DIR) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) ARCH=arm CROSS_COMPILE=$(CROSS) -C kernel M=$(DIR) clean
|
||||
|
||||
# Compile the module
|
||||
|
||||
ln -sf path/to/rpi-kernel kernel
|
||||
make
|
||||
|
||||
# Copy module to rpi
|
||||
|
||||
scp hello.ko pi.local:
|
||||
|
||||
# Load it on the pi
|
||||
|
||||
sudo insmod hello.ko
|
||||
|
||||
# Look for message in syslog
|
||||
|
||||
tail /var/log/syslog
|
||||
106
docs/development.md
Normal file
106
docs/development.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Buildbotics CNC Controller Development Guide
|
||||
|
||||
This document describes how to setup your environment for Buildbotics CNC
|
||||
controller development on Debian Linux. Development on systems other than
|
||||
Debian Linux are not supported.
|
||||
|
||||
## Installing the Development Prerequisites
|
||||
|
||||
On a Debian Linux (9.6.0 stable) system install the required packages:
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential git wget binfmt-support qemu \
|
||||
parted gcc-avr avr-libc avrdude pylint3 python3 python3-tornado curl \
|
||||
unzip python3-setuptools gcc-arm-linux-gnueabihf bc sudo
|
||||
curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
## Getting the Source Code
|
||||
|
||||
git clone https://github.com/buildbotics/bbctrl-firmware
|
||||
|
||||
## Build the Firmware
|
||||
|
||||
cd bbctrl-firmware
|
||||
make
|
||||
|
||||
## Build GPlan Module
|
||||
|
||||
GPlan is a Python module written in C++. It must be compiled for ARM so that
|
||||
it can be used on the Raspberry Pi. This is accomplished using a chroot, qemu
|
||||
and binfmt to create an emulated ARM build environment. This is faster and
|
||||
more convenient than building on the RPi itself. All of this is automated.
|
||||
|
||||
make gplan
|
||||
|
||||
The first time this is run it will take quite awhile as it setups up the build
|
||||
environment. You can run the above command again later to build the latest
|
||||
version.
|
||||
|
||||
## Build the Firmware Package
|
||||
|
||||
make pkg
|
||||
|
||||
The resulting package will be a ``.tar.bz2`` file in ``dist``.
|
||||
|
||||
## Upload the Firmware Package to a Buildbotics CNC Controller
|
||||
If you have a Buildbotics CNC controller at ``bbctrl.local``, the default
|
||||
address, you can upgrade it with the new package like this:
|
||||
|
||||
make update HOST=bbctrl.local PASSWORD=<pass>
|
||||
|
||||
Where ``<pass>`` is the controller's admin password.
|
||||
|
||||
## Updating the Pwr Firmware
|
||||
|
||||
The Pwr firmware must be uploaded manually using an ISP programmer. With the
|
||||
programmer attached to the pwr chip ISP port on the Builbotics controller's
|
||||
main board run the following:
|
||||
|
||||
make -C src/pwr program
|
||||
|
||||
## Initializing the main AVR firmware
|
||||
|
||||
The main AVR must also be programmed manually the first time. Later it will be
|
||||
automatically programmed by the RPi as part of the firmware install. To perform
|
||||
the initial AVR programming connec the ISP programmer to the main AVR's ISP port
|
||||
on the Buildbotics controller's main board and run the following:
|
||||
|
||||
make -C src/avr init
|
||||
|
||||
This will set the fuses, install the bootloader and program the firmware.
|
||||
|
||||
## Installing the RaspberryPi base system
|
||||
|
||||
Download the latest Buildbotics CNC controller base image and decompress it:
|
||||
|
||||
wget \
|
||||
https://buildbotics.com/upload/2018-05-15-raspbian-stretch-bbctrl.img.xz
|
||||
xz -d 2018-05-15-raspbian-stretch-bbctrl.img.xz
|
||||
|
||||
Now copy the base system to an SD card. You need a card with at least 8GiB.
|
||||
After installing the RPi system all data on the SD card will be lost. So make
|
||||
sure you back up the SD card if there's anything important on it.
|
||||
|
||||
In the command below, make sure you have the correct device or you can
|
||||
**destroy your Linux system** by overwriting the disk. One way to do this is
|
||||
to run ``sudo tail -f /var/log/syslog`` before inserting the SD card. After
|
||||
inserting the card look for log messages containing ``/dev/sdx`` where ``x`` is
|
||||
a letter. This should be the device name of the SD card. Hit ``CTRL-C`` to
|
||||
stop following the system log.
|
||||
|
||||
sudo dd bs=4M if=2015-05-05-raspbian-wheezy.img of=/dev/sde
|
||||
sudo sync
|
||||
|
||||
The first command takes awhile and does not produce any output until it's done.
|
||||
|
||||
Insert the SD card into your RPi and power it on. Plug in the network
|
||||
connection, wired or wireless.
|
||||
|
||||
## Logging into the Buildbotics Controller
|
||||
|
||||
You can ssh in to the Buildbotics Controller like so:
|
||||
|
||||
ssh bbmc@bbctrl.local
|
||||
|
||||
The default password is ``buildbotics``. It's best if you change this.
|
||||
45
docs/emu_chroot.md
Normal file
45
docs/emu_chroot.md
Normal file
@@ -0,0 +1,45 @@
|
||||
This document describes how to setup the Buildbotics firmware in a chroot
|
||||
environment for the purposes of demonstrating the user interface.
|
||||
|
||||
On a Debian system install:
|
||||
|
||||
ROOT=/opt/demo
|
||||
sudo apt-get install -y binutils debootstrap
|
||||
sudo mkdir $ROOT
|
||||
sudo debootstrap --arch amd64 stable $ROOT/ http://deb.debian.org/debian
|
||||
|
||||
Then chroot:
|
||||
|
||||
sudo mount --bind /dev $ROOT/dev/
|
||||
sudo mount --bind /sys $ROOT/sys/
|
||||
sudo mount --bind /proc $ROOT/proc/
|
||||
sudo mount --bind /dev/pts $ROOT/dev/pts
|
||||
sudo chroot $ROOT
|
||||
|
||||
Setup the demo system:
|
||||
|
||||
export LC_ALL=C
|
||||
apt-get update
|
||||
apt-get install -y wget git python3-tornado python3-sockjs-tornado \
|
||||
python3-setuptools python-six build-essential scons libv8-dev
|
||||
libpython3-dev
|
||||
|
||||
cd /opt
|
||||
BASE=https://buildbotics.com/bbctrl
|
||||
LATEST=$(wget $BASE/latest.txt -O- -q)
|
||||
wget $BASE/bbctrl-$LATEST.tar.bz2
|
||||
tar xf bbctrl-$LATEST.tar.bz2
|
||||
ln -sf bbctrl-$LATEST bbctrl
|
||||
|
||||
git clone --depth=1 https://github.com/CauldronDevelopmentLLC/cbang
|
||||
git clone --depth=1 https://github.com/CauldronDevelopmentLLC/camotics
|
||||
export CBANG_HOME=/opt/cbang
|
||||
scons -C cbang -j8 disable_local="re2 libevent"
|
||||
scons -C camotics -j8 gplan.so with_gui=False
|
||||
|
||||
cd bbctrl
|
||||
python3 setup.py install
|
||||
cp /opt/camotics/gplan.so /usr/local/lib/python*/dist-packages/bbctrl-$VERSION-py*.egg/camotics/gplan.so
|
||||
|
||||
mkdir -p /var/lib/bbctrl/upload
|
||||
useradd -u 1001 bbmc
|
||||
15
jshint.json
Normal file
15
jshint.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"asi": true,
|
||||
"browser": true,
|
||||
"devel": true,
|
||||
"strict": "global",
|
||||
"globals": {
|
||||
"$": false,
|
||||
"require": false,
|
||||
"module": false,
|
||||
"Vue": false,
|
||||
"SockJS": false,
|
||||
"Gauge": false,
|
||||
"Clusterize": false
|
||||
}
|
||||
}
|
||||
14
package.json
Normal file
14
package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "bbctrl",
|
||||
"version": "1.0.3",
|
||||
"homepage": "https://onefinitycnc.com/",
|
||||
"repository": "https://github.com/OneFinityCNC/onefinity",
|
||||
"license": "GPL-3.0+",
|
||||
"dependencies": {
|
||||
"jshint": "",
|
||||
"browserify": "",
|
||||
"jstransformer-stylus": "",
|
||||
"jstransformer-escape-html": "",
|
||||
"pug-cli": ""
|
||||
}
|
||||
}
|
||||
11
pug-opts.js
Normal file
11
pug-opts.js
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
pretty: true,
|
||||
filters: {
|
||||
browserify: function (text, options) {
|
||||
return require('child_process').execSync(
|
||||
`./node_modules/.bin/browserify - --basedir src/js`,
|
||||
{input: text}
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
10
scripts/11-automount.rules
Normal file
10
scripts/11-automount.rules
Normal file
@@ -0,0 +1,10 @@
|
||||
KERNEL!="sd[a-z]*", GOTO="automount_end"
|
||||
IMPORT{program}="/sbin/blkid -o udev -p %N"
|
||||
ENV{ID_FS_TYPE}=="", GOTO="automount_end"
|
||||
ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"
|
||||
ENV{ID_FS_LABEL}=="", ENV{dir_name}="usb-%k"
|
||||
ACTION=="add", ENV{mount_options}="relatime"
|
||||
ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},utf8,gid=100,umask=002,sync"
|
||||
ACTION=="add", RUN+="/bin/mkdir -p /media/%E{dir_name}", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/%E{dir_name}"
|
||||
ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l /media/%E{dir_name}", RUN+="/bin/rmdir /media/%E{dir_name}"
|
||||
LABEL="automount_end"
|
||||
206
scripts/avr109-flash.py
Normal file
206
scripts/avr109-flash.py
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import time
|
||||
import serial
|
||||
import binascii
|
||||
|
||||
|
||||
dev = '/dev/ttyAMA0'
|
||||
baud = 921600
|
||||
boot_id = 'bbctrl '
|
||||
verbose = False
|
||||
|
||||
|
||||
def crc16(data):
|
||||
crc = 0xffff
|
||||
|
||||
for x in data:
|
||||
crc = crc ^ int(x)
|
||||
for bit in range(8):
|
||||
if crc & 1: crc = (crc >> 1) ^ 0xa001
|
||||
else: crc = crc >> 1
|
||||
|
||||
return crc
|
||||
|
||||
|
||||
def avr_crc32(data, length):
|
||||
mem = [0xff] * length
|
||||
|
||||
for addr, chunk in data:
|
||||
for x in chunk:
|
||||
mem[addr] = x
|
||||
addr += 1
|
||||
|
||||
return binascii.crc32(bytes(mem))
|
||||
|
||||
|
||||
def read_intel_hex(f):
|
||||
base = 0
|
||||
pos = 0
|
||||
start = 0
|
||||
chunk = None
|
||||
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line[0] != ':': continue
|
||||
|
||||
count = int(line[1:3], 16)
|
||||
addr = int(line[3:7], 16)
|
||||
type = int(line[7:9], 16)
|
||||
data = line[9:-2]
|
||||
checksum = int(line[-2:], 16)
|
||||
|
||||
if type == 0:
|
||||
addr += base
|
||||
data = binascii.unhexlify(bytes(data, 'utf8'))
|
||||
|
||||
if chunk is None or pos != addr:
|
||||
if chunk is not None: yield (start, chunk)
|
||||
start = addr
|
||||
chunk = data
|
||||
|
||||
else: chunk += data
|
||||
|
||||
pos = addr + len(data)
|
||||
|
||||
if type == 2: base = int(data, 16) * 16
|
||||
|
||||
if chunk is not None: yield (start, chunk)
|
||||
|
||||
|
||||
def send(data):
|
||||
if verbose: print('Sending:', data)
|
||||
sp.write(bytes(data, 'utf8'))
|
||||
|
||||
|
||||
def send_int(x, size):
|
||||
if verbose: print('Sending: %d', x)
|
||||
sp.write((x).to_bytes(size, byteorder = 'big'))
|
||||
|
||||
|
||||
def recv(count):
|
||||
data = sp.read(count).decode('utf8')
|
||||
if count and verbose: print('Received:', data)
|
||||
return data
|
||||
|
||||
|
||||
def recv_int(size):
|
||||
x = int.from_bytes(sp.read(size), byteorder = 'big')
|
||||
if verbose: print('Received:', x)
|
||||
return x
|
||||
|
||||
|
||||
# Read firmware hex file
|
||||
data = list(read_intel_hex(open(sys.argv[1], 'r')))
|
||||
|
||||
# Open serial port
|
||||
sp = serial.Serial(dev, baud, timeout = 10)
|
||||
|
||||
# Reset AVR
|
||||
import RPi.GPIO as gpio
|
||||
gpio.setwarnings(False)
|
||||
gpio.setmode(gpio.BCM)
|
||||
gpio.setup(27, gpio.OUT)
|
||||
gpio.output(27, 0)
|
||||
gpio.output(27, 1)
|
||||
gpio.setup(27, gpio.IN, pull_up_down = gpio.PUD_UP)
|
||||
time.sleep(0.1)
|
||||
|
||||
# Sync
|
||||
for i in range(10): send('\x1b')
|
||||
|
||||
# Flush serial
|
||||
try:
|
||||
recv(sp.in_waiting)
|
||||
except: pass
|
||||
|
||||
# Get bootloader ID
|
||||
send('S')
|
||||
if boot_id != recv(len(boot_id)):
|
||||
raise Exception('Failed to communicate with bootloader')
|
||||
|
||||
# Get version
|
||||
send('V')
|
||||
major = int(recv(1))
|
||||
minor = int(recv(1))
|
||||
print('Bootloader version: %d.%d' % (major, minor))
|
||||
|
||||
# If bootloader is new enough compare checksums
|
||||
if 0 < major or 1 < minor:
|
||||
# Get flash length
|
||||
send('n')
|
||||
flash_len = recv_int(3)
|
||||
|
||||
# Get current flash CRC
|
||||
send('X')
|
||||
new_crc = avr_crc32(data, flash_len)
|
||||
old_crc = recv_int(4)
|
||||
if old_crc == new_crc:
|
||||
print('Flash already up to date')
|
||||
sys.exit(0)
|
||||
|
||||
print('CRC: old=0x%08x new=0x%08x' % (old_crc, new_crc))
|
||||
|
||||
# Erase
|
||||
send('e')
|
||||
if recv(1) != '\r': raise Exception('Flash erase failed')
|
||||
|
||||
# Get page size
|
||||
send('b')
|
||||
if recv(1) != 'Y': raise Exception('Cannot get page size')
|
||||
page_size = recv_int(2)
|
||||
print('Page size:', page_size)
|
||||
|
||||
|
||||
# Program
|
||||
print('Programming', end = '')
|
||||
count = 0
|
||||
retry = 0
|
||||
for addr, chunk in data:
|
||||
# Set address
|
||||
send('H')
|
||||
send_int(addr, 3)
|
||||
if recv(1) != '\r': raise Exception('Failed to set address')
|
||||
|
||||
while len(chunk):
|
||||
sys.stdout.flush()
|
||||
page = chunk[0:512]
|
||||
|
||||
# Block command
|
||||
send('B')
|
||||
|
||||
# Send block size
|
||||
send_int(len(page), 2)
|
||||
|
||||
# Send memory type
|
||||
send('F')
|
||||
|
||||
# Send block
|
||||
sp.write(page)
|
||||
|
||||
if recv(1) != '\r': raise Exception('Failed to write block')
|
||||
|
||||
# Get and check block CRC
|
||||
send('i')
|
||||
crc = recv_int(2)
|
||||
expect = crc16(page)
|
||||
if crc != expect:
|
||||
retry += 1
|
||||
if retry == 5:
|
||||
raise Exception('CRC mismatch %d != %d' % (crc, expect))
|
||||
|
||||
print('x', end = '')
|
||||
continue
|
||||
|
||||
count += len(page)
|
||||
chunk = chunk[512:]
|
||||
retry = 0
|
||||
print('.', end = '')
|
||||
|
||||
|
||||
print('done')
|
||||
print('Wrote %d bytes' % count)
|
||||
|
||||
# Exit bootloader
|
||||
send('E')
|
||||
15
scripts/bbctrl.service
Normal file
15
scripts/bbctrl.service
Normal file
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=Buildbotics Controller
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
ExecStart=/usr/local/bin/bbctrl -l /var/log/bbctrl.log
|
||||
WorkingDirectory=/var/lib/bbctrl
|
||||
Restart=always
|
||||
StandardOutput=null
|
||||
Nice=-10
|
||||
KillMode=process
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
15
scripts/browser
Normal file
15
scripts/browser
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
|
||||
def enter_cgroup():
|
||||
with open('/sys/fs/cgroup/memory/chrome/tasks', 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
|
||||
|
||||
# Start browser
|
||||
args = ['/usr/lib/chromium-browser/chromium-browser'] + sys.argv[1:]
|
||||
subprocess.Popen(args, preexec_fn = enter_cgroup).wait()
|
||||
37
scripts/check-config-vars.py
Normal file
37
scripts/check-config-vars.py
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
'''Check that the configuration variable template used on the RPi matches the
|
||||
variables used in the AVR'''
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
templ = json.load(open('src/resources/config-template.json', 'r'))
|
||||
vars = json.load(open('avr/build/vars.json', 'r'))
|
||||
|
||||
|
||||
def check(section):
|
||||
errors = 0
|
||||
|
||||
for name, entry in section.items():
|
||||
if 'type' in entry:
|
||||
ok = False
|
||||
|
||||
# TODO check that defaults are valid
|
||||
# TODO check that types match
|
||||
|
||||
if 'code' in entry and not entry['code'] in vars:
|
||||
print('"%s" with code "%s" not found' % (name, entry['code']))
|
||||
|
||||
else: ok = True
|
||||
|
||||
if not ok: errors += 1
|
||||
|
||||
else: errors += check(entry)
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
errors = check(templ)
|
||||
print('\n%d errors' % errors)
|
||||
sys.exit(errors != 0)
|
||||
32
scripts/config-screen
Normal file
32
scripts/config-screen
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# != 3 ]; then
|
||||
echo "Usage: $0 <width> <height> <rotation>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
WIDTH="$1"
|
||||
HEIGHT="$2"
|
||||
ROTATION="$3"
|
||||
|
||||
if [[ ! "$WIDTH" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid width '$WIDTH'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$HEIGHT" =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid height '$HEIGHT'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$ROTATION" =~ ^[0-3]$ ]]; then
|
||||
echo "Invalid rotation '$ROTATION'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
OPTIONS="framebuffer_width=$WIDTH "
|
||||
OPTIONS+="framebuffer_height=$HEIGHT "
|
||||
OPTIONS+="display_rotate=$ROTATION"
|
||||
|
||||
edit-boot-config $OPTIONS
|
||||
259
scripts/config-wifi
Normal file
259
scripts/config-wifi
Normal file
@@ -0,0 +1,259 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
AP=false
|
||||
DISABLE=false
|
||||
SSID=
|
||||
PASS=
|
||||
CHANNEL=7
|
||||
REBOOT=false
|
||||
|
||||
WLAN0_CFG=/etc/network/interfaces.d/wlan0
|
||||
HOSTAPD_CFG=/etc/hostapd/hostapd.conf
|
||||
DNSMASQ_CFG=/etc/dnsmasq.conf
|
||||
DHCPCD_CFG=/etc/dhcpcd.conf
|
||||
WPA_CFG=/etc/wpa_supplicant/wpa_supplicant.conf
|
||||
|
||||
|
||||
function query_config() {
|
||||
if [ -e $WLAN0_CFG ]; then
|
||||
SSID=$(grep wpa-ssid $WLAN0_CFG |
|
||||
sed 's/^[[:space:]]*wpa-ssid "\([^"]*\)"/\1/')
|
||||
echo "{\"ssid\": \"$SSID\", \"mode\": \"client\"}"
|
||||
|
||||
else
|
||||
if [ -e $HOSTAPD_CFG -a -e /etc/default/hostapd ]; then
|
||||
SSID=$(grep ^ssid= $HOSTAPD_CFG | sed 's/^ssid=\(.*\)$/\1/')
|
||||
CHANNEL=$(grep ^channel= $HOSTAPD_CFG |
|
||||
sed 's/^channel=\(.*\)$/\1/')
|
||||
|
||||
echo -n "{\"ssid\": \"$SSID\", "
|
||||
echo "\"channel\": $CHANNEL, \"mode\": \"ap\"}"
|
||||
|
||||
else
|
||||
echo "{\"mode\": \"disabled\"}"
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
|
||||
function disable_wifi() {
|
||||
rm -f $WLAN0_CFG $HOSTAPD_CFG /etc/default/hostapd
|
||||
}
|
||||
|
||||
|
||||
function configure_wlan0() {
|
||||
echo "auto wlan0"
|
||||
echo "allow-hotplug wlan0"
|
||||
echo "iface wlan0 inet dhcp"
|
||||
echo " wpa-scan-ssid 1"
|
||||
echo " wpa-ap-scan 1"
|
||||
echo " wpa-key-mgmt WPA-PSK"
|
||||
echo " wpa-proto RSN WPA"
|
||||
echo " wpa-pairwise CCMP TKIP"
|
||||
echo " wpa-group CCMP TKIP"
|
||||
echo " wpa-ssid \"$SSID\""
|
||||
|
||||
if [ ${#PASS} -ne 0 ]; then
|
||||
echo " wpa-psk \"$PASS\""
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function configure_wpa() {
|
||||
echo "country=US"
|
||||
echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev"
|
||||
echo "update_config=1"
|
||||
|
||||
if [ ${#PASS} -eq 0 ]; then
|
||||
echo "network={"
|
||||
echo " ssid=\"$SSID\""
|
||||
echo " key_mgmt=NONE"
|
||||
echo "}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function configure_dhcpcd() {
|
||||
echo "hostname"
|
||||
echo "clientid"
|
||||
echo "persistent"
|
||||
echo "option rapid_commit"
|
||||
echo "option domain_name_servers, domain_name, domain_search, host_name"
|
||||
echo "option classless_static_routes"
|
||||
echo "option ntp_servers"
|
||||
echo "option interface_mtu"
|
||||
echo "require dhcp_server_identifier"
|
||||
echo "slaac private"
|
||||
|
||||
if $AP; then
|
||||
echo
|
||||
echo "interface wlan0"
|
||||
echo " static ip_address=192.168.43.1/24"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function configure_wifi() {
|
||||
disable_wifi
|
||||
echo "source-directory /etc/network/interfaces.d" > /etc/network/interfaces
|
||||
configure_wlan0 > $WLAN0_CFG
|
||||
configure_wpa > $WPA_CFG
|
||||
configure_dhcpcd > $DHCPCD_CFG
|
||||
}
|
||||
|
||||
|
||||
function configure_dnsmasq() {
|
||||
echo "interface=wlan0"
|
||||
echo "domain-needed"
|
||||
echo "bogus-priv"
|
||||
echo "dhcp-range=192.168.43.2,192.168.43.20,255.255.255.0,12h"
|
||||
}
|
||||
|
||||
|
||||
function configure_hostapd() {
|
||||
echo "interface=wlan0"
|
||||
echo "driver=nl80211"
|
||||
echo "ssid=$SSID"
|
||||
echo "hw_mode=g"
|
||||
echo "channel=$CHANNEL"
|
||||
echo "wmm_enabled=0"
|
||||
echo "macaddr_acl=0"
|
||||
echo "auth_algs=1"
|
||||
echo "ignore_broadcast_ssid=0"
|
||||
echo "wpa=2"
|
||||
echo "wpa_passphrase=$PASS"
|
||||
echo "wpa_key_mgmt=WPA-PSK"
|
||||
echo "wpa_pairwise=TKIP"
|
||||
echo "rsn_pairwise=CCMP"
|
||||
}
|
||||
|
||||
|
||||
function is_installed() {
|
||||
dpkg-query -W --showformat='${Status}' $1 |
|
||||
grep "install ok installed" >/dev/null
|
||||
if [ $? -eq 0 ]; then echo true; else echo false; fi
|
||||
}
|
||||
|
||||
|
||||
function configure_ap() {
|
||||
disable_wifi
|
||||
|
||||
# Install packages
|
||||
(
|
||||
$(is_installed dnsmasq) &&
|
||||
$(is_installed hostapd) &&
|
||||
$(is_installed iptables-persistent)
|
||||
|
||||
) || (
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -yq dnsmasq hostapd iptables-persistent
|
||||
)
|
||||
|
||||
configure_dhcpcd > $DHCPCD_CFG
|
||||
configure_dnsmasq > $DNSMASQ_CFG
|
||||
configure_hostapd > $HOSTAPD_CFG
|
||||
|
||||
echo "DAEMON_CONF=\"/etc/hostapd/hostapd.conf\"" > /etc/default/hostapd
|
||||
|
||||
# Enable IP forwarding
|
||||
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
# Enable IP masquerading
|
||||
iptables -t nat -F
|
||||
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
}
|
||||
|
||||
|
||||
function usage() {
|
||||
echo "Usage: config-wifi [OPTIONS]"
|
||||
echo
|
||||
echo "Configure wifi as either a client or access point."
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo
|
||||
echo " -a Configure access point."
|
||||
echo " -d Disable wifi."
|
||||
echo " -r Reboot when done."
|
||||
echo " -s <SSID> Set SSID."
|
||||
echo " -p <PASS> Set password."
|
||||
echo " -c <CHANNEL> Set wifi channel."
|
||||
echo " -j Report wifi config as JSON data."
|
||||
echo
|
||||
}
|
||||
|
||||
|
||||
# Parse args
|
||||
while [ $# -ne 0 ]; do
|
||||
case "$1" in
|
||||
-a) AP=true ;;
|
||||
-d) DISABLE=true ;;
|
||||
-r) REBOOT=true; ;;
|
||||
-s) SSID="$2"; shift ;;
|
||||
-p) PASS="$2"; shift ;;
|
||||
-c) CHANNEL="$2"; shift ;;
|
||||
-j) query_config; exit 0 ;;
|
||||
|
||||
-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
|
||||
*)
|
||||
usage
|
||||
echo "Unknown argument '$1'"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
|
||||
if $DISABLE; then
|
||||
disable_wifi
|
||||
|
||||
else
|
||||
# Check args
|
||||
function clean_str() {
|
||||
echo "$1" | tr -d '\n\r"'
|
||||
}
|
||||
|
||||
SSID=$(clean_str "$SSID")
|
||||
PASS=$(clean_str "$PASS")
|
||||
|
||||
LANG=C LC_ALL=C # For correct string byte length
|
||||
|
||||
if [ ${#SSID} -eq 0 -o 32 -lt ${#SSID} ]; then
|
||||
echo "Invalid or missing SSID '$SSID'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#PASS} -ne 0 ]; then
|
||||
if [ ${#PASS} -lt 8 -o 128 -lt ${#PASS} ]; then
|
||||
echo "Invalid passsword"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$CHANNEL" | grep '^[0-9]\{1,2\}' > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Invalid channel '$CHANNEL'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute
|
||||
if $AP; then
|
||||
echo "Configuring Wifi access point"
|
||||
configure_ap
|
||||
|
||||
else
|
||||
echo "Configuring Wifi"
|
||||
configure_wifi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if $REBOOT; then nohup reboot & fi
|
||||
17
scripts/demo-chroot
Normal file
17
scripts/demo-chroot
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
ROOT="$PWD/demo"
|
||||
|
||||
# Clean up on EXIT
|
||||
function cleanup {
|
||||
umount "$ROOT"/{dev/pts,dev,sys,proc} 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# mount binds
|
||||
mount --bind /dev "$ROOT/dev/"
|
||||
mount --bind /sys "$ROOT/sys/"
|
||||
mount --bind /proc "$ROOT/proc/"
|
||||
mount --bind /dev/pts "$ROOT/dev/pts"
|
||||
|
||||
chroot "$ROOT" "$@"
|
||||
12
scripts/edit-boot-config
Normal file
12
scripts/edit-boot-config
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
cp /boot/config.txt /tmp/
|
||||
|
||||
edit-config /tmp/config.txt "$@"
|
||||
|
||||
diff /boot/config.txt /tmp/config.txt >/dev/null
|
||||
if [ $? -eq 1 ]; then
|
||||
mount -o remount,rw /boot
|
||||
mv /tmp/config.txt /boot/
|
||||
mount -o remount,ro /boot
|
||||
fi
|
||||
83
scripts/edit-config
Normal file
83
scripts/edit-config
Normal file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import re
|
||||
|
||||
|
||||
def option_type(s, pat = re.compile(r'\w+=.*')):
|
||||
if not pat.match(s): raise argparse.ArgumentTypeError
|
||||
return s
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(description = 'Edit config file.')
|
||||
parser.add_argument('config', help = 'The configuration file to edit.')
|
||||
parser.add_argument('options', nargs = '*', type = option_type,
|
||||
metavar = '<name>=<value>', help = 'An option to set.')
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
# Parse config lines and options
|
||||
lines = []
|
||||
options = {}
|
||||
optRE = re.compile(r'(\w+)\s*=\s*([^#]+)(#.*)?')
|
||||
|
||||
|
||||
class Line:
|
||||
def __init__(self, text, name = None, value = None, comment = None):
|
||||
self.text = text
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.comment = comment
|
||||
|
||||
|
||||
def __str__(self):
|
||||
if self.name is not None:
|
||||
if self.value.strip():
|
||||
text = '%s=%s' % (self.name, self.value)
|
||||
if self.comment: text += ' # ' + self.comment
|
||||
text += '\n'
|
||||
return text
|
||||
|
||||
else: return ''
|
||||
|
||||
return self.text
|
||||
|
||||
|
||||
with open(args.config, 'r') as f:
|
||||
for line in f:
|
||||
m = optRE.match(line.strip())
|
||||
|
||||
if m: name, value, comment = m.groups()
|
||||
else: name, value, comment = None, None, None
|
||||
|
||||
l = Line(line, name, value, comment)
|
||||
lines.append(l)
|
||||
if name is not None: options[name] = l
|
||||
|
||||
|
||||
# Save original config
|
||||
config = ''.join(map(str, lines))
|
||||
|
||||
|
||||
# Set options
|
||||
first = True
|
||||
for opt in args.options:
|
||||
name, value = opt.split('=', 1)
|
||||
|
||||
if name in options: options[name].value = value
|
||||
else:
|
||||
if first and len(lines) and str(lines[:-1]).strip() != '':
|
||||
first = False
|
||||
lines.append(Line('\n'))
|
||||
|
||||
lines.append(Line(None, name, value, None))
|
||||
|
||||
|
||||
# Assemble new config
|
||||
new_config = ''.join(map(str, lines))
|
||||
|
||||
|
||||
if new_config != config:
|
||||
with open(args.config, 'w') as f:
|
||||
f.write(new_config)
|
||||
6
scripts/gplan-build.sh
Normal file
6
scripts/gplan-build.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
cd /mnt/host
|
||||
scons -C cbang disable_local="re2 libevent"
|
||||
export CBANG_HOME="/mnt/host/cbang"
|
||||
scons -C camotics gplan.so with_gui=0 with_tpl=0
|
||||
59
scripts/gplan-init-build.sh
Normal file
59
scripts/gplan-init-build.sh
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
IMG_DATE=2017-11-29
|
||||
IMG_BASE=${IMG_DATE}-raspbian-stretch-lite
|
||||
BASE_URL=https://downloads.raspberrypi.org/raspbian_lite/images
|
||||
IMG_URL=$BASE_URL/raspbian_lite-2017-12-01/$IMG_BASE.zip
|
||||
GPLAN_IMG=gplan-dev.img
|
||||
|
||||
# Create dev image
|
||||
if [ ! -e $GPLAN_IMG ]; then
|
||||
|
||||
# Get base image
|
||||
if [ ! -e $IMG_BASE.img ]; then
|
||||
if [ ! -e $IMG_BASE.zip ]; then
|
||||
wget $IMG_URL
|
||||
fi
|
||||
|
||||
unzip $IMG_BASE.zip
|
||||
fi
|
||||
|
||||
# Copy base image
|
||||
cp $IMG_BASE.img $GPLAN_IMG.tmp
|
||||
|
||||
# Init image
|
||||
mkdir -p rpi-share
|
||||
cp ./scripts/gplan-init-dev-img.sh rpi-share
|
||||
sudo ./scripts/rpi-chroot.sh $GPLAN_IMG.tmp /mnt/host/gplan-init-dev-img.sh
|
||||
|
||||
# Move image
|
||||
mv $GPLAN_IMG.tmp $GPLAN_IMG
|
||||
fi
|
||||
|
||||
# Get repos
|
||||
function fetch_local_repo() {
|
||||
mkdir -p $1
|
||||
git -C $1 init
|
||||
git -C $1 fetch -t "$2" $3
|
||||
git -C $1 reset --hard FETCH_HEAD
|
||||
}
|
||||
|
||||
mkdir -p rpi-share || true
|
||||
|
||||
if [ ! -e rpi-share/cbang ]; then
|
||||
if [ "$CBANG_HOME" != "" ]; then
|
||||
fetch_local_repo rpi-share/cbang "$CBANG_HOME" master
|
||||
else
|
||||
git clone https://github.com/CauldronDevelopmentLLC/cbang \
|
||||
rpi-share/cbang
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -e rpi-share/camotics ]; then
|
||||
if [ "$CAMOTICS_HOME" != "" ]; then
|
||||
fetch_local_repo rpi-share/camotics "$CAMOTICS_HOME" master
|
||||
else
|
||||
git clone https://github.com/CauldronDevelopmentLLC/camotics \
|
||||
rpi-share/camotics
|
||||
fi
|
||||
fi
|
||||
11
scripts/gplan-init-dev-img.sh
Normal file
11
scripts/gplan-init-dev-img.sh
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
export LC_ALL=C
|
||||
cd /mnt/host
|
||||
|
||||
# Update the system
|
||||
apt-get update
|
||||
#apt-get dist-upgrade -y
|
||||
|
||||
# Install packages
|
||||
apt-get install -y scons build-essential libssl-dev python3-dev
|
||||
121
scripts/install.sh
Normal file
121
scripts/install.sh
Normal file
@@ -0,0 +1,121 @@
|
||||
#!/bin/bash
|
||||
|
||||
UPDATE_AVR=true
|
||||
UPDATE_PY=true
|
||||
REBOOT=false
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--no-avr) UPDATE_AVR=false ;;
|
||||
--no-py) UPDATE_PY=false ;;
|
||||
esac
|
||||
shift 1
|
||||
done
|
||||
|
||||
|
||||
if $UPDATE_PY; then
|
||||
systemctl stop bbctrl
|
||||
|
||||
# Update service
|
||||
rm -f /etc/init.d/bbctrl
|
||||
cp scripts/bbctrl.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable bbctrl
|
||||
fi
|
||||
|
||||
if $UPDATE_AVR; then
|
||||
./scripts/avr109-flash.py src/avr/bbctrl-avr-firmware.hex
|
||||
fi
|
||||
|
||||
# Update config.txt
|
||||
./scripts/edit-boot-config max_usb_current=1
|
||||
./scripts/edit-boot-config config_hdmi_boost=8
|
||||
|
||||
# TODO Enable GPU
|
||||
#./scripts/edit-boot-config dtoverlay=vc4-kms-v3d
|
||||
#./scripts/edit-boot-config gpu_mem=16
|
||||
#chmod ug+s /usr/lib/xorg/Xorg
|
||||
|
||||
# Fix camera
|
||||
grep dwc_otg.fiq_fsm_mask /boot/cmdline.txt >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
mount -o remount,rw /boot &&
|
||||
sed -i 's/\(.*\)/\1 dwc_otg.fiq_fsm_mask=0x3/' /boot/cmdline.txt
|
||||
mount -o remount,ro /boot
|
||||
REBOOT=true
|
||||
fi
|
||||
|
||||
# Enable memory cgroups
|
||||
grep cgroup_memory /boot/cmdline.txt >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
mount -o remount,rw /boot &&
|
||||
sed -i 's/\(.*\)/\1 cgroup_memory=1/' /boot/cmdline.txt
|
||||
mount -o remount,ro /boot
|
||||
REBOOT=true
|
||||
fi
|
||||
|
||||
# Remove Hawkeye
|
||||
if [ -e /etc/init.d/hawkeye ]; then
|
||||
apt-get remove --purge -y hawkeye
|
||||
fi
|
||||
|
||||
# Decrease boot delay
|
||||
sed -i 's/^TimeoutStartSec=.*$/TimeoutStartSec=1/' \
|
||||
/etc/systemd/system/network-online.target.wants/networking.service
|
||||
|
||||
# Change to US keyboard layout
|
||||
sed -i 's/^XKBLAYOUT="gb"$/XKBLAYOUT="us" # Comment stops change on upgrade/' \
|
||||
/etc/default/keyboard
|
||||
|
||||
# Setup USB stick automount
|
||||
diff ./scripts/11-automount.rules /etc/udev/rules.d/11-automount.rules \
|
||||
>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
cp ./scripts/11-automount.rules /etc/udev/rules.d/
|
||||
sed -i 's/^\(MountFlags=slave\)/#\1/' \
|
||||
/lib/systemd/system/systemd-udevd.service
|
||||
REBOOT=true
|
||||
fi
|
||||
|
||||
# Increase swap
|
||||
grep 'CONF_SWAPSIZE=1000' /etc/dphys-swapfile >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
sed -i 's/^CONF_SWAPSIZE=.*$/CONF_SWAPSIZE=1000/' /etc/dphys-swapfile
|
||||
REBOOT=true
|
||||
fi
|
||||
|
||||
# Install xinitrc
|
||||
cp scripts/xinitrc ~pi/.xinitrc
|
||||
chmod +x ~pi/.xinitrc
|
||||
chown pi:pi ~pi/.xinitrc
|
||||
|
||||
# Install bbserial
|
||||
MODSRC=src/bbserial/bbserial.ko
|
||||
MODDST=/lib/modules/$(uname -r)/kernel/drivers/tty/serial/bbserial.ko
|
||||
diff -q $MODSRC $MODDST 2>/dev/null >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
cp $MODSRC $MODDST
|
||||
depmod
|
||||
REBOOT=true
|
||||
fi
|
||||
|
||||
# Install rc.local
|
||||
cp scripts/rc.local /etc/
|
||||
|
||||
# Install bbctrl
|
||||
if $UPDATE_PY; then
|
||||
rm -rf /usr/local/lib/python*/dist-packages/bbctrl-*
|
||||
./setup.py install --force
|
||||
service bbctrl restart
|
||||
HTTP_DIR=$(find /usr/local/lib/ -type d -name "http")
|
||||
chmod 777 $HTTP_DIR
|
||||
fi
|
||||
|
||||
sync
|
||||
|
||||
if $REBOOT; then
|
||||
echo "Rebooting"
|
||||
reboot
|
||||
fi
|
||||
|
||||
echo "Install complete"
|
||||
27
scripts/log-position-to-gcode
Normal file
27
scripts/log-position-to-gcode
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
p = [0, 0, 0]
|
||||
|
||||
|
||||
print('F400 G21')
|
||||
|
||||
for line in sys.stdin:
|
||||
try:
|
||||
if not line.startswith('I:Comm:> '): continue
|
||||
line = line[9:]
|
||||
|
||||
data = json.loads(line)
|
||||
|
||||
changed = False
|
||||
for axis in range(3):
|
||||
var = 'xyz'[axis] + 'p'
|
||||
if var in data:
|
||||
p[axis] = data[var]
|
||||
changed = True
|
||||
|
||||
if changed: print('G1 X%d Y%d Z%d' % tuple(p))
|
||||
|
||||
except json.decoder.JSONDecodeError: pass
|
||||
19
scripts/next-rc
Normal file
19
scripts/next-rc
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
if os.path.exists('dist/latest-beta.txt'):
|
||||
with open('dist/latest-beta.txt', 'r') as f:
|
||||
latest_beta = f.read().strip()
|
||||
|
||||
else: latest_beta = ''
|
||||
|
||||
with open('package.json', 'r') as f:
|
||||
version = json.load(f)['version']
|
||||
|
||||
if latest_beta.startswith(version + '-rc'):
|
||||
print(int(latest_beta[len(version) + 3:]) + 1)
|
||||
|
||||
else:
|
||||
print(1)
|
||||
1
scripts/ratpoisonrc
Normal file
1
scripts/ratpoisonrc
Normal file
@@ -0,0 +1 @@
|
||||
startup_message off
|
||||
31
scripts/rc.local
Normal file
31
scripts/rc.local
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Mount /boot read only
|
||||
mount -o remount,ro /boot
|
||||
|
||||
# Load bbserial
|
||||
echo 3f201000.serial > /sys/bus/amba/drivers/uart-pl011/unbind
|
||||
modprobe -r bbserial
|
||||
modprobe bbserial
|
||||
|
||||
# Set SPI GPIO mode
|
||||
gpio mode 27 alt3
|
||||
|
||||
# Create browser memory limited cgroup
|
||||
if [ -d sys/fs/cgroup/memory ]; then
|
||||
CGROUP=/sys/fs/cgroup/memory/chrome
|
||||
mkdir $CGROUP
|
||||
chown -R pi:pi $CGROUP
|
||||
echo 650000000 > $CGROUP/memory.soft_limit_in_bytes
|
||||
echo 750000000 > $CGROUP/memory.limit_in_bytes
|
||||
fi
|
||||
|
||||
# Reload udev
|
||||
/etc/init.d/udev restart
|
||||
|
||||
# Stop boot splash so it doesn't interfere with X if GPU enabled and to save CPU
|
||||
plymouth quit
|
||||
|
||||
# Start X in /home/pi
|
||||
cd /home/pi
|
||||
sudo -u pi startx
|
||||
23
scripts/reset-video
Normal file
23
scripts/reset-video
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import os.path
|
||||
import time
|
||||
|
||||
if not os.path.exists('/dev/video0'):
|
||||
print('/dev/video0 not found')
|
||||
sys.exit(1)
|
||||
|
||||
p = subprocess.Popen('udevadm info -q path /dev/video0'.split(),
|
||||
stdout = subprocess.PIPE)
|
||||
s = p.communicate()[0].decode('utf-8')
|
||||
dev = s.split('/')[7]
|
||||
|
||||
with open('/sys/bus/usb/drivers/usb/unbind', 'w') as f:
|
||||
f.write(dev)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
with open('/sys/bus/usb/drivers/usb/bind', 'w') as f:
|
||||
f.write(dev)
|
||||
63
scripts/rpi-chroot.sh
Normal file
63
scripts/rpi-chroot.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
ROOT="$PWD/rpi-root"
|
||||
LOOP=9
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <image> <exec>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IMAGE="$1"
|
||||
LOOP_DEV=/dev/loop${LOOP}
|
||||
EXEC=
|
||||
|
||||
if [ $# -gt 1 ]; then
|
||||
shift
|
||||
EXEC="$@"
|
||||
fi
|
||||
|
||||
# install dependecies
|
||||
if [ ! -e /usr/bin/qemu-arm-static ]; then
|
||||
apt-get update
|
||||
apt-get install -y qemu qemu-user-static binfmt-support
|
||||
fi
|
||||
|
||||
# Clean up on EXIT
|
||||
function cleanup {
|
||||
umount "$ROOT"/{dev/pts,dev,sys,proc,boot,mnt/host,} 2>/dev/null || true
|
||||
losetup -d $LOOP_DEV 2>/dev/null || true
|
||||
rmdir "$ROOT" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# set up image as loop device
|
||||
losetup $LOOP_DEV "$IMAGE"
|
||||
partprobe $LOOP_DEV
|
||||
|
||||
# check and fix filesystems
|
||||
fsck -f ${LOOP_DEV}p1
|
||||
fsck -f ${LOOP_DEV}p2
|
||||
|
||||
# make dir
|
||||
mkdir -p "$ROOT"
|
||||
|
||||
# mount partition
|
||||
mount -o rw ${LOOP_DEV}p2 -t ext4 "$ROOT"
|
||||
mount -o rw ${LOOP_DEV}p1 "$ROOT/boot"
|
||||
|
||||
# mount binds
|
||||
mount --bind /dev "$ROOT/dev/"
|
||||
mount --bind /sys "$ROOT/sys/"
|
||||
mount --bind /proc "$ROOT/proc/"
|
||||
mount --bind /dev/pts "$ROOT/dev/pts"
|
||||
if [ -e ./rpi-share ]; then
|
||||
mkdir -p "$ROOT/mnt/host"
|
||||
mount --bind ./rpi-share "$ROOT/mnt/host"
|
||||
fi
|
||||
|
||||
# copy qemu binary
|
||||
cp /usr/bin/qemu-arm-static "$ROOT/usr/bin/"
|
||||
|
||||
# chroot to raspbian
|
||||
chroot "$ROOT" $EXEC
|
||||
26
scripts/sethostname
Normal file
26
scripts/sethostname
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
HOSTNAME="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [ "$HOSTNAME" == "" ]; then
|
||||
echo "Usage: $0 <hostname>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$HOSTNAME" == "localhost" ]; then
|
||||
echo "Cannot set hostname to 'localhost'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$HOSTNAME" =~ ^.*\.local$ ]; then
|
||||
echo "Hostname cannot end with '.local'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! "$HOSTNAME" =~ ^[a-zA-Z][a-zA-Z0-9-]{0,62}$ ]]; then
|
||||
echo "Invalid hostname '$HOSTNAME'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sed -i "s/^127.0.1.1\([[:space:]]*\).*$/127.0.1.1\1$HOSTNAME/" /etc/hosts
|
||||
echo "$HOSTNAME" > /etc/hostname
|
||||
110
scripts/setup_rpi.sh
Normal file
110
scripts/setup_rpi.sh
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
export LC_ALL=C
|
||||
cd /mnt/host
|
||||
|
||||
# Update the system
|
||||
apt-get update
|
||||
apt-get dist-upgrade -y
|
||||
|
||||
# Install packages
|
||||
apt-get install -y avahi-daemon avrdude minicom python3-pip python3-smbus \
|
||||
i2c-tools python3-rpi.gpio libjpeg8 wiringpi dnsmasq hostapd \
|
||||
iptables-persistent chromium-browser xorg rpd-plym-splash samba
|
||||
pip3 install --upgrade tornado sockjs-tornado pyserial
|
||||
|
||||
# Clean
|
||||
apt-get autoclean
|
||||
|
||||
# Enable avahi
|
||||
update-rc.d avahi-daemon defaults
|
||||
|
||||
# Change hostname
|
||||
sed -i "s/raspberrypi/bbctrl/" /etc/hosts /etc/hostname
|
||||
|
||||
# Create bbmc user
|
||||
useradd -m -p $(openssl passwd -1 buildbotics) -s /bin/bash bbmc
|
||||
sed -i 's/pi$/pi,bbmc/g' /etc/group
|
||||
passwd -l pi
|
||||
|
||||
# Disable console on serial port
|
||||
sed -i 's/console=[a-zA-Z0-9]*,115200 \?//' /boot/cmdline.txt
|
||||
|
||||
# Disable i2c HAT ID probe
|
||||
echo -n " bcm2708.vc_i2c_override=1" >> /boot/cmdline.txt
|
||||
|
||||
# Enable I2C
|
||||
sed -i 's/#dtparam=i2c/dtparam=i2c/' /boot/config.txt
|
||||
#echo 'dtparam=i2c_vc=on' >> /boot/config.txt
|
||||
echo i2c-bcm2708 >> /etc/modules
|
||||
echo i2c-dev >> /etc/modules
|
||||
|
||||
# Install bbctrl w/ init.d script
|
||||
cp bbctrl.init.d /etc/init.d/bbctrl
|
||||
chmod +x /etc/init.d/bbctrl
|
||||
update-rc.d bbctrl defaults
|
||||
|
||||
# Disable Pi 3 USART BlueTooth swap
|
||||
echo -e "\ndtoverlay=pi3-disable-bt" >> /boot/config.txt
|
||||
rm -f /etc/systemd/system/multi-user.target.wants/hciuart.service
|
||||
|
||||
# Install hawkeye
|
||||
dpkg -i hawkeye_0.6_armhf.deb
|
||||
sed -i 's/localhost/0.0.0.0/' /etc/hawkeye/hawkeye.conf
|
||||
echo 'ACTION=="add", KERNEL=="video0", RUN+="/usr/sbin/service hawkeye restart"' > /etc/udev/rules.d/50-hawkeye.rules
|
||||
adduser hawkeye video
|
||||
|
||||
# Disable HDMI to save power and remount /boot read-only
|
||||
sed -i 's/^exit 0$//' /etc/rc.local
|
||||
echo "mount -o remount,ro /boot" >> /etc/rc.local
|
||||
echo "gpio mode 27 alt3" >> /etc/rc.local # Enable serial CTS on pin 27
|
||||
|
||||
# Dynamic clock to save power
|
||||
echo -e "\n# Dynamic clock\nnohz=on" >> /boot/config.txt
|
||||
|
||||
# Shave 2 sec off of boot time
|
||||
echo -e "\n# Faster boot\ndtparam=sd_overclock=100" >> /boot/config.txt
|
||||
|
||||
# Enable ssh
|
||||
touch /boot/ssh
|
||||
|
||||
# Fix boot
|
||||
sed -i 's/ root=[^ ]* / root=\/dev\/mmcblk0p2/' /boot/cmdline.txt
|
||||
sed -i 's/^PARTUUID=.*\/boot/\/dev\/mmcblk0p1 \/boot/' /etc/fstab
|
||||
sed -i 's/^PARTUUID=.*\//\/dev\/mmcblk0p2 \//' /etc/fstab
|
||||
|
||||
# Enable browser in xorg
|
||||
sed -i 's/allowed_users=console/allowed_users=anybody/' /etc/X11/Xwrapper.config
|
||||
echo "sudo -u pi startx" >> /etc/rc.local
|
||||
cp /mnt/host/xinitrc /home/pi/.xinitrc
|
||||
cp /mnt/host/ratpoisonrc /home/pi/.ratpoisonrc
|
||||
cp /mnt/host/xorg.conf /etc/X11/
|
||||
|
||||
# Set screen resolution
|
||||
sed -i 's/^#disable_overscan/disable_overscan/' /boot/config.txt
|
||||
sed -i 's/^#framebuffer_/framebuffer_/' /boot/config.txt
|
||||
|
||||
# Boot splash
|
||||
mkdir -p /usr/share/plymouth/themes/buildbotics/
|
||||
cp -av /mnt/host/splash/* /usr/share/plymouth/themes/buildbotics/
|
||||
echo -n " quiet splash logo.nologo plymouth.ignore-serial-consoles" >> /boot/cmdline.txt
|
||||
plymouth-set-default-theme -R buildbotics
|
||||
|
||||
# Samba
|
||||
# TODO install custom smb.conf
|
||||
smbpasswd -a bbmc
|
||||
|
||||
# Install bbctrl
|
||||
tar xf /mnt/host/bbctrl-*.tar.bz2
|
||||
cd $(basename bbctrl-*.tar.bz2 .tar.bz2)
|
||||
./setup.py install
|
||||
cd ..
|
||||
rm -rf $(basename bbctrl-*.tar.bz2 .tar.bz2)
|
||||
|
||||
|
||||
# Allow any user to shutdown
|
||||
chmod +s /sbin/{halt,reboot,shutdown,poweroff}
|
||||
|
||||
# Clean up
|
||||
apt-get autoremove -y
|
||||
apt-get autoclean -y
|
||||
16
scripts/ssh-bbctrl
Normal file
16
scripts/ssh-bbctrl
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
USER=bbmc
|
||||
HOST=bbctrl.local
|
||||
|
||||
if [ $# -eq 1 ]; then
|
||||
if [[ "$1" = *@ ]]; then
|
||||
LOGIN="$1"
|
||||
else
|
||||
LOGIN=$USER@"$1"
|
||||
fi
|
||||
else
|
||||
LOGIN=$USER@$HOST
|
||||
fi
|
||||
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$LOGIN"
|
||||
64
scripts/svg2abs.js
Normal file
64
scripts/svg2abs.js
Normal file
@@ -0,0 +1,64 @@
|
||||
function convertToAbsolute(path) {
|
||||
var x0, y0, x1, y1, x2, y2, segs = path.pathSegList;
|
||||
|
||||
for (var x = 0, y = 0, i = 0, len = segs.numberOfItems; i < len; i++) {
|
||||
var seg = segs.getItem(i), c = seg.pathSegTypeAsLetter;
|
||||
|
||||
if (/[MLHVCSQTA]/.test(c)){
|
||||
if ('x' in seg) x = seg.x;
|
||||
if ('y' in seg) y = seg.y;
|
||||
|
||||
} else {
|
||||
if ('x1' in seg) x1 = x + seg.x1;
|
||||
if ('x2' in seg) x2 = x + seg.x2;
|
||||
if ('y1' in seg) y1 = y + seg.y1;
|
||||
if ('y2' in seg) y2 = y + seg.y2;
|
||||
if ('x' in seg) x += seg.x;
|
||||
if ('y' in seg) y += seg.y;
|
||||
|
||||
switch(c) {
|
||||
case 'm':
|
||||
segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i);
|
||||
break;
|
||||
case 'l':
|
||||
segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i);
|
||||
break;
|
||||
case 'h':
|
||||
segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i);
|
||||
break;
|
||||
case 'v':
|
||||
segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i);
|
||||
break;
|
||||
case 'c':
|
||||
segs.replaceItem(
|
||||
path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i);
|
||||
break;
|
||||
case 's':
|
||||
segs.replaceItem(
|
||||
path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i);
|
||||
break;
|
||||
case 'q':
|
||||
segs.replaceItem(
|
||||
path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i);
|
||||
break;
|
||||
case 't':
|
||||
segs.replaceItem(
|
||||
path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i);
|
||||
break;
|
||||
case 'a':
|
||||
segs.replaceItem(
|
||||
path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle,
|
||||
seg.largeArcFlag, seg.sweepFlag), i);
|
||||
break;
|
||||
|
||||
case 'z': case 'Z':
|
||||
x = x0;
|
||||
y = y0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Record the start of a subpath
|
||||
if (c == 'M' || c == 'm') x0 = x, y0 = y;
|
||||
}
|
||||
}
|
||||
27
scripts/update-bbctrl
Normal file
27
scripts/update-bbctrl
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
(
|
||||
flock -n 9
|
||||
|
||||
UPDATE=/var/lib/bbctrl/firmware/update.tar.bz2
|
||||
|
||||
if [ ! -e "$UPDATE" ]; then
|
||||
echo "Missing $UPDATE"
|
||||
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 "$*" 2>&1 > $LOG
|
||||
|
||||
cd -
|
||||
rm -rf /tmp/update $UPDATE
|
||||
|
||||
) 9> /var/lock/bbctrl.update.lock
|
||||
25
scripts/upgrade-bbctrl
Normal file
25
scripts/upgrade-bbctrl
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
(
|
||||
flock -n 9
|
||||
|
||||
VERSION=$(curl -s https://raw.githubusercontent.com/OneFinityCNC/onefinity/master/latest.txt)
|
||||
PKG_NAME=onefinity-$VERSION
|
||||
PKG=/var/lib/bbctrl/firmware/update.tar.bz2
|
||||
PKG_URL=https://https://raw.githubusercontent.com/OneFinityCNC/onefinity/master/release/$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
|
||||
|
||||
/usr/local/bin/update-bbctrl
|
||||
|
||||
echo Success
|
||||
|
||||
logger bbctrl firmware $VERSION installed
|
||||
|
||||
) 9> /var/lock/bbctrl.upgrade.lock
|
||||
22
scripts/xinitrc
Normal file
22
scripts/xinitrc
Normal file
@@ -0,0 +1,22 @@
|
||||
hostinfo.sh &
|
||||
ratpoison &
|
||||
|
||||
xset -dpms
|
||||
xset s off
|
||||
xset s noblank
|
||||
|
||||
while true; do
|
||||
tvservice -s 2>&1 | grep "state 0x40001" >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
# Clear browser errors
|
||||
PREFS='/home/pi/.config/chromium/Default/Preferences'
|
||||
sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' $PREFS
|
||||
sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' $PREFS
|
||||
|
||||
# Start browser
|
||||
/usr/local/bin/browser --no-first-run --disable-infobars \
|
||||
--noerrdialogs --disable-3d-apis http://localhost/
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
done
|
||||
3
scripts/xorg.conf
Normal file
3
scripts/xorg.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
Section "ServerFlags"
|
||||
Option "DontVTSwitch" "on"
|
||||
EndSection
|
||||
40
setup.py
Normal file
40
setup.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from setuptools import setup
|
||||
import json
|
||||
|
||||
pkg = json.load(open('package.json', 'r'))
|
||||
|
||||
|
||||
setup(
|
||||
name = pkg['name'],
|
||||
version = pkg['version'],
|
||||
description = 'Buildbotics Machine Controller',
|
||||
long_description = open('README.md', 'rt').read(),
|
||||
author = 'Joseph Coffland',
|
||||
author_email = 'joseph@buildbotics.org',
|
||||
platforms = ['any'],
|
||||
license = pkg['license'],
|
||||
url = pkg['homepage'],
|
||||
package_dir = {'': 'src/py'},
|
||||
packages = ['bbctrl', 'inevent', 'lcd', 'camotics'],
|
||||
include_package_data = True,
|
||||
entry_points = {
|
||||
'console_scripts': [
|
||||
'bbctrl = bbctrl:run'
|
||||
]
|
||||
},
|
||||
scripts = [
|
||||
'scripts/update-bbctrl',
|
||||
'scripts/upgrade-bbctrl',
|
||||
'scripts/sethostname',
|
||||
'scripts/reset-video',
|
||||
'scripts/config-wifi',
|
||||
'scripts/config-screen',
|
||||
'scripts/edit-config',
|
||||
'scripts/edit-boot-config',
|
||||
'scripts/browser',
|
||||
],
|
||||
install_requires = 'tornado sockjs-tornado pyserial pyudev smbus2'.split(),
|
||||
zip_safe = False,
|
||||
)
|
||||
14
src/avr/.gitignore
vendored
Normal file
14
src/avr/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Backup files
|
||||
*~
|
||||
\#*
|
||||
|
||||
build
|
||||
.dep
|
||||
|
||||
/*.eep
|
||||
/*.hex
|
||||
/*.elf
|
||||
/*.lss
|
||||
/*.map
|
||||
|
||||
*.o
|
||||
56
src/avr/BezierMath.md
Normal file
56
src/avr/BezierMath.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Cubic Bezier
|
||||
|
||||
f(x) = A(1 - x)^3 + 3B(1 - x)^2 x + 3C(1 - x) x^2 + Dx^3
|
||||
|
||||
-Ax^3 + 3Ax^2 - 3Ax + A
|
||||
3Bx^3 - 6Bx^2 + 3Bx
|
||||
-3Cx^3 + 3Cx^2
|
||||
Dx^3
|
||||
|
||||
|
||||
f(x) = (-A + 3B -3C + D)x^3 + (3A - 6B + 3C)x^2 + (-3A + 3B)x + A
|
||||
|
||||
a = -A + 3B - 3C + D
|
||||
b = 3A - 6B + 3C
|
||||
c = -3A + 3B
|
||||
d = A
|
||||
|
||||
f(x) = ax^3 + bx^2 + cx + d
|
||||
|
||||
integral f(x) dx = a/4 x^4 + b/3 x^3 + c/2 x^2 + dx + E
|
||||
|
||||
= (-A + 3B - 3C + D)/4 x^4 + (A - 2B + B) x^3 + 3/2 (B - A) x^2 + Ax + E
|
||||
|
||||
# Quintic Bezier
|
||||
|
||||
A(1 - x)^5 + 5A(1 - x)^4 x + 10A(1 - x)^3 x^2 + 10B(1 - x)^2 x^3 +
|
||||
5B(1 - x)x^4 + Bx^5
|
||||
|
||||
(-6A + 6B)x^5 + (15A - 15B)x^4 + (-10A + 10B)x^3 + A
|
||||
|
||||
6(B - A)x^5 + 15(A - B)x^4 + 10(B - A)x^3 + A
|
||||
|
||||
x^3 (6(B - A)x^2 + 15(A - B)x + 10(B - A)) + A
|
||||
|
||||
a = 6(B - A)
|
||||
b = -15(B - A)
|
||||
c = 10(B - A)
|
||||
d = A
|
||||
|
||||
f(x) = ax^5 + bx^4 + cx^3 + d
|
||||
|
||||
f(x) = (ax^2 + bx + c)x^3 + d
|
||||
|
||||
|
||||
integral f(x) = a/6 x^6 + b/5 x^5 + c/4 x^4 + dx + e
|
||||
|
||||
= (B - A)x^6 - 3(B - A)x^5 + 5/2(B - A)x^4 + Ax + e
|
||||
|
||||
= (B - A)x^4 (x^2 - 3x + 5/2) + Ax + e
|
||||
|
||||
A = 0
|
||||
B = 1
|
||||
e = 0
|
||||
|
||||
f(x) = 6x^5 -15x^4 + 10x^3
|
||||
int f(x) dx = x^6 - 3x^5 + 5/2x^4 + C
|
||||
40
src/avr/Makefile
Normal file
40
src/avr/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
# Makefile for the project Bulidbotics firmware
|
||||
PROJECT = bbctrl-avr-firmware
|
||||
MCU = atxmega192a3u
|
||||
CLOCK = 32000000
|
||||
|
||||
# SRC
|
||||
SRC = $(wildcard src/*.c) $(wildcard src/*.cpp) $(wildcard src/vfd/*.c)
|
||||
OBJ := $(patsubst src/%.c,build/%.o,$(SRC))
|
||||
OBJ := $(patsubst src/%.cpp,build/%.o,$(OBJ))
|
||||
OBJ := $(patsubst src/vfd/%.c,build/vfd/%.o,$(OBJ))
|
||||
JSON = vars command messages
|
||||
JSON := $(patsubst %,build/%.json,$(JSON))
|
||||
|
||||
all: $(PROJECT).hex $(JSON) size
|
||||
|
||||
include Makefile.common
|
||||
|
||||
CFLAGS += -Isrc
|
||||
|
||||
# Build
|
||||
$(PROJECT).elf: $(OBJ)
|
||||
$(CC) $(LDFLAGS) $(OBJ) $(LIBS) -o $@
|
||||
|
||||
|
||||
# JSON
|
||||
build/%.json: src/%.json.in src/%.def
|
||||
cpp -Isrc $< | sed "/^#.*$$/d;s/'\(.\)'/\"\1\"/g" > $@
|
||||
|
||||
# Program
|
||||
init:
|
||||
$(MAKE) erase
|
||||
-$(MAKE) fuses
|
||||
$(MAKE) fuses
|
||||
$(MAKE) program-boot
|
||||
$(MAKE) program
|
||||
|
||||
program-boot:
|
||||
$(MAKE) -C ../boot program
|
||||
|
||||
.PHONY: all init program-boot
|
||||
115
src/avr/Makefile.common
Normal file
115
src/avr/Makefile.common
Normal file
@@ -0,0 +1,115 @@
|
||||
# Compile flags
|
||||
CC = avr-g++
|
||||
|
||||
COMMON = -mmcu=$(MCU) -flto -fwhole-program
|
||||
|
||||
CFLAGS += $(COMMON)
|
||||
CFLAGS += -Wall -Werror
|
||||
CFLAGS += -Wno-error=strict-aliasing # for _invsqrt
|
||||
CFLAGS += -std=gnu++98 -DF_CPU=$(CLOCK)UL -O3
|
||||
CFLAGS += -funsigned-bitfields -fpack-struct -fshort-enums -funsigned-char
|
||||
CFLAGS += -MD -MP -MT $@ -MF build/dep/$(@F).d
|
||||
CFLAGS += -D__STDC_LIMIT_MACROS
|
||||
|
||||
# Linker flags
|
||||
LDFLAGS += $(COMMON) -Wl,-u,vfprintf -lprintf_flt -lm
|
||||
LIBS += -lm
|
||||
|
||||
# EEPROM flags
|
||||
EEFLAGS += -j .eeprom
|
||||
EEFLAGS += --set-section-flags=.eeprom="alloc,load"
|
||||
EEFLAGS += --change-section-lma .eeprom=0 --no-change-warnings
|
||||
|
||||
# Programming flags
|
||||
ifndef (PROGRAMMER)
|
||||
PROGRAMMER = avrispmkII
|
||||
#PROGRAMMER = jtag3pdi
|
||||
endif
|
||||
PDEV = usb
|
||||
AVRDUDE_OPTS = -c $(PROGRAMMER) -p $(MCU) -P $(PDEV)
|
||||
|
||||
FUSE0=0xff
|
||||
FUSE1=0x00
|
||||
FUSE2=0xbe
|
||||
FUSE4=0xff
|
||||
FUSE5=0xeb
|
||||
|
||||
# Compile
|
||||
build/%.o: src/%.c
|
||||
@mkdir -p $(shell dirname $@)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
build/%.o: src/%.cpp
|
||||
@mkdir -p $(shell dirname $@)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
build/%.o: src/%.S
|
||||
@mkdir -p $(shell dirname $@)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
# Link
|
||||
%.hex: %.elf
|
||||
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@
|
||||
|
||||
%.eep: %.elf
|
||||
avr-objcopy $(EEFLAGS) -O ihex $< $@
|
||||
|
||||
%.lss: %.elf
|
||||
avr-objdump -h -S $< > $@
|
||||
|
||||
size: $(PROJECT).elf
|
||||
@for X in A B C; do\
|
||||
echo '****************************************************************' ;\
|
||||
avr-size -$$X --mcu=$(MCU) $(PROJECT).elf ;\
|
||||
done
|
||||
|
||||
data-usage: $(PROJECT).elf
|
||||
avr-nm -CS --size-sort -t decimal $(PROJECT).elf | grep ' [BbDd] '
|
||||
|
||||
|
||||
prog-usage: $(PROJECT).elf
|
||||
avr-nm -CS --size-sort -t decimal $(PROJECT).elf | grep -v ' [BbDd] '
|
||||
|
||||
# Program
|
||||
reset:
|
||||
avrdude $(AVRDUDE_OPTS)
|
||||
|
||||
erase:
|
||||
avrdude $(AVRDUDE_OPTS) -e
|
||||
|
||||
program: $(PROJECT).hex
|
||||
avrdude $(AVRDUDE_OPTS) -U flash:w:$(PROJECT).hex:i
|
||||
|
||||
verify: $(PROJECT).hex
|
||||
avrdude $(AVRDUDE_OPTS) -U flash:v:$(PROJECT).hex:i
|
||||
|
||||
fuses:
|
||||
avrdude $(AVRDUDE_OPTS) -U fuse0:w:$(FUSE0):m -U fuse1:w:$(FUSE1):m \
|
||||
-U fuse2:w:$(FUSE2):m -U fuse4:w:$(FUSE4):m -U fuse5:w:$(FUSE5):m
|
||||
|
||||
read_fuses:
|
||||
avrdude $(AVRDUDE_OPTS) -q -q -U fuse0:r:-:h -U fuse1:r:-:h -U fuse2:r:-:h \
|
||||
-U fuse4:r:-:h -U fuse5:r:-:h
|
||||
|
||||
signature:
|
||||
avrdude $(AVRDUDE_OPTS) -q -q -U signature:r:-:h
|
||||
|
||||
prodsig:
|
||||
avrdude $(AVRDUDE_OPTS) -q -q -U prodsig:r:-:h
|
||||
|
||||
usersig:
|
||||
avrdude $(AVRDUDE_OPTS) -q -q -U usersig:r:-:h
|
||||
|
||||
# Clean
|
||||
tidy:
|
||||
rm -f $(shell find -name \*~ -o -name \#\*)
|
||||
|
||||
clean: tidy
|
||||
rm -rf $(PROJECT).elf $(PROJECT).hex $(PROJECT).eep $(PROJECT).lss \
|
||||
$(PROJECT).map build
|
||||
|
||||
.PHONY: tidy clean size reset erase program fuses read_fuses prodsig
|
||||
.PHONY: signature usersig data-usage prog-usage
|
||||
|
||||
# Dependencies
|
||||
-include $(shell mkdir -p build/dep) $(wildcard build/dep/*)
|
||||
18
src/avr/README.md
Normal file
18
src/avr/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
The Buildbotics firmware is a 4 axis motion control system designed for
|
||||
high-performance on small to mid-sized machines. It operates in conjunction
|
||||
with the Buildbotics RaspberryPi firmware.
|
||||
|
||||
# Build Instructions
|
||||
To build in Linux run:
|
||||
|
||||
make
|
||||
|
||||
Other make commands are:
|
||||
|
||||
* **size** - Display program and data sizes
|
||||
* **program** - program using AVR dude and an avrispmkII
|
||||
* **erase** - Erase chip
|
||||
* **fuses** - Write AVR fuses bytes
|
||||
* **read_fuses** - Read and print AVR fuse bytes
|
||||
* **clean** - Remove build files
|
||||
* **tidy** - Remove backup files
|
||||
63
src/avr/data_usage.py
Normal file
63
src/avr/data_usage.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
################################################################################
|
||||
# #
|
||||
# This file is part of the Buildbotics firmware. #
|
||||
# #
|
||||
# Copyright (c) 2015 - 2018, Buildbotics LLC #
|
||||
# All rights reserved. #
|
||||
# #
|
||||
# This file ("the software") is free software: you can redistribute it #
|
||||
# and/or modify it under the terms of the GNU General Public License, #
|
||||
# version 2 as published by the Free Software Foundation. You should #
|
||||
# have received a copy of the GNU General Public License, version 2 #
|
||||
# along with the software. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# The software is distributed in the hope that it will be useful, but #
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
|
||||
# Lesser General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU Lesser General Public #
|
||||
# License along with the software. If not, see #
|
||||
# <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
# For information regarding this software email: #
|
||||
# "Joseph Coffland" <joseph@buildbotics.com> #
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
|
||||
lineRE = r'%(addr)s '
|
||||
command = 'avr-objdump -j .bss -t buildbotics.elf'
|
||||
|
||||
proc = subprocess.Popen(shlex.split(command), stdout = subprocess.PIPE)
|
||||
|
||||
out, err = proc.communicate()
|
||||
|
||||
if proc.returncode:
|
||||
print(out)
|
||||
raise Exception('command failed')
|
||||
|
||||
def get_sizes(data):
|
||||
for line in data.decode().split('\n'):
|
||||
if not re.match(r'^[0-9a-f]{8} .*', line): continue
|
||||
|
||||
size, name = int(line[22:30], 16), line[31:]
|
||||
if not size: continue
|
||||
|
||||
yield (size, name)
|
||||
|
||||
sizes = sorted(get_sizes(out))
|
||||
total = sum(x[0] for x in sizes)
|
||||
|
||||
for size, name in sizes:
|
||||
print('% 6d %5.2f%% %s' % (size, size / total * 100, name))
|
||||
|
||||
print('-' * 40)
|
||||
print('% 6d Total' % total)
|
||||
1
src/avr/emu/.gitignore
vendored
Normal file
1
src/avr/emu/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bbemu
|
||||
38
src/avr/emu/Makefile
Normal file
38
src/avr/emu/Makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
TARGET = bbemu
|
||||
|
||||
SRC:=$(wildcard ../src/*.c) $(wildcard ../src/*.cpp)
|
||||
OBJ:=$(patsubst %.cpp,%.o,$(patsubst %.c,%.o,$(SRC)))
|
||||
OBJ:=$(patsubst ../src/%,build/%,$(OBJ))
|
||||
SRC+=src/emu.c
|
||||
OBJ+=build/emu.o
|
||||
|
||||
CFLAGS = -I../src -Isrc -Wall -Werror -DDEBUG -g -std=gnu++98
|
||||
CFLAGS += -MD -MP -MT $@ -MF build/$(@F).d
|
||||
CFLAGS += -DF_CPU=32000000 -Wno-class-memaccess -pthread
|
||||
LDFLAGS = -lm -pthread
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
g++ -o $@ $(OBJ) $(LDFLAGS)
|
||||
|
||||
build/%.o: ../src/%.c
|
||||
g++ -c -o $@ $(CFLAGS) $<
|
||||
|
||||
build/%.o: src/%.c
|
||||
g++ -c -o $@ $(CFLAGS) $<
|
||||
|
||||
build/%.o: ../src/%.cpp
|
||||
g++ -c -o $@ $(CFLAGS) $<
|
||||
|
||||
# Clean
|
||||
tidy:
|
||||
rm -f $(shell find -name \*~ -o -name \#\*)
|
||||
|
||||
clean: tidy
|
||||
rm -rf $(TARGET) build
|
||||
|
||||
.PHONY: tidy clean all
|
||||
|
||||
# Dependencies
|
||||
-include $(shell mkdir -p build) $(wildcard build/*.d)
|
||||
34
src/avr/emu/src/avr/eeprom.h
Normal file
34
src/avr/emu/src/avr/eeprom.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define EEMEM
|
||||
|
||||
#define eeprom_update_word(PTR, VAL) *(PTR) = (VAL)
|
||||
#define eeprom_read_word(PTR) *(PTR)
|
||||
#define eeprom_is_ready() true
|
||||
35
src/avr/emu/src/avr/interrupt.h
Normal file
35
src/avr/emu/src/avr/interrupt.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "io.h"
|
||||
|
||||
void cli();
|
||||
void sei();
|
||||
|
||||
#define ISR(X) void __##X()
|
||||
7718
src/avr/emu/src/avr/io.h
Normal file
7718
src/avr/emu/src/avr/io.h
Normal file
File diff suppressed because it is too large
Load Diff
41
src/avr/emu/src/avr/pgmspace.h
Normal file
41
src/avr/emu/src/avr/pgmspace.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PRPSTR "s"
|
||||
#define PROGMEM
|
||||
#define PGM_P const char *
|
||||
#define PSTR(X) X
|
||||
#define vfprintf_P vfprintf
|
||||
#define printf_P printf
|
||||
#define puts_P puts
|
||||
#define sprintf_P sprintf
|
||||
#define strcmp_P strcmp
|
||||
#define pgm_read_ptr(x) *(x)
|
||||
#define pgm_read_word(x) *(x)
|
||||
#define pgm_read_byte(x) *(x)
|
||||
33
src/avr/emu/src/avr/wdt.h
Normal file
33
src/avr/emu/src/avr/wdt.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define WDTO_250MS 0
|
||||
#define wdt_enable(...)
|
||||
#define wdt_disable()
|
||||
#define wdt_reset()
|
||||
163
src/avr/emu/src/emu.c
Normal file
163
src/avr/emu/src/emu.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <avr/io.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
|
||||
void __SPIC_INT_vect(); // DRV8711 SPI
|
||||
void __I2C_ISR(); // I2C from RPi
|
||||
void __ADCA_CH0_vect(); // Analog input
|
||||
void __ADCA_CH1_vect(); // Analog input
|
||||
void __RS485_DRE_vect(); // RS848
|
||||
void __RS485_TXC_vect(); // RS848
|
||||
void __RS485_RXC_vect(); // RS848
|
||||
void __SERIAL_DRE_vect(); // Serial to RPi
|
||||
void __SERIAL_RXC_vect(); // Serial from RPi
|
||||
void __STEP_LOW_LEVEL_ISR(); // Stepper lo interrupt
|
||||
void __STEP_TIMER_ISR(); // Stepper hi interrupt
|
||||
void __RTC_OVF_vect(); // RTC tick
|
||||
|
||||
void motor_emulate_steps(int motor);
|
||||
|
||||
extern int __argc;
|
||||
extern char **__argv;
|
||||
|
||||
|
||||
volatile uint8_t io_mem[4096] = {0};
|
||||
|
||||
|
||||
bool fast = false;
|
||||
int serialByte = -1;
|
||||
uint8_t i2cData[I2C_MAX_DATA];
|
||||
int i2cIndex = 0;
|
||||
bool haveI2C = false;
|
||||
fd_set readFDs;
|
||||
|
||||
|
||||
void cli() {}
|
||||
void sei() {}
|
||||
|
||||
|
||||
void emu_init() {
|
||||
// Parse command line args
|
||||
for (int i = 0; i < __argc; i++)
|
||||
if (strcmp(__argv[i], "--fast") == 0) fast = true;
|
||||
|
||||
// Mark clocks ready
|
||||
OSC.STATUS = OSC_XOSCRDY_bm | OSC_PLLRDY_bm | OSC_RC32KRDY_bm;
|
||||
|
||||
// So usart_flush() returns
|
||||
SERIAL_PORT.STATUS = USART_DREIF_bm | USART_TXCIF_bm;
|
||||
|
||||
// Clear motor fault
|
||||
PIN_PORT(MOTOR_FAULT_PIN)->IN |= PIN_BM(MOTOR_FAULT_PIN);
|
||||
|
||||
FD_ZERO(&readFDs);
|
||||
}
|
||||
|
||||
|
||||
void emu_callback() {
|
||||
fflush(stdout);
|
||||
|
||||
if (RST.CTRL == RST_SWRST_bm) exit(0);
|
||||
|
||||
struct timeval t = {0, fast ? 0 : 1000};
|
||||
bool readData = true;
|
||||
while (readData) {
|
||||
readData = false;
|
||||
|
||||
// Try to read
|
||||
FD_SET(0, &readFDs);
|
||||
if (fcntl(3, F_GETFL) != -1) FD_SET(3, &readFDs);
|
||||
|
||||
if (0 < select(4, &readFDs, 0, 0, &t)) {
|
||||
uint8_t data;
|
||||
|
||||
if (serialByte == -1 && FD_ISSET(0, &readFDs) && read(0, &data, 1) == 1)
|
||||
serialByte = data;
|
||||
|
||||
if (!haveI2C && FD_ISSET(3, &readFDs) && read(3, &data, 1) == 1) {
|
||||
if (data == '\n') haveI2C = true;
|
||||
else if (i2cIndex < I2C_MAX_DATA) i2cData[i2cIndex++] = data;
|
||||
}
|
||||
}
|
||||
|
||||
// Send message to i2c port
|
||||
if (haveI2C && (I2C_DEV.SLAVE.CTRLA & TWI_SLAVE_INTLVL_LO_gc)) {
|
||||
// START
|
||||
I2C_DEV.SLAVE.STATUS = TWI_SLAVE_APIF_bm | TWI_SLAVE_AP_bm;
|
||||
__I2C_ISR();
|
||||
|
||||
// DATA
|
||||
for (int i = 0; i < i2cIndex; i++) {
|
||||
I2C_DEV.SLAVE.STATUS = TWI_SLAVE_DIF_bm;
|
||||
I2C_DEV.SLAVE.DATA = i2cData[i];
|
||||
__I2C_ISR();
|
||||
}
|
||||
|
||||
// STOP
|
||||
I2C_DEV.SLAVE.STATUS = TWI_SLAVE_APIF_bm;
|
||||
__I2C_ISR();
|
||||
|
||||
i2cIndex = 0;
|
||||
haveI2C = false;
|
||||
readData = true;
|
||||
}
|
||||
|
||||
// Send byte to serial port
|
||||
if (serialByte != -1 && SERIAL_PORT.CTRLA & USART_RXCINTLVL_MED_gc) {
|
||||
SERIAL_PORT.DATA = (uint8_t)serialByte;
|
||||
__SERIAL_RXC_vect();
|
||||
|
||||
if (SERIAL_PORT.CTRLA & USART_RXCINTLVL_MED_gc) {
|
||||
serialByte = -1;
|
||||
readData = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call stepper ISRs
|
||||
if (ADCB_CH0_INTCTRL == ADC_CH_INTLVL_LO_gc) __STEP_LOW_LEVEL_ISR();
|
||||
for (int motor = 0; motor < 4; motor++) motor_emulate_steps(motor);
|
||||
__STEP_TIMER_ISR();
|
||||
|
||||
// Call RTC
|
||||
__RTC_OVF_vect();
|
||||
|
||||
// Throttle with remaining time
|
||||
if (t.tv_usec) usleep(t.tv_usec);
|
||||
}
|
||||
31
src/avr/emu/src/util/atomic.h
Normal file
31
src/avr/emu/src/util/atomic.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define ATOMIC_BLOCK(x)
|
||||
#define ATOMIC_RESTORESTATE
|
||||
30
src/avr/emu/src/util/crc16.h
Normal file
30
src/avr/emu/src/util/crc16.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _crc16_update(...) 0
|
||||
33
src/avr/emu/src/util/delay.h
Normal file
33
src/avr/emu/src/util/delay.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define _delay_ms(x) usleep((x) * 1000)
|
||||
#define _delay_us(x) usleep(x)
|
||||
175
src/avr/src/SCurve.cpp
Normal file
175
src/avr/src/SCurve.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
|
||||
#include "SCurve.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
SCurve::SCurve(float maxV, float maxA, float maxJ) :
|
||||
maxV(maxV), maxA(maxA), maxJ(maxJ), v(0), a(0), j(0) {}
|
||||
|
||||
|
||||
unsigned SCurve::getPhase() const {
|
||||
if (!v) return 0;
|
||||
|
||||
// Handle negative velocity
|
||||
float v = this->v;
|
||||
float a = this->a;
|
||||
if (v < 0) {
|
||||
v = -v;
|
||||
a = -a;
|
||||
}
|
||||
|
||||
if (0 < a) {
|
||||
if (0 < j) return 1;
|
||||
if (!j) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (!a) return 4;
|
||||
if (j < 0) return 5;
|
||||
if (!j) return 6;
|
||||
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
float SCurve::getStoppingDist() const {return stoppingDist(v, a, maxA, maxJ);}
|
||||
|
||||
|
||||
float SCurve::next(float t, float targetV) {
|
||||
// Compute next acceleration
|
||||
float nextA = nextAccel(t, targetV, v, a, maxA, maxJ);
|
||||
|
||||
// Compute next velocity
|
||||
float deltaV = nextA * t;
|
||||
if ((deltaV < 0 && targetV < v && v + deltaV < targetV) ||
|
||||
(0 < deltaV && v < targetV && targetV < v + deltaV)) {
|
||||
nextA = (targetV - v) / t;
|
||||
v = targetV;
|
||||
|
||||
} else v += deltaV;
|
||||
|
||||
// Compute jerk = delta accel / time
|
||||
j = (nextA - a) / t;
|
||||
a = nextA;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
float SCurve::stoppingDist(float v, float a, float maxA, float maxJ) {
|
||||
// Already stopped
|
||||
if (!v) return 0;
|
||||
|
||||
// Handle negative velocity
|
||||
if (v < 0) {
|
||||
v = -v;
|
||||
a = -a;
|
||||
}
|
||||
|
||||
float d = 0;
|
||||
|
||||
// Compute distance and velocity change to accel = 0
|
||||
if (0 < a) {
|
||||
// Compute distance to decrease accel to zero
|
||||
float t = a / maxJ;
|
||||
d += distance(t, v, a, -maxJ);
|
||||
v += velocity(t, a, -maxJ);
|
||||
a = 0;
|
||||
}
|
||||
|
||||
// Compute max deccel
|
||||
float maxDeccel = -sqrt(v * maxJ + 0.5 * a * a);
|
||||
if (maxDeccel < -maxA) maxDeccel = -maxA;
|
||||
|
||||
// Compute distance and velocity change to max deccel
|
||||
if (maxDeccel < a) {
|
||||
float t = (a - maxDeccel) / maxJ;
|
||||
d += distance(t, v, a, -maxJ);
|
||||
v += velocity(t, a, -maxJ);
|
||||
a = maxDeccel;
|
||||
}
|
||||
|
||||
// Compute velocity change over remaining accel
|
||||
float deltaV = 0.5 * a * a / maxJ;
|
||||
|
||||
// Compute constant deccel period
|
||||
if (deltaV < v) {
|
||||
float t = (v - deltaV) / -a;
|
||||
d += distance(t, v, a, 0);
|
||||
v += velocity(t, a, 0);
|
||||
}
|
||||
|
||||
// Compute distance to zero vel
|
||||
d += distance(-a / maxJ, v, a, maxJ);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
float SCurve::nextAccel(float t, float targetV, float v, float a, float maxA,
|
||||
float maxJ) {
|
||||
bool increasing = v < targetV;
|
||||
float deltaA = acceleration(t, maxJ);
|
||||
|
||||
if (increasing && a < -deltaA)
|
||||
return a + deltaA; // negative accel, increasing speed
|
||||
|
||||
if (!increasing && deltaA < a)
|
||||
return a - deltaA; // positive accel, decreasing speed
|
||||
|
||||
float deltaV = fabs(targetV - v);
|
||||
float targetA = sqrt(2 * deltaV * maxJ);
|
||||
if (maxA < targetA) targetA = maxA;
|
||||
|
||||
if (increasing) {
|
||||
if (targetA < a + deltaA) return targetA;
|
||||
return a + deltaA;
|
||||
|
||||
} else {
|
||||
if (a - deltaA < -targetA) return -targetA;
|
||||
return a - deltaA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float SCurve::distance(float t, float v, float a, float j) {
|
||||
// v * t + 1/2 * a * t^2 + 1/6 * j * t^3
|
||||
return t * (v + t * (0.5 * a + 1.0 / 6.0 * j * t));
|
||||
}
|
||||
|
||||
|
||||
float SCurve::velocity(float t, float a, float j) {
|
||||
// a * t + 1/2 * j * t^2
|
||||
return t * (a + 0.5 * j * t);
|
||||
}
|
||||
|
||||
|
||||
float SCurve::acceleration(float t, float j) {return j * t;}
|
||||
66
src/avr/src/SCurve.h
Normal file
66
src/avr/src/SCurve.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
class SCurve {
|
||||
float maxV;
|
||||
float maxA;
|
||||
float maxJ;
|
||||
|
||||
float v;
|
||||
float a;
|
||||
float j;
|
||||
|
||||
public:
|
||||
SCurve(float maxV = 0, float maxA = 0, float maxJ = 0);
|
||||
|
||||
float getMaxVelocity() const {return maxV;}
|
||||
void setMaxVelocity(float v) {maxV = v;}
|
||||
float getMaxAcceleration() const {return maxA;}
|
||||
void setMaxAcceleration(float a) {maxA = a;}
|
||||
float getMaxJerk() const {return maxJ;}
|
||||
void setMaxJerk(float j) {maxJ = j;}
|
||||
|
||||
float getVelocity() const {return v;}
|
||||
float getAcceleration() const {return a;}
|
||||
float getJerk() const {return j;}
|
||||
|
||||
unsigned getPhase() const;
|
||||
float getStoppingDist() const;
|
||||
float next(float t, float targetV);
|
||||
|
||||
static float stoppingDist(float v, float a, float maxA, float maxJ);
|
||||
static float nextAccel(float t, float targetV, float v, float a, float maxA,
|
||||
float maxJ);
|
||||
static float distance(float t, float v, float a, float j);
|
||||
static float velocity(float t, float a, float j);
|
||||
static float acceleration(float t, float j);
|
||||
};
|
||||
90
src/avr/src/analog.c
Normal file
90
src/avr/src/analog.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "analog.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t pin;
|
||||
uint16_t value;
|
||||
} analog_port_t;
|
||||
|
||||
|
||||
analog_port_t ports[] = {
|
||||
{.pin = ANALOG_1_PIN},
|
||||
{.pin = ANALOG_2_PIN},
|
||||
};
|
||||
|
||||
|
||||
ISR(ADCA_CH0_vect) {ports[0].value = ADCA.CH0.RES;}
|
||||
ISR(ADCA_CH1_vect) {ports[1].value = ADCA.CH1.RES;}
|
||||
|
||||
|
||||
void analog_init() {
|
||||
// Channel 0
|
||||
ADCA.CH0.CTRL = ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;
|
||||
ADCA.CH0.MUXCTRL = ADC_CH_MUXPOS_PIN6_gc;
|
||||
ADCA.CH0.INTCTRL = ADC_CH_INTLVL_LO_gc;
|
||||
|
||||
// Channel 1
|
||||
ADCA.CH1.CTRL = ADC_CH_GAIN_1X_gc | ADC_CH_INPUTMODE_SINGLEENDED_gc;
|
||||
ADCA.CH1.MUXCTRL = ADC_CH_MUXPOS_PIN7_gc;
|
||||
ADCA.CH1.INTCTRL = ADC_CH_INTLVL_LO_gc;
|
||||
|
||||
// ADC
|
||||
ADCA.REFCTRL = ADC_REFSEL_INTVCC_gc; // 3.3V / 1.6 = 2.06V
|
||||
ADCA.PRESCALER = ADC_PRESCALER_DIV512_gc;
|
||||
ADCA.EVCTRL = ADC_SWEEP_01_gc;
|
||||
ADCA.CTRLA = ADC_FLUSH_bm | ADC_ENABLE_bm;
|
||||
}
|
||||
|
||||
|
||||
float analog_get(unsigned port) {
|
||||
if (1 < port) return 0;
|
||||
return ports[port].value * (1.0 / 0x1000);
|
||||
}
|
||||
|
||||
|
||||
void analog_rtc_callback() {
|
||||
static uint8_t count = 0;
|
||||
|
||||
// Every 1/4 sec
|
||||
if (++count == 250) {
|
||||
count = 0;
|
||||
ADCA.CTRLA |= ADC_CH0START_bm | ADC_CH1START_bm;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Var callbacks
|
||||
float get_analog_input(int port) {return analog_get(port);}
|
||||
33
src/avr/src/analog.h
Normal file
33
src/avr/src/analog.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
void analog_init();
|
||||
float analog_get(unsigned port);
|
||||
void analog_rtc_callback();
|
||||
124
src/avr/src/axis.c
Normal file
124
src/avr/src/axis.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "axis.h"
|
||||
#include "motor.h"
|
||||
#include "switch.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
int motor_map[AXES] = {-1, -1, -1, -1, -1, -1};
|
||||
|
||||
|
||||
typedef struct {
|
||||
float velocity_max; // max velocity in mm/min or deg/min
|
||||
float accel_max; // max acceleration in mm/min^2
|
||||
float jerk_max; // max jerk (Jm) in km/min^3
|
||||
} axis_t;
|
||||
|
||||
|
||||
axis_t axes[MOTORS] = {};
|
||||
|
||||
|
||||
bool axis_is_enabled(int axis) {
|
||||
int motor = axis_get_motor(axis);
|
||||
return motor != -1 && motor_is_enabled(motor) &&
|
||||
!fp_ZERO(axis_get_velocity_max(axis));
|
||||
}
|
||||
|
||||
|
||||
int axis_get_id(char axis) {
|
||||
const char *axes = "XYZABCUVW";
|
||||
const char *ptr = strchr(axes, toupper(axis));
|
||||
return ptr == 0 ? -1 : (ptr - axes);
|
||||
}
|
||||
|
||||
|
||||
int axis_get_motor(int axis) {return motor_map[axis];}
|
||||
|
||||
|
||||
bool axis_get_homed(int axis) {
|
||||
return axis_is_enabled(axis) ? motor_get_homed(axis_get_motor(axis)) : false;
|
||||
}
|
||||
|
||||
|
||||
float axis_get_soft_limit(int axis, bool min) {
|
||||
if (!axis_is_enabled(axis)) return min ? -INFINITY : INFINITY;
|
||||
return motor_get_soft_limit(axis_get_motor(axis), min);
|
||||
}
|
||||
|
||||
|
||||
// Map axes to first matching motor
|
||||
void axis_map_motors() {
|
||||
for (int axis = 0; axis < AXES; axis++)
|
||||
for (int motor = 0; motor < MOTORS; motor++)
|
||||
if (motor_get_axis(motor) == axis) {
|
||||
motor_map[axis] = motor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define AXIS_VAR_GET(NAME, TYPE) \
|
||||
TYPE get_##NAME(int axis) {return axes[axis].NAME;}
|
||||
|
||||
|
||||
#define AXIS_VAR_SET(NAME, TYPE) \
|
||||
void set_##NAME(int axis, TYPE value) {axes[axis].NAME = value;}
|
||||
|
||||
|
||||
/// Velocity is scaled by 1,000
|
||||
float axis_get_velocity_max(int axis) {
|
||||
int motor = axis_get_motor(axis);
|
||||
return motor == -1 ? 0 : axes[motor].velocity_max * VELOCITY_MULTIPLIER;
|
||||
}
|
||||
AXIS_VAR_GET(velocity_max, float)
|
||||
|
||||
|
||||
/// Acceleration is scaled by 1,000
|
||||
float axis_get_accel_max(int axis) {
|
||||
int motor = axis_get_motor(axis);
|
||||
return motor == -1 ? 0 : axes[motor].accel_max * ACCEL_MULTIPLIER;
|
||||
}
|
||||
AXIS_VAR_GET(accel_max, float)
|
||||
|
||||
|
||||
/// Jerk is scaled by 1,000,000
|
||||
float axis_get_jerk_max(int axis) {
|
||||
int motor = axis_get_motor(axis);
|
||||
return motor == -1 ? 0 : axes[motor].jerk_max * JERK_MULTIPLIER;
|
||||
}
|
||||
AXIS_VAR_GET(jerk_max, float)
|
||||
|
||||
|
||||
AXIS_VAR_SET(velocity_max, float)
|
||||
AXIS_VAR_SET(accel_max, float)
|
||||
AXIS_VAR_SET(jerk_max, float)
|
||||
50
src/avr/src/axis.h
Normal file
50
src/avr/src/axis.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
enum {
|
||||
AXIS_X, AXIS_Y, AXIS_Z,
|
||||
AXIS_A, AXIS_B, AXIS_C,
|
||||
};
|
||||
|
||||
|
||||
bool axis_is_enabled(int axis);
|
||||
int axis_get_id(char axis);
|
||||
int axis_get_motor(int axis);
|
||||
bool axis_get_homed(int axis);
|
||||
float axis_get_soft_limit(int axis, bool min);
|
||||
void axis_map_motors();
|
||||
|
||||
float axis_get_velocity_max(int axis);
|
||||
float axis_get_accel_max(int axis);
|
||||
float axis_get_jerk_max(int axis);
|
||||
151
src/avr/src/base64.c
Normal file
151
src/avr/src/base64.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
static const char *_b64_encode =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
static const int8_t _b64_decode[] = { // 43-122
|
||||
62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||
};
|
||||
|
||||
|
||||
static int8_t _decode(char c) {
|
||||
return (c < 43 || 122 < c) ? -1 : _b64_decode[c - 43];
|
||||
}
|
||||
|
||||
|
||||
static char _encode(uint8_t b) {return _b64_encode[b & 63];}
|
||||
|
||||
|
||||
static void _skip_space(const char **s, const char *end) {
|
||||
while (*s < end && isspace(**s)) (*s)++;
|
||||
}
|
||||
|
||||
|
||||
static char _next(const char **s, const char *end) {
|
||||
char c = *(*s)++;
|
||||
_skip_space(s, end);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
unsigned b64_encoded_length(unsigned len, bool pad) {
|
||||
unsigned elen = len / 3 * 4;
|
||||
|
||||
switch (len % 3) {
|
||||
case 1: elen += pad ? 4 : 2; break;
|
||||
case 2: elen += pad ? 4 : 3; break;
|
||||
}
|
||||
|
||||
return elen;
|
||||
}
|
||||
|
||||
|
||||
void b64_encode(const uint8_t *in, unsigned len, char *out, bool pad) {
|
||||
const uint8_t *end = in + len;
|
||||
int padding = 0;
|
||||
uint8_t a, b, c;
|
||||
|
||||
while (in < end) {
|
||||
a = *in++;
|
||||
|
||||
if (in < end) {
|
||||
b = *in++;
|
||||
|
||||
if (in < end) c = *in++;
|
||||
else {c = 0; padding = 1;}
|
||||
|
||||
} else {c = b = 0; padding = 2;}
|
||||
|
||||
*out++ = _encode(63 & (a >> 2));
|
||||
*out++ = _encode(63 & (a << 4 | b >> 4));
|
||||
|
||||
if (pad && padding == 2) *out++ = '=';
|
||||
else *out++ = _encode(63 & (b << 2 | c >> 6));
|
||||
|
||||
if (pad && padding) *out++ = '=';
|
||||
else *out++ = _encode(63 & c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool b64_decode(const char *in, unsigned len, uint8_t *out) {
|
||||
const char *end = in + len;
|
||||
|
||||
_skip_space(&in, end);
|
||||
|
||||
while (in < end) {
|
||||
int8_t w = _decode(_next(&in, end));
|
||||
int8_t x = in < end ? _decode(_next(&in, end)) : -2;
|
||||
int8_t y = in < end ? _decode(_next(&in, end)) : -2;
|
||||
int8_t z = in < end ? _decode(_next(&in, end)) : -2;
|
||||
|
||||
if (w == -2 || x == -2 || w == -1 || x == -1 || y == -1 || z == -1)
|
||||
return false;
|
||||
|
||||
*out++ = (uint8_t)(w << 2 | x >> 4);
|
||||
if (y != -2) {
|
||||
*out++ = (uint8_t)(x << 4 | y >> 2);
|
||||
if (z != -2) *out++ = (uint8_t)(y << 6 | z);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool b64_decode_float(const char *s, float *f) {
|
||||
union {
|
||||
float f;
|
||||
uint8_t b[4];
|
||||
} u;
|
||||
|
||||
if (!b64_decode(s, 6, u.b)) return false;
|
||||
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define XORSWAP(a, b) a ^= (b ^ (b ^= a)
|
||||
XORSWAP(u.b[0], u.b[3]);
|
||||
XORSWAP(u.b[1], u.b[2]);
|
||||
#endif
|
||||
|
||||
*f = u.f;
|
||||
|
||||
return true;
|
||||
}
|
||||
37
src/avr/src/base64.h
Normal file
37
src/avr/src/base64.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
unsigned b64_encoded_length(unsigned len, bool pad);
|
||||
void b64_encode(const uint8_t *in, unsigned len, char *out, bool pad);
|
||||
bool b64_decode(const char *in, unsigned len, uint8_t *out);
|
||||
bool b64_decode_float(const char *s, float *f);
|
||||
278
src/avr/src/command.c
Normal file
278
src/avr/src/command.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#include "usart.h"
|
||||
#include "hardware.h"
|
||||
#include "vars.h"
|
||||
#include "estop.h"
|
||||
#include "i2c.h"
|
||||
#include "config.h"
|
||||
#include "pgmspace.h"
|
||||
#include "state.h"
|
||||
#include "exec.h"
|
||||
#include "base64.h"
|
||||
#include "rtc.h"
|
||||
#include "stepper.h"
|
||||
#include "cpp_magic.h"
|
||||
|
||||
#include <util/atomic.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#define RING_BUF_NAME sync_q
|
||||
#define RING_BUF_TYPE uint8_t
|
||||
#define RING_BUF_INDEX_TYPE volatile uint16_t
|
||||
#define RING_BUF_SIZE SYNC_QUEUE_SIZE
|
||||
#define RING_BUF_ATOMIC_COPY 1
|
||||
#include "ringbuf.def"
|
||||
|
||||
|
||||
static struct {
|
||||
bool active;
|
||||
uint16_t id;
|
||||
uint32_t last_empty;
|
||||
volatile uint16_t count;
|
||||
float position[AXES];
|
||||
} cmd = {0,};
|
||||
|
||||
|
||||
// Define command callbacks
|
||||
#define CMD(CODE, NAME, SYNC) \
|
||||
stat_t command_##NAME(char *); \
|
||||
IF(SYNC)(unsigned command_##NAME##_size();) \
|
||||
IF(SYNC)(void command_##NAME##_exec(void *);)
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
|
||||
|
||||
// Name
|
||||
#define CMD(CODE, NAME, SYNC) \
|
||||
static const char command_##NAME##_name[] PROGMEM = #NAME;
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
|
||||
|
||||
static bool _is_synchronous(char code) {
|
||||
switch (code) {
|
||||
#define CMD(CODE, NAME, SYNC, ...) case COMMAND_##NAME: return SYNC;
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static stat_t _dispatch(char *s) {
|
||||
switch (*s) {
|
||||
#define CMD(CODE, NAME, SYNC, ...) \
|
||||
case COMMAND_##NAME: return command_##NAME(s);
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
}
|
||||
|
||||
return STAT_INVALID_COMMAND;
|
||||
}
|
||||
|
||||
|
||||
static unsigned _size(char code) {
|
||||
switch (code) {
|
||||
#define CMD(CODE, NAME, SYNC, ...) \
|
||||
IF(SYNC)(case COMMAND_##NAME: return command_##NAME##_size();)
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void _exec_cb(char code, uint8_t *data) {
|
||||
switch (code) {
|
||||
#define CMD(CODE, NAME, SYNC, ...) \
|
||||
IF(SYNC)(case COMMAND_##NAME: command_##NAME##_exec(data); break;)
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _i2c_cb(uint8_t *data, uint8_t length) {
|
||||
stat_t status = _dispatch((char *)data);
|
||||
if (status) STATUS_ERROR(status, "i2c: %s", data);
|
||||
}
|
||||
|
||||
|
||||
void command_init() {i2c_set_read_callback(_i2c_cb);}
|
||||
bool command_is_active() {return cmd.active;}
|
||||
unsigned command_get_count() {return cmd.count;}
|
||||
|
||||
|
||||
void command_print_json() {
|
||||
bool first = true;
|
||||
static const char fmt[] PROGMEM = "\"%c\":{\"name\":\"%" PRPSTR "\"}";
|
||||
|
||||
#define CMD(CODE, NAME, SYNC) \
|
||||
if (first) first = false; else putchar(','); \
|
||||
printf_P(fmt, CODE, command_##NAME##_name);
|
||||
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
}
|
||||
|
||||
|
||||
void command_flush_queue() {
|
||||
sync_q_init();
|
||||
cmd.count = 0;
|
||||
command_reset_position();
|
||||
}
|
||||
|
||||
|
||||
void command_push(char code, void *_data) {
|
||||
uint8_t *data = (uint8_t *)_data;
|
||||
unsigned size = _size(code);
|
||||
|
||||
if (!_is_synchronous(code)) estop_trigger(STAT_Q_INVALID_PUSH);
|
||||
if (sync_q_space() <= size) estop_trigger(STAT_Q_OVERRUN);
|
||||
|
||||
sync_q_push(code);
|
||||
for (unsigned i = 0; i < size; i++) sync_q_push(*data++);
|
||||
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) cmd.count++;
|
||||
}
|
||||
|
||||
|
||||
bool command_callback() {
|
||||
static char *block = 0;
|
||||
|
||||
if (!block) block = usart_readline();
|
||||
if (!block) return false; // No command
|
||||
|
||||
stat_t status = STAT_OK;
|
||||
|
||||
// Special processing for synchronous commands
|
||||
if (_is_synchronous(*block)) {
|
||||
if (estop_triggered()) status = STAT_MACHINE_ALARMED;
|
||||
else if (state_is_flushing()) status = STAT_NOP; // Flush command
|
||||
else if (state_is_resuming() || sync_q_space() <= _size(*block))
|
||||
return false; // Wait
|
||||
}
|
||||
|
||||
// Dispatch non-empty commands
|
||||
if (*block && status == STAT_OK) {
|
||||
status = _dispatch(block);
|
||||
if (status == STAT_OK) cmd.active = true; // Disables LCD booting message
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case STAT_OK: break;
|
||||
case STAT_NOP: break;
|
||||
case STAT_MACHINE_ALARMED: STATUS_WARNING(status, ""); break;
|
||||
default: STATUS_ERROR(status, "%s", block); break;
|
||||
}
|
||||
|
||||
block = 0; // Command consumed
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void command_set_axis_position(int axis, const float p) {
|
||||
cmd.position[axis] = p;
|
||||
}
|
||||
|
||||
|
||||
void command_set_position(const float position[AXES]) {
|
||||
memcpy(cmd.position, position, sizeof(cmd.position));
|
||||
}
|
||||
|
||||
|
||||
void command_get_position(float position[AXES]) {
|
||||
memcpy(position, cmd.position, sizeof(cmd.position));
|
||||
}
|
||||
|
||||
|
||||
void command_reset_position() {
|
||||
float position[AXES];
|
||||
exec_get_position(position);
|
||||
command_set_position(position);
|
||||
}
|
||||
|
||||
|
||||
char command_peek() {return (char)(cmd.count ? sync_q_peek() : 0);}
|
||||
|
||||
|
||||
uint8_t *command_next() {
|
||||
if (!cmd.count) return 0;
|
||||
cmd.count--;
|
||||
|
||||
if (sync_q_empty()) estop_trigger(STAT_Q_UNDERRUN);
|
||||
|
||||
static uint8_t data[INPUT_BUFFER_LEN];
|
||||
|
||||
data[0] = sync_q_next();
|
||||
|
||||
if (!_is_synchronous((char)data[0])) estop_trigger(STAT_INVALID_QCMD);
|
||||
|
||||
unsigned size = _size((char)data[0]);
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
data[i + 1] = sync_q_next();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// Returns true if command queued
|
||||
// Called by exec.c from low-level interrupt
|
||||
bool command_exec() {
|
||||
if (!cmd.count) {
|
||||
cmd.last_empty = rtc_get_time();
|
||||
state_idle();
|
||||
return false;
|
||||
}
|
||||
|
||||
// On restart wait a bit to give queue a chance to fill
|
||||
if (cmd.count < EXEC_FILL_TARGET &&
|
||||
!rtc_expired(cmd.last_empty + EXEC_DELAY)) return false;
|
||||
|
||||
uint8_t *data = command_next();
|
||||
state_running();
|
||||
|
||||
_exec_cb((char)*data, data + 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Var callbacks
|
||||
uint16_t get_id() {return cmd.id;}
|
||||
void set_id(uint16_t id) {cmd.id = id;}
|
||||
50
src/avr/src/command.def
Normal file
50
src/avr/src/command.def
Normal file
@@ -0,0 +1,50 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
//(CODE, NAME, SYNC)
|
||||
CMD('$', var, 0) // Set or get variable
|
||||
CMD('#', sync_var, 1) // Set variable synchronous
|
||||
CMD('s', seek, 1) // [switch][flags:active|error]
|
||||
CMD('a', set_axis, 1) // [axis][position] Set axis position
|
||||
CMD('l', line, 1) // [targetVel][maxJerk][axes][times]
|
||||
CMD('%', sync_speed, 1) // [offset][speed] Command synchronized speed
|
||||
CMD('p', speed, 1) // [speed] Spindle speed
|
||||
CMD('I', input, 1) // [a|d][port][mode][timeout] Read input
|
||||
CMD('d', dwell, 1) // [seconds]
|
||||
CMD('P', pause, 1) // [type] Pause control
|
||||
CMD('S', stop, 0) // Stop move, spindle and load outputs
|
||||
CMD('U', unpause, 0) // Unpause
|
||||
CMD('j', jog, 0) // [axes]
|
||||
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
|
||||
CMD('h', help, 0) // Print this help screen
|
||||
58
src/avr/src/command.h
Normal file
58
src/avr/src/command.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
#include "status.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Commands
|
||||
typedef enum {
|
||||
#define CMD(CODE, NAME, ...) COMMAND_##NAME = CODE,
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
} command_t;
|
||||
|
||||
|
||||
void command_init();
|
||||
bool command_is_active();
|
||||
unsigned command_get_count();
|
||||
void command_print_json();
|
||||
void command_flush_queue();
|
||||
void command_push(char code, void *data);
|
||||
bool command_callback();
|
||||
void command_set_axis_position(int axis, const float p);
|
||||
void command_set_position(const float position[AXES]);
|
||||
void command_get_position(float position[AXES]);
|
||||
void command_reset_position();
|
||||
char command_peek();
|
||||
uint8_t *command_next();
|
||||
bool command_exec();
|
||||
11
src/avr/src/command.json.in
Normal file
11
src/avr/src/command.json.in
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "cpp_magic.h"
|
||||
{
|
||||
#define CMD(CODE, NAME, SYNC) \
|
||||
#NAME: { \
|
||||
"code": CODE, \
|
||||
"sync": IF_ELSE(SYNC)(true, false) \
|
||||
},
|
||||
#include "command.def"
|
||||
#undef CMD
|
||||
"_": {}
|
||||
}
|
||||
83
src/avr/src/commands.c
Normal file
83
src/avr/src/commands.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "stepper.h"
|
||||
#include "command.h"
|
||||
#include "vars.h"
|
||||
#include "base64.h"
|
||||
#include "hardware.h"
|
||||
#include "report.h"
|
||||
#include "exec.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
stat_t command_dwell(char *cmd) {
|
||||
float seconds;
|
||||
if (!b64_decode_float(cmd + 1, &seconds)) return STAT_BAD_FLOAT;
|
||||
command_push(*cmd, &seconds);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
static stat_t _dwell_exec() {
|
||||
exec_set_cb(0); // Immediately clear the callback
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
unsigned command_dwell_size() {return sizeof(float);}
|
||||
|
||||
|
||||
void command_dwell_exec(void *seconds) {
|
||||
st_prep_dwell(*(float *)seconds);
|
||||
exec_set_cb(_dwell_exec); // Command must set an exec callback
|
||||
}
|
||||
|
||||
|
||||
stat_t command_help(char *cmd) {
|
||||
printf_P(PSTR("\n{\"commands\":{"));
|
||||
command_print_json();
|
||||
printf_P(PSTR("},\"variables\":{"));
|
||||
vars_print_json();
|
||||
printf_P(PSTR("}}\n"));
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
stat_t command_reboot(char *cmd) {
|
||||
hw_request_hard_reset();
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
stat_t command_dump(char *cmd) {
|
||||
report_request_full();
|
||||
return STAT_OK;
|
||||
}
|
||||
222
src/avr/src/config.h
Normal file
222
src/avr/src/config.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pins.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
|
||||
// Pins
|
||||
enum {
|
||||
STALL_0_PIN = PIN_ID(PORT_A, 0),
|
||||
STALL_1_PIN,
|
||||
STALL_2_PIN,
|
||||
STALL_3_PIN,
|
||||
TOOL_DIR_PIN,
|
||||
TOOL_ENABLE_PIN,
|
||||
ANALOG_1_PIN,
|
||||
ANALOG_2_PIN,
|
||||
|
||||
MIN_0_PIN = PIN_ID(PORT_B, 0),
|
||||
MAX_0_PIN,
|
||||
MIN_3_PIN,
|
||||
MAX_3_PIN,
|
||||
MIN_1_PIN,
|
||||
MAX_1_PIN,
|
||||
MIN_2_PIN,
|
||||
MAX_2_PIN,
|
||||
|
||||
SDA_PIN = PIN_ID(PORT_C, 0),
|
||||
SCL_PIN,
|
||||
SERIAL_RX_PIN,
|
||||
SERIAL_TX_PIN,
|
||||
SERIAL_CTS_PIN,
|
||||
SPI_CLK_PIN,
|
||||
SPI_MISO_PIN,
|
||||
SPI_MOSI_PIN,
|
||||
|
||||
STEP_0_PIN = PIN_ID(PORT_D, 0),
|
||||
SPI_CS_0_PIN,
|
||||
SPI_CS_3_PIN,
|
||||
SPI_CS_2_PIN,
|
||||
PWM_PIN,
|
||||
SWITCH_2_PIN,
|
||||
RS485_RO_PIN,
|
||||
RS485_DI_PIN,
|
||||
|
||||
STEP_1_PIN = PIN_ID(PORT_E, 0),
|
||||
SPI_CS_1_PIN,
|
||||
DIR_0_PIN,
|
||||
DIR_1_PIN,
|
||||
STEP_3_PIN,
|
||||
SWITCH_1_PIN,
|
||||
DIR_2_PIN,
|
||||
DIR_3_PIN,
|
||||
|
||||
STEP_2_PIN = PIN_ID(PORT_F, 0),
|
||||
RS485_RW_PIN,
|
||||
FAULT_PIN,
|
||||
ESTOP_PIN,
|
||||
MOTOR_FAULT_PIN,
|
||||
MOTOR_ENABLE_PIN,
|
||||
TEST_PIN,
|
||||
PROBE_PIN,
|
||||
};
|
||||
|
||||
#define SPI_SS_PIN SERIAL_CTS_PIN // Needed for SPI configuration
|
||||
|
||||
|
||||
#define AXES 6 // number of axes
|
||||
#define MOTORS 4 // number of motors on the board
|
||||
#define OUTS 6 // number of supported pin outputs
|
||||
#define ANALOG 2 // number of supported analog inputs
|
||||
#define VFDREG 32 // number of supported VFD modbus registers
|
||||
|
||||
// Switch settings. See switch.c
|
||||
#define SWITCH_DEBOUNCE 5 // ms, default value
|
||||
#define SWITCH_LOCKOUT 250 // ms, default value
|
||||
#define SWITCH_MAX_DEBOUNCE 5000 // ms
|
||||
#define SWITCH_MAX_LOCKOUT 60000 // ms
|
||||
|
||||
|
||||
// Motor ISRs
|
||||
#define STALL_ISR_vect PORTA_INT1_vect
|
||||
#define FAULT_ISR_vect PORTF_INT1_vect
|
||||
|
||||
|
||||
/* Interrupt usage:
|
||||
*
|
||||
* HI Step timers stepper.c
|
||||
* HI Serial RX usart.c
|
||||
* MED Serial TX usart.c (* see note)
|
||||
* MED Modbus serial interrupts modbus.c
|
||||
* LO Segment execution SW interrupt stepper.c
|
||||
* LO I2C Slave i2c.c
|
||||
* LO Real-time clock interrupt rtc.c
|
||||
* LO DRV8711 SPI drv8711.c
|
||||
* LO A2D interrupts analog.c
|
||||
*
|
||||
* (*) The TX cannot run at LO level or exception reports and other prints
|
||||
* called from a LO interrupt (as in prep_line()) will kill the system
|
||||
* in a permanent loop call in usart_putc() (usart.c).
|
||||
*/
|
||||
|
||||
// Timer assignments
|
||||
// NOTE, TCC1 is unused
|
||||
#define TIMER_STEP TCC0 // Step timer (see stepper.h)
|
||||
#define TIMER_PWM TCD1 // PWM timer (see pwm.c)
|
||||
|
||||
|
||||
// Timer setup for stepper and dwells
|
||||
#define STEP_TIMER_DIV 8
|
||||
#define STEP_TIMER_FREQ (F_CPU / STEP_TIMER_DIV)
|
||||
#define STEP_TIMER_POLL ((uint16_t)(STEP_TIMER_FREQ * 0.001)) // 1ms
|
||||
#define STEP_TIMER_ISR TCC0_OVF_vect
|
||||
#define STEP_LOW_LEVEL_ISR ADCB_CH0_vect
|
||||
#define STEP_PULSE_WIDTH (F_CPU * 0.000002) // 2uS w/ clk/1
|
||||
#define SEGMENT_MS 4
|
||||
#define SEGMENT_TIME (SEGMENT_MS / 60000.0) // mins
|
||||
|
||||
|
||||
// DRV8711 settings
|
||||
// NOTE, PWM frequency = 1 / (2 * DTIME + TBLANK + TOFF)
|
||||
// We have PWM frequency = 1 / (2 * 850nS + 1uS + 6.5uS) ~= 110kHz
|
||||
#define DRV8711_OFF 12
|
||||
#define DRV8711_BLANK (0x32 | DRV8711_BLANK_ABT_bm)
|
||||
#define DRV8711_DECAY (DRV8711_DECAY_DECMOD_MIXED | 16)
|
||||
|
||||
#define DRV8711_DRIVE (DRV8711_DRIVE_IDRIVEP_50 | \
|
||||
DRV8711_DRIVE_IDRIVEN_100 | \
|
||||
DRV8711_DRIVE_TDRIVEP_500 | \
|
||||
DRV8711_DRIVE_TDRIVEN_500 | \
|
||||
DRV8711_DRIVE_OCPDEG_1 | \
|
||||
DRV8711_DRIVE_OCPTH_500)
|
||||
#define DRV8711_TORQUE DRV8711_TORQUE_SMPLTH_200
|
||||
// NOTE, Datasheet suggests 850ns DTIME with the optional gate resistor
|
||||
// installed. See page 30 section 8.1.2 of DRV8711 datasheet.
|
||||
#define DRV8711_CTRL (DRV8711_CTRL_ISGAIN_5 | \
|
||||
DRV8711_CTRL_DTIME_850)
|
||||
|
||||
|
||||
// RS485 settings
|
||||
#define RS485_PORT USARTD1
|
||||
#define RS485_DRE_vect USARTD1_DRE_vect
|
||||
#define RS485_TXC_vect USARTD1_TXC_vect
|
||||
#define RS485_RXC_vect USARTD1_RXC_vect
|
||||
|
||||
|
||||
// Modbus settings
|
||||
#define MODBUS_TIMEOUT 100 // ms. response timeout
|
||||
#define MODBUS_RETRIES 4 // Number of retries before failure
|
||||
#define MODBUS_BUF_SIZE 18 // Max bytes in rx/tx buffers
|
||||
#define VFD_QUERY_DELAY 100 // ms
|
||||
|
||||
|
||||
// Serial settings
|
||||
#define SERIAL_BAUD USART_BAUD_230400 // 115200
|
||||
#define SERIAL_PORT USARTC0
|
||||
#define SERIAL_DRE_vect USARTC0_DRE_vect
|
||||
#define SERIAL_RXC_vect USARTC0_RXC_vect
|
||||
#define SERIAL_CTS_THRESH 4
|
||||
|
||||
|
||||
// PWM settings
|
||||
#define POWER_MAX_UPDATES SEGMENT_MS
|
||||
|
||||
// Input
|
||||
#define INPUT_BUFFER_LEN 128 // text buffer size (255 max)
|
||||
|
||||
|
||||
// Report
|
||||
#define REPORT_RATE 250 // ms
|
||||
|
||||
|
||||
// I2C
|
||||
#define I2C_DEV TWIC
|
||||
#define I2C_ISR TWIC_TWIS_vect
|
||||
#define I2C_ADDR 0x2b
|
||||
#define I2C_MAX_DATA 8
|
||||
|
||||
|
||||
// Motor
|
||||
#define MOTOR_IDLE_TIMEOUT 0.25 // secs, motor off after this time
|
||||
#define MIN_STEP_CORRECTION 2
|
||||
|
||||
#define MIN_VELOCITY 10 // mm/min
|
||||
#define CURRENT_SENSE_RESISTOR 0.05 // ohms
|
||||
#define CURRENT_SENSE_REF 2.75 // volts
|
||||
#define MAX_CURRENT 6 // amps
|
||||
#define MAX_IDLE_CURRENT 2 // amps
|
||||
#define VELOCITY_MULTIPLIER 1000.0
|
||||
#define ACCEL_MULTIPLIER 1000000.0
|
||||
#define JERK_MULTIPLIER 1000000.0
|
||||
#define SYNC_QUEUE_SIZE 4096
|
||||
#define EXEC_FILL_TARGET 8
|
||||
#define EXEC_DELAY 250 // ms
|
||||
#define JOG_STOPPING_UNDERSHOOT 1 // % of stopping distance
|
||||
507
src/avr/src/cpp_magic.h
Normal file
507
src/avr/src/cpp_magic.h
Normal file
@@ -0,0 +1,507 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
/* This header file contains a library of advanced C Pre-Processor (CPP) macros
|
||||
* which implement various useful functions, such as iteration, in the
|
||||
* pre-processor.
|
||||
*
|
||||
* Though the file name (quite validly) labels this as magic, there should be
|
||||
* enough documentation in the comments for a reader only casually familiar
|
||||
* with the CPP to be able to understand how everything works.
|
||||
*
|
||||
* The majority of the magic tricks used in this file are based on those
|
||||
* described by pfultz2 in his "Cloak" library:
|
||||
*
|
||||
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
|
||||
*
|
||||
* Major differences are a greater level of detailed explanation in this
|
||||
* implementation and also a refusal to include any macros which require a O(N)
|
||||
* macro definitions to handle O(N) arguments (with the exception of DEFERn).
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Force the pre-processor to expand the macro a large number of times.
|
||||
* Usage:
|
||||
*
|
||||
* EVAL(expression)
|
||||
*
|
||||
* This is useful when you have a macro which evaluates to a valid
|
||||
* macro expression which is not subsequently expanded in the same
|
||||
* pass. A contrived, but easy to understand, example of such a macro
|
||||
* follows. Note that though this example is contrived, this behaviour
|
||||
* is abused to implement bounded recursion in macros such as FOR.
|
||||
*
|
||||
* #define A(x) x+1
|
||||
* #define EMPTY
|
||||
* #define NOT_QUITE_RIGHT(x) A EMPTY (x)
|
||||
* NOT_QUITE_RIGHT(999)
|
||||
*
|
||||
* Here's what happens inside the C preprocessor:
|
||||
*
|
||||
* 1. It sees a macro "NOT_QUITE_RIGHT" and performs a single macro
|
||||
* expansion pass on its arguments. Since the argument is "999" and
|
||||
* this isn't a macro, this is a boring step resulting in no
|
||||
* change.
|
||||
*
|
||||
* 2. The NOT_QUITE_RIGHT macro is substituted for its definition
|
||||
* giving "A EMPTY() (x)".
|
||||
*
|
||||
* 3. The expander moves from left-to-right trying to expand the
|
||||
* macro: The first token, A, cannot be expanded since there are no
|
||||
* brackets immediately following it. The second token EMPTY(),
|
||||
* however, can be expanded (recursively in this manner) and is
|
||||
* replaced with "".
|
||||
*
|
||||
* 4. Expansion continues from the start of the substituted test
|
||||
* (which in this case is just empty), and sees "(999)" but since
|
||||
* no macro name is present, nothing is done. This results in a
|
||||
* final expansion of "A (999)".
|
||||
*
|
||||
* Unfortunately, this doesn't quite meet expectations since you may
|
||||
* expect that "A (999)" would have been expanded into
|
||||
* "999+1". Unfortunately this requires a second expansion pass but
|
||||
* luckily we can force the macro processor to make more passes by
|
||||
* abusing the first step of macro expansion: the preprocessor expands
|
||||
* arguments in their own pass. If we define a macro which does
|
||||
* nothing except produce its arguments e.g.:
|
||||
*
|
||||
* #define PASS_THROUGH(...) __VA_ARGS__
|
||||
*
|
||||
* We can now do "PASS_THROUGH(NOT_QUITE_RIGHT(999))" causing
|
||||
* "NOT_QUITE_RIGHT" to be expanded to "A (999)", as described above,
|
||||
* when the arguments are expanded. Now when the body of PASS_THROUGH
|
||||
* is expanded, "A (999)" gets expanded to "999+1".
|
||||
*
|
||||
* The EVAL defined below is essentially equivalent to a large nesting
|
||||
* of "PASS_THROUGH(PASS_THROUGH(PASS_THROUGH(..." which results in
|
||||
* the preprocessor making a large number of expansion passes over the
|
||||
* given expression.
|
||||
*/
|
||||
#define EVAL(...) EVAL1024(__VA_ARGS__)
|
||||
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
|
||||
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
|
||||
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
|
||||
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
|
||||
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
|
||||
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
|
||||
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
|
||||
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
|
||||
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
|
||||
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
|
||||
#define EVAL1(...) __VA_ARGS__
|
||||
|
||||
|
||||
// Macros which expand to common values
|
||||
#define PASS(...) __VA_ARGS__
|
||||
#define EMPTY()
|
||||
#define COMMA() ,
|
||||
#define SEMI() ;
|
||||
#define PLUS() +
|
||||
#define ZERO() 0
|
||||
#define ONE() 1
|
||||
|
||||
/**
|
||||
* Causes a function-style macro to require an additional pass to be expanded.
|
||||
*
|
||||
* This is useful, for example, when trying to implement recursion since the
|
||||
* recursive step must not be expanded in a single pass as the pre-processor
|
||||
* will catch it and prevent it.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* DEFER1(IN_NEXT_PASS)(args, to, the, macro)
|
||||
*
|
||||
* How it works:
|
||||
*
|
||||
* 1. When DEFER1 is expanded, first its arguments are expanded which are
|
||||
* simply IN_NEXT_PASS. Since this is a function-style macro and it has no
|
||||
* arguments, nothing will happen.
|
||||
* 2. The body of DEFER1 will now be expanded resulting in EMPTY() being
|
||||
* deleted. This results in "IN_NEXT_PASS (args, to, the macro)". Note that
|
||||
* since the macro expander has already passed IN_NEXT_PASS by the time it
|
||||
* expands EMPTY() and so it won't spot that the brackets which remain can be
|
||||
* applied to IN_NEXT_PASS.
|
||||
* 3. At this point the macro expansion completes. If one more pass is made,
|
||||
* IN_NEXT_PASS(args, to, the, macro) will be expanded as desired.
|
||||
*/
|
||||
#define DEFER1(id) id EMPTY()
|
||||
|
||||
/**
|
||||
* As with DEFER1 except here n additional passes are required for DEFERn.
|
||||
*
|
||||
* The mechanism is analogous.
|
||||
*
|
||||
* Note that there doesn't appear to be a way of combining DEFERn macros in
|
||||
* order to achieve exponentially increasing defers e.g. as is done by EVAL.
|
||||
*/
|
||||
#define DEFER2(id) id EMPTY EMPTY()()
|
||||
#define DEFER3(id) id EMPTY EMPTY EMPTY()()()
|
||||
#define DEFER4(id) id EMPTY EMPTY EMPTY EMPTY()()()()
|
||||
#define DEFER5(id) id EMPTY EMPTY EMPTY EMPTY EMPTY()()()()()
|
||||
#define DEFER6(id) id EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY()()()()()()
|
||||
#define DEFER7(id) id EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY()()()()()()()
|
||||
#define DEFER8(id) \
|
||||
id EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY EMPTY()()()()()()()()
|
||||
|
||||
|
||||
/**
|
||||
* Indirection around the standard ## concatenation operator. This simply
|
||||
* ensures that the arguments are expanded (once) before concatenation.
|
||||
*/
|
||||
#define CAT(a, ...) a ## __VA_ARGS__
|
||||
#define CAT3(a, b, ...) a ## b ## __VA_ARGS__
|
||||
|
||||
|
||||
/**
|
||||
* Get the first argument and ignore the rest.
|
||||
*/
|
||||
#define FIRST(a, ...) a
|
||||
|
||||
/**
|
||||
* Get the second argument and ignore the rest.
|
||||
*/
|
||||
#define SECOND(a, b, ...) b
|
||||
|
||||
/**
|
||||
* Expects a single input (not containing commas). Returns 1 if the input is
|
||||
* PROBE() and otherwise returns 0.
|
||||
*
|
||||
* This can be useful as the basis of a NOT function.
|
||||
*
|
||||
* This macro abuses the fact that PROBE() contains a comma while other valid
|
||||
* inputs must not.
|
||||
*/
|
||||
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
|
||||
#define PROBE() ~, 1
|
||||
|
||||
|
||||
/**
|
||||
* Logical negation. 0 is defined as false and everything else as true.
|
||||
*
|
||||
* When 0, _NOT_0 will be found which evaluates to the PROBE. When 1
|
||||
* (or any other value) is given, an appropriately named macro won't
|
||||
* be found and the concatenated string will be produced. IS_PROBE
|
||||
* then simply checks to see if the PROBE was returned, cleanly
|
||||
* converting the argument into a 1 or 0.
|
||||
*/
|
||||
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
|
||||
#define _NOT_0 PROBE()
|
||||
|
||||
/**
|
||||
* Macro version of C's famous "cast to bool" operator (i.e. !!) which takes
|
||||
* anything and casts it to 0 if it is 0 and 1 otherwise.
|
||||
*/
|
||||
#define BOOL(x) NOT(NOT(x))
|
||||
|
||||
/**
|
||||
* Logical OR. Simply performs a lookup.
|
||||
*/
|
||||
#define OR(a,b) CAT3(_OR_, a, b)
|
||||
#define _OR_00 0
|
||||
#define _OR_01 1
|
||||
#define _OR_10 1
|
||||
#define _OR_11 1
|
||||
|
||||
/**
|
||||
* Logical AND. Simply performs a lookup.
|
||||
*/
|
||||
#define AND(a,b) CAT3(_AND_, a, b)
|
||||
#define _AND_00 0
|
||||
#define _AND_01 0
|
||||
#define _AND_10 0
|
||||
#define _AND_11 1
|
||||
|
||||
|
||||
/**
|
||||
* Macro if statement. Usage:
|
||||
*
|
||||
* IF(c)(expansion when true)
|
||||
*
|
||||
* Here's how:
|
||||
*
|
||||
* 1. The preprocessor expands the arguments to _IF casting the condition to '0'
|
||||
* or '1'.
|
||||
* 2. The casted condition is concatencated with _IF_ giving _IF_0 or _IF_1.
|
||||
* 3. The _IF_0 and _IF_1 macros either returns the argument or doesn't (e.g.
|
||||
* they implement the "choice selection" part of the macro).
|
||||
* 4. Note that the "true" clause is in the extra set of brackets; thus these
|
||||
* become the arguments to _IF_0 or _IF_1 and thus a selection is made!
|
||||
*/
|
||||
#define IF(c) _IF(BOOL(c))
|
||||
#define _IF(c) CAT(_IF_,c)
|
||||
#define _IF_0(...)
|
||||
#define _IF_1(...) __VA_ARGS__
|
||||
|
||||
/**
|
||||
* Macro if/else statement. Usage:
|
||||
*
|
||||
* IF_ELSE(c)( \
|
||||
* expansion when true, \
|
||||
* expansion when false \
|
||||
* )
|
||||
*
|
||||
* The mechanism is analogous to IF.
|
||||
*/
|
||||
#define IF_ELSE(c) _IF_ELSE(BOOL(c))
|
||||
#define _IF_ELSE(c) CAT(_IF_ELSE_,c)
|
||||
#define _IF_ELSE_0(t,f) f
|
||||
#define _IF_ELSE_1(t,f) t
|
||||
|
||||
|
||||
/**
|
||||
* Macro which checks if it has any arguments. Returns '0' if there are no
|
||||
* arguments, '1' otherwise.
|
||||
*
|
||||
* Limitation: HAS_ARGS(,1,2,3) returns 0 -- this check essentially only checks
|
||||
* that the first argument exists.
|
||||
*
|
||||
* This macro works as follows:
|
||||
*
|
||||
* 1. _END_OF_ARGUMENTS_ is concatenated with the first argument.
|
||||
* 2. If the first argument is not present then only "_END_OF_ARGUMENTS_" will
|
||||
* remain, otherwise "_END_OF_ARGUMENTS something_here" will remain.
|
||||
* 3. In the former case, the _END_OF_ARGUMENTS_() macro expands to a
|
||||
* 0 when it is expanded. In the latter, a non-zero result remains.
|
||||
* 4. BOOL is used to force non-zero results into 1 giving the clean 0 or 1
|
||||
* output required.
|
||||
*/
|
||||
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
|
||||
#define _END_OF_ARGUMENTS_() 0
|
||||
|
||||
|
||||
/**
|
||||
* Macro map/list comprehension. Usage:
|
||||
*
|
||||
* MAP(op, sep, ...)
|
||||
*
|
||||
* Produces a 'sep()'-separated list of the result of op(arg) for each arg.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* #define MAKE_HAPPY(x) happy_##x
|
||||
* #define COMMA() ,
|
||||
* MAP(MAKE_HAPPY, COMMA, 1,2,3)
|
||||
*
|
||||
* Which expands to:
|
||||
*
|
||||
* happy_1 , happy_2 , happy_3
|
||||
*
|
||||
* How it works:
|
||||
*
|
||||
* 1. The MAP macro simply maps the inner MAP_INNER function in an EVAL which
|
||||
* forces it to be expanded a large number of times, thus enabling many steps
|
||||
* of iteration (see step 6).
|
||||
* 2. The MAP_INNER macro is substituted for its body.
|
||||
* 3. In the body, op(cur_val) is substituted giving the value for this
|
||||
* iteration.
|
||||
* 4. The IF macro expands according to whether further iterations are required.
|
||||
* This expansion either produces _IF_0 or _IF_1.
|
||||
* 5. Since the IF is followed by a set of brackets containing the "if true"
|
||||
* clause, these become the argument to _IF_0 or _IF_1. At this point, the
|
||||
* macro in the brackets will be expanded giving the separator followed by
|
||||
* _MAP_INNER EMPTY()()(op, sep, __VA_ARGS__).
|
||||
* 5. If the IF was not taken, the above will simply be discarded and everything
|
||||
* stops. If the IF is taken, The expression is then processed a second time
|
||||
* yielding "_MAP_INNER()(op, sep, __VA_ARGS__)". Note that this call looks
|
||||
* very similar to the essentially the same as the original call except the
|
||||
* first argument has been dropped.
|
||||
* 6. At this point expansion of MAP_INNER will terminate. However, since we can
|
||||
* force more rounds of expansion using EVAL1. In the argument-expansion pass
|
||||
* of the EVAL1, _MAP_INNER() is expanded to MAP_INNER which is then expanded
|
||||
* using the arguments which follow it as in step 2-5. This is followed by a
|
||||
* second expansion pass as the substitution of EVAL1() is expanded executing
|
||||
* 2-5 a second time. This results in up to two iterations occurring. Using
|
||||
* many nested EVAL1 macros, i.e. the very-deeply-nested EVAL macro, will in
|
||||
* this manner produce further iterations, hence the outer MAP macro doing
|
||||
* this for us.
|
||||
*
|
||||
* Important tricks used:
|
||||
*
|
||||
* * If we directly produce "MAP_INNER" in an expansion of MAP_INNER,
|
||||
* a special case in the preprocessor will prevent it being expanded
|
||||
* in the future, even if we EVAL. As a result, the MAP_INNER macro
|
||||
* carefully only expands to something containing "_MAP_INNER()"
|
||||
* which requires a further expansion step to invoke MAP_INNER and
|
||||
* thus implementing the recursion.
|
||||
*
|
||||
* * To prevent _MAP_INNER being expanded within the macro we must
|
||||
* first defer its expansion during its initial pass as an argument
|
||||
* to _IF_0 or _IF_1. We must then defer its expansion a second time
|
||||
* as part of the body of the _IF_0. As a result hence the DEFER2.
|
||||
*
|
||||
* * _MAP_INNER seemingly gets away with producing itself because it
|
||||
* actually only produces MAP_INNER. It just happens that when
|
||||
* _MAP_INNER() is expanded in this case it is followed by some
|
||||
* arguments which get consumed by MAP_INNER and produce a
|
||||
* _MAP_INNER. As such, the macro expander never marks _MAP_INNER
|
||||
* as expanding to itself and thus it will still be expanded in
|
||||
* future productions of itself.
|
||||
*/
|
||||
#define MAP(...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(MAP_INNER(__VA_ARGS__)))
|
||||
#define MAP_INNER(op,sep,cur_val, ...) \
|
||||
op(cur_val) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))( \
|
||||
sep() DEFER2(_MAP_INNER)()(op, sep, ##__VA_ARGS__) \
|
||||
)
|
||||
#define _MAP_INNER() MAP_INNER
|
||||
|
||||
|
||||
/**
|
||||
* This is a variant of the MAP macro which also includes as an argument to the
|
||||
* operation a valid C variable name which is different for each iteration.
|
||||
*
|
||||
* Usage:
|
||||
* MAP_WITH_ID(op, sep, ...)
|
||||
*
|
||||
* Where op is a macro op(val, id) which takes a list value and an ID. This ID
|
||||
* will simply be a unary number using the digit "I", that is, I, II, III, IIII,
|
||||
* and so on.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define MAKE_STATIC_VAR(type, name) static type name;
|
||||
* MAP_WITH_ID(MAKE_STATIC_VAR, EMPTY, int, int, int, bool, char)
|
||||
*
|
||||
* Which expands to:
|
||||
*
|
||||
* static int I; static int II; static int III; static bool IIII;
|
||||
* static char IIIII;
|
||||
*
|
||||
* The mechanism is analogous to the MAP macro.
|
||||
*/
|
||||
#define MAP_WITH_ID(op,sep,...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(MAP_WITH_ID_INNER(op,sep,I, ##__VA_ARGS__)))
|
||||
#define MAP_WITH_ID_INNER(op,sep,id,cur_val, ...) \
|
||||
op(cur_val,id) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))( \
|
||||
sep() DEFER2(_MAP_WITH_ID_INNER)()(op, sep, CAT(id,I), ##__VA_ARGS__) \
|
||||
)
|
||||
#define _MAP_WITH_ID_INNER() MAP_WITH_ID_INNER
|
||||
|
||||
|
||||
/**
|
||||
* This is a variant of the MAP macro which iterates over pairs rather than
|
||||
* singletons.
|
||||
*
|
||||
* Usage:
|
||||
* MAP_PAIRS(op, sep, ...)
|
||||
*
|
||||
* Where op is a macro op(val_1, val_2) which takes two list values.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define MAKE_STATIC_VAR(type, name) static type name;
|
||||
* MAP_PAIRS(MAKE_STATIC_VAR, EMPTY, char, my_char, int, my_int)
|
||||
*
|
||||
* Which expands to:
|
||||
*
|
||||
* static char my_char; static int my_int;
|
||||
*
|
||||
* The mechanism is analogous to the MAP macro.
|
||||
*/
|
||||
#define MAP_PAIRS(op,sep,...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(MAP_PAIRS_INNER(op,sep,__VA_ARGS__)))
|
||||
#define MAP_PAIRS_INNER(op,sep,cur_val_1, cur_val_2, ...) \
|
||||
op(cur_val_1,cur_val_2) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))( \
|
||||
sep() DEFER2(_MAP_PAIRS_INNER)()(op, sep, __VA_ARGS__) \
|
||||
)
|
||||
#define _MAP_PAIRS_INNER() MAP_PAIRS_INNER
|
||||
|
||||
/**
|
||||
* This is a variant of the MAP macro which iterates over a two-element sliding
|
||||
* window.
|
||||
*
|
||||
* Usage:
|
||||
* MAP_SLIDE(op, last_op, sep, ...)
|
||||
*
|
||||
* Where op is a macro op(val_1, val_2) which takes the two list values
|
||||
* currently in the window. last_op is a macro taking a single value which is
|
||||
* called for the last argument.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* #define SIMON_SAYS_OP(simon, next) IF(NOT(simon()))(next)
|
||||
* #define SIMON_SAYS_LAST_OP(val) last_but_not_least_##val
|
||||
* #define SIMON_SAYS() 0
|
||||
*
|
||||
* MAP_SLIDE(SIMON_SAYS_OP, SIMON_SAYS_LAST_OP, EMPTY, wiggle, SIMON_SAYS,
|
||||
* dance, move, SIMON_SAYS, boogie, stop)
|
||||
*
|
||||
* Which expands to:
|
||||
*
|
||||
* dance boogie last_but_not_least_stop
|
||||
*
|
||||
* The mechanism is analogous to the MAP macro.
|
||||
*/
|
||||
#define MAP_SLIDE(op,last_op,sep,...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(MAP_SLIDE_INNER(op,last_op,sep,__VA_ARGS__)))
|
||||
#define MAP_SLIDE_INNER(op,last_op,sep,cur_val, ...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(op(cur_val,FIRST(__VA_ARGS__))) \
|
||||
IF(NOT(HAS_ARGS(__VA_ARGS__)))(last_op(cur_val)) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))( \
|
||||
sep() DEFER2(_MAP_SLIDE_INNER)()(op, last_op, sep, __VA_ARGS__) \
|
||||
)
|
||||
#define _MAP_SLIDE_INNER() MAP_SLIDE_INNER
|
||||
|
||||
|
||||
/**
|
||||
* Strip any excess commas from a set of arguments.
|
||||
*/
|
||||
#define REMOVE_TRAILING_COMMAS(...) \
|
||||
MAP(PASS, COMMA, __VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates an array of macros passing 1 argument
|
||||
*/
|
||||
#define EMAP1(...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(EMAP1_INNER(__VA_ARGS__)))
|
||||
|
||||
#define EMAP1_INNER(ARG1, OP, ...) \
|
||||
_##OP(ARG1) \
|
||||
IF(HAS_ARGS(__VA_ARGS__)) \
|
||||
(DEFER2(_EMAP1_INNER)()(ARG1, ##__VA_ARGS__))
|
||||
|
||||
#define _EMAP1_INNER() EMAP1_INNER
|
||||
|
||||
|
||||
/**
|
||||
* Evaluates an array of macros passing 2 arguments
|
||||
*/
|
||||
#define EMAP2(...) \
|
||||
IF(HAS_ARGS(__VA_ARGS__))(EVAL(EMAP2_INNER(__VA_ARGS__)))
|
||||
|
||||
#define EMAP2_INNER(ARG1, ARG2, OP, ...) \
|
||||
_##OP(ARG1, ARG2) \
|
||||
IF(HAS_ARGS(__VA_ARGS__)) \
|
||||
(DEFER2(_EMAP2_INNER)()(ARG1, ARG2, ##__VA_ARGS__))
|
||||
|
||||
#define _EMAP2_INNER() EMAP2_INNER
|
||||
546
src/avr/src/drv8711.c
Normal file
546
src/avr/src/drv8711.c
Normal file
@@ -0,0 +1,546 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "drv8711.h"
|
||||
#include "status.h"
|
||||
#include "stepper.h"
|
||||
#include "switch.h"
|
||||
#include "estop.h"
|
||||
#include "seek.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
#define DRIVERS MOTORS
|
||||
|
||||
|
||||
#define DRV8711_WORD_BYTE_PTR(WORD, LOW) (((uint8_t *)&(WORD)) + !(LOW))
|
||||
|
||||
|
||||
typedef enum {
|
||||
SS_WRITE_OFF,
|
||||
SS_WRITE_BLANK,
|
||||
SS_WRITE_DECAY,
|
||||
SS_WRITE_STALL,
|
||||
SS_WRITE_DRIVE,
|
||||
SS_WRITE_TORQUE,
|
||||
SS_WRITE_CTRL,
|
||||
SS_READ_OFF,
|
||||
SS_READ_STATUS,
|
||||
SS_CLEAR_STATUS,
|
||||
} spi_state_t;
|
||||
|
||||
|
||||
bool motor_fault = false;
|
||||
|
||||
|
||||
typedef struct {
|
||||
float current;
|
||||
uint8_t torque;
|
||||
} current_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t cs_pin;
|
||||
switch_id_t stall_sw;
|
||||
|
||||
uint8_t status;
|
||||
uint16_t flags;
|
||||
bool reset_flags;
|
||||
bool stalled;
|
||||
|
||||
drv8711_state_t state;
|
||||
current_t drive;
|
||||
current_t idle;
|
||||
current_t stall;
|
||||
uint16_t stall_vdiv;
|
||||
uint8_t stall_thresh;
|
||||
uint8_t last_thresh;
|
||||
uint16_t sample_time;
|
||||
//float stall_current;
|
||||
|
||||
uint8_t microstep;
|
||||
stall_callback_t stall_cb;
|
||||
|
||||
uint8_t last_torque;
|
||||
uint8_t last_microstep;
|
||||
|
||||
spi_state_t spi_state;
|
||||
} drv8711_driver_t;
|
||||
|
||||
|
||||
static drv8711_driver_t drivers[DRIVERS] = {
|
||||
{.cs_pin = SPI_CS_0_PIN, .stall_sw = SW_STALL_0},
|
||||
{.cs_pin = SPI_CS_1_PIN, .stall_sw = SW_STALL_1},
|
||||
{.cs_pin = SPI_CS_2_PIN, .stall_sw = SW_STALL_2},
|
||||
{.cs_pin = SPI_CS_3_PIN, .stall_sw = SW_STALL_3},
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool advance;
|
||||
uint8_t disable_cs_pin;
|
||||
|
||||
uint16_t command;
|
||||
uint16_t response;
|
||||
uint8_t driver;
|
||||
bool low_byte;
|
||||
} spi_t;
|
||||
|
||||
static spi_t spi = {0};
|
||||
|
||||
|
||||
static void _current_set(current_t *c, float current) {
|
||||
const float gain = DRV8711_CTRL_GAIN(DRV8711_CTRL);
|
||||
const float max_current = CURRENT_SENSE_REF / (CURRENT_SENSE_RESISTOR * gain);
|
||||
|
||||
// Limit to max configurable current (11A)
|
||||
if (max_current < current) current = max_current;
|
||||
|
||||
c->current = current;
|
||||
c->torque = round(current * CURRENT_SENSE_RESISTOR / CURRENT_SENSE_REF *
|
||||
gain * 255);
|
||||
}
|
||||
|
||||
|
||||
static bool _driver_fault(drv8711_driver_t *drv) {return drv->flags & 0x1f;}
|
||||
|
||||
|
||||
static bool _driver_active(drv8711_driver_t *drv) {
|
||||
return drv->state == DRV8711_ACTIVE;
|
||||
}
|
||||
|
||||
|
||||
static float _driver_get_current(drv8711_driver_t *drv) {
|
||||
if (_driver_fault(drv)) return 0;
|
||||
|
||||
switch (drv->state) {
|
||||
case DRV8711_IDLE: return drv->idle.current;
|
||||
case DRV8711_ACTIVE: return drv->drive.current;
|
||||
default: return 0; // Off
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t _driver_get_torque(drv8711_driver_t *drv) {
|
||||
if (estop_triggered()) return 0;
|
||||
|
||||
if(seek_active()) return drv->stall.torque;
|
||||
|
||||
switch (drv->state) {
|
||||
case DRV8711_IDLE: return drv->idle.torque;
|
||||
case DRV8711_ACTIVE: return drv->drive.torque;
|
||||
default: return 0; // Off
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint16_t _driver_spi_command(drv8711_driver_t *drv) {
|
||||
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);
|
||||
case SS_WRITE_DECAY: return DRV8711_WRITE(DRV8711_DECAY_REG, DRV8711_DECAY);
|
||||
|
||||
case SS_WRITE_STALL: {
|
||||
//uint16_t reg = drv->stall_thresh | DRV8711_STALL_SDCNT_2 | drv->stall_vdiv; //ORIGINAL
|
||||
//uint16_t reg = 50 | DRV8711_STALL_SDCNT_8 | DRV8711_STALL_VDIV_4; //WORKS
|
||||
uint16_t reg = drv->stall_thresh | DRV8711_STALL_SDCNT_8 | drv->stall_vdiv;
|
||||
drv->last_thresh = drv->stall_thresh;
|
||||
return DRV8711_WRITE(DRV8711_STALL_REG, reg);
|
||||
}
|
||||
|
||||
case SS_WRITE_DRIVE: return DRV8711_WRITE(DRV8711_DRIVE_REG, DRV8711_DRIVE);
|
||||
|
||||
case SS_WRITE_TORQUE:
|
||||
drv->last_torque = _driver_get_torque(drv);
|
||||
return DRV8711_WRITE(DRV8711_TORQUE_REG, DRV8711_TORQUE | drv->last_torque);
|
||||
|
||||
case SS_WRITE_CTRL: {
|
||||
// NOTE, we disable the driver if it's not active. The chip gets hot
|
||||
// idling with the driver enabled.
|
||||
bool enable = _driver_get_torque(drv);
|
||||
drv->last_microstep = drv->microstep;
|
||||
return DRV8711_WRITE(DRV8711_CTRL_REG, DRV8711_CTRL |
|
||||
(drv->microstep << 3) |
|
||||
(enable ? DRV8711_CTRL_ENBL_bm : 0));
|
||||
}
|
||||
|
||||
case SS_READ_OFF: return DRV8711_READ(DRV8711_OFF_REG);
|
||||
case SS_READ_STATUS: return DRV8711_READ(DRV8711_STATUS_REG);
|
||||
|
||||
case SS_CLEAR_STATUS:
|
||||
drv->reset_flags = false;
|
||||
drv->flags = 0;
|
||||
return DRV8711_WRITE(DRV8711_STATUS_REG, 0x0fff & ~drv->status);
|
||||
}
|
||||
|
||||
return 0; // Should not get here
|
||||
}
|
||||
|
||||
|
||||
static spi_state_t _driver_spi_next(drv8711_driver_t *drv) {
|
||||
// Process response
|
||||
switch (drv->spi_state) {
|
||||
case SS_READ_OFF:
|
||||
// We read back the OFF register to test for communication failure.
|
||||
if ((spi.response & 0x1ff) != DRV8711_OFF)
|
||||
drv->flags |= DRV8711_COMM_ERROR_bm;
|
||||
else drv->flags &= ~DRV8711_COMM_ERROR_bm;
|
||||
break;
|
||||
|
||||
case SS_READ_STATUS: {
|
||||
drv->status = spi.response;
|
||||
|
||||
// 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.
|
||||
// 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);
|
||||
drv->flags = (drv->flags & 0xff00) | (mask & drv->status);
|
||||
|
||||
// EStop on fatal driver faults
|
||||
if (_driver_fault(drv)) estop_trigger(STAT_MOTOR_FAULT);
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (drv->spi_state) {
|
||||
case SS_READ_OFF:
|
||||
if (drv->flags & DRV8711_COMM_ERROR_bm) return SS_WRITE_OFF; // Retry
|
||||
break;
|
||||
|
||||
case SS_READ_STATUS:
|
||||
if (drv->reset_flags) return SS_CLEAR_STATUS;
|
||||
if (drv->last_torque != _driver_get_torque(drv)) return SS_WRITE_TORQUE;
|
||||
if (drv->last_microstep != drv->microstep) return SS_WRITE_CTRL;
|
||||
if (drv->last_thresh != drv->stall_thresh) return SS_WRITE_STALL;
|
||||
// Fall through
|
||||
|
||||
case SS_CLEAR_STATUS: return SS_READ_OFF;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return (spi_state_t)(drv->spi_state + 1); // Next
|
||||
}
|
||||
|
||||
|
||||
static void _spi_send() {
|
||||
drv8711_driver_t *drv = &drivers[spi.driver];
|
||||
|
||||
// Flush any status errors (TODO check SPI errors)
|
||||
uint8_t x = SPIC.STATUS;
|
||||
x = x;
|
||||
|
||||
// Read byte
|
||||
*DRV8711_WORD_BYTE_PTR(spi.response, !spi.low_byte) = SPIC.DATA;
|
||||
|
||||
// Advance state and process response
|
||||
if (spi.advance) {
|
||||
spi.advance = false;
|
||||
|
||||
// Handle response and set next state
|
||||
drv->spi_state = _driver_spi_next(drv);
|
||||
|
||||
// Next driver
|
||||
if (++spi.driver == DRIVERS) spi.driver = 0; // Wrap around
|
||||
drv = &drivers[spi.driver];
|
||||
}
|
||||
|
||||
// Disable CS
|
||||
if (spi.disable_cs_pin) {
|
||||
OUTCLR_PIN(spi.disable_cs_pin); // Set low (inactive)
|
||||
_delay_us(1);
|
||||
spi.disable_cs_pin = 0;
|
||||
}
|
||||
|
||||
if (spi.low_byte) {
|
||||
spi.disable_cs_pin = drv->cs_pin; // Schedule next CS disable
|
||||
spi.advance = true; // Word complete
|
||||
|
||||
} else {
|
||||
// Enable CS
|
||||
OUTSET_PIN(drv->cs_pin); // Set high (active)
|
||||
_delay_us(1);
|
||||
|
||||
// Get next command
|
||||
spi.command = _driver_spi_command(drv);
|
||||
}
|
||||
|
||||
// Write byte and prep next read
|
||||
SPIC.DATA = *DRV8711_WORD_BYTE_PTR(spi.command, spi.low_byte);
|
||||
|
||||
// Next byte
|
||||
spi.low_byte = !spi.low_byte;
|
||||
}
|
||||
|
||||
|
||||
ISR(SPIC_INT_vect) {_spi_send();}
|
||||
|
||||
|
||||
static void _stall_change(int driver, bool stalled) {
|
||||
drivers[driver].stalled = stalled;
|
||||
|
||||
// Call stall callback
|
||||
if (stalled && drivers[driver].stall_cb)
|
||||
drivers[driver].stall_cb(driver);
|
||||
}
|
||||
|
||||
|
||||
static void _stall_switch_cb(switch_id_t sw, bool active) {
|
||||
switch (sw) {
|
||||
case SW_STALL_0: _stall_change(0, active); break;
|
||||
case SW_STALL_1: _stall_change(1, active); break;
|
||||
case SW_STALL_2: _stall_change(2, active); break;
|
||||
case SW_STALL_3: _stall_change(3, active); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _motor_fault_switch_cb(switch_id_t sw, bool active) {
|
||||
motor_fault = active;
|
||||
}
|
||||
|
||||
|
||||
void drv8711_init() {
|
||||
// Setup pins
|
||||
// Must set the SS pin either in/high or out/any for master mode to work
|
||||
// Note, this pin is also used by the USART as the CTS line
|
||||
DIRSET_PIN(SPI_SS_PIN); // Output
|
||||
OUTSET_PIN(SPI_CLK_PIN); // High
|
||||
DIRSET_PIN(SPI_CLK_PIN); // Output
|
||||
DIRCLR_PIN(SPI_MISO_PIN); // Input
|
||||
OUTSET_PIN(SPI_MOSI_PIN); // High
|
||||
DIRSET_PIN(SPI_MOSI_PIN); // Output
|
||||
|
||||
// Motor driver enable
|
||||
OUTSET_PIN(MOTOR_ENABLE_PIN); // Active high
|
||||
DIRSET_PIN(MOTOR_ENABLE_PIN); // Output
|
||||
|
||||
for (int i = 0; i < DRIVERS; i++) {
|
||||
uint8_t cs_pin = drivers[i].cs_pin;
|
||||
OUTSET_PIN(cs_pin); // High
|
||||
DIRSET_PIN(cs_pin); // Output
|
||||
|
||||
switch_id_t stall_sw = drivers[i].stall_sw;
|
||||
switch_set_type(stall_sw, SW_NORMALLY_OPEN);
|
||||
switch_set_callback(stall_sw, _stall_switch_cb);
|
||||
|
||||
drivers[i].reset_flags = true; // Reset flags once on startup
|
||||
}
|
||||
|
||||
switch_set_type(SW_MOTOR_FAULT, SW_NORMALLY_OPEN);
|
||||
switch_set_callback(SW_MOTOR_FAULT, _motor_fault_switch_cb);
|
||||
|
||||
// Configure SPI
|
||||
PR.PRPC &= ~PR_SPI_bm; // Disable power reduction
|
||||
SPIC.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_0_gc |
|
||||
SPI_PRESCALER_DIV16_gc; // enable, big endian, master, mode, clock div
|
||||
PIN_PORT(SPI_CLK_PIN)->REMAP = PORT_SPI_bm; // Swap SCK and MOSI
|
||||
SPIC.INTCTRL = SPI_INTLVL_LO_gc; // interupt level
|
||||
|
||||
_spi_send(); // Kick it off
|
||||
}
|
||||
|
||||
|
||||
drv8711_state_t drv8711_get_state(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return DRV8711_DISABLED;
|
||||
return drivers[driver].state;
|
||||
}
|
||||
|
||||
|
||||
void drv8711_set_state(int driver, drv8711_state_t state) {
|
||||
if (driver < 0 || DRIVERS <= driver) return;
|
||||
drivers[driver].state = state;
|
||||
}
|
||||
|
||||
|
||||
void drv8711_set_microsteps(int driver, uint16_t msteps) {
|
||||
if (driver < 0 || DRIVERS <= driver) return;
|
||||
switch (msteps) {
|
||||
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: case 256:
|
||||
break;
|
||||
default: return; // Invalid
|
||||
}
|
||||
|
||||
drivers[driver].microstep = round(logf(msteps) / logf(2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void drv8711_set_stall_callback(int driver, stall_callback_t cb) {
|
||||
drivers[driver].stall_cb = cb;
|
||||
}
|
||||
|
||||
|
||||
float get_drive_current(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
return drivers[driver].drive.current;
|
||||
}
|
||||
|
||||
|
||||
void set_drive_current(int driver, float value) {
|
||||
if (driver < 0 || DRIVERS <= driver || value < 0) return;
|
||||
if (MAX_CURRENT < value) value = MAX_CURRENT;
|
||||
_current_set(&drivers[driver].drive, value);
|
||||
}
|
||||
|
||||
|
||||
float get_idle_current(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
return drivers[driver].idle.current;
|
||||
}
|
||||
|
||||
|
||||
void set_idle_current(int driver, float value) {
|
||||
if (driver < 0 || DRIVERS <= driver || value < 0 || MAX_IDLE_CURRENT < value)
|
||||
return;
|
||||
|
||||
_current_set(&drivers[driver].idle, value);
|
||||
}
|
||||
|
||||
|
||||
float get_active_current(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
return _driver_get_current(&drivers[driver]);
|
||||
}
|
||||
|
||||
|
||||
bool get_motor_fault() {return motor_fault;}
|
||||
|
||||
|
||||
void set_driver_flags(int driver, uint16_t flags) {
|
||||
drivers[driver].reset_flags = true;
|
||||
}
|
||||
|
||||
|
||||
uint16_t get_driver_flags(int driver) {return drivers[driver].flags;}
|
||||
bool get_driver_stalled(int driver) {return drivers[driver].stalled;}
|
||||
|
||||
|
||||
float get_stall_volts(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
|
||||
float vdiv;
|
||||
switch (drivers[driver].stall_vdiv) {
|
||||
case DRV8711_STALL_VDIV_4: vdiv = 4; break;
|
||||
case DRV8711_STALL_VDIV_8: vdiv = 8; break;
|
||||
case DRV8711_STALL_VDIV_16: vdiv = 16; break;
|
||||
default: vdiv = 32; break;
|
||||
}
|
||||
|
||||
return 1.8 / 256 * vdiv * drivers[driver].stall_thresh;
|
||||
}
|
||||
|
||||
|
||||
void set_stall_volts(int driver, float volts) {
|
||||
if (driver < 0 || DRIVERS <= driver) return;
|
||||
|
||||
uint16_t vdiv = DRV8711_STALL_VDIV_32;
|
||||
uint16_t thresh = (uint16_t)(volts * 256 / 1.8);
|
||||
|
||||
if (thresh < 4 << 8) {
|
||||
thresh >>= 2;
|
||||
vdiv = DRV8711_STALL_VDIV_4;
|
||||
|
||||
} else if (thresh < 8 << 8) {
|
||||
thresh >>= 3;
|
||||
vdiv = DRV8711_STALL_VDIV_8;
|
||||
|
||||
} else if (thresh < 16 << 8) {
|
||||
thresh >>= 4;
|
||||
vdiv = DRV8711_STALL_VDIV_16;
|
||||
|
||||
} else {
|
||||
if (thresh < 32 << 8) thresh >>= 5;
|
||||
else thresh = 255;
|
||||
}
|
||||
|
||||
drivers[driver].stall_vdiv = vdiv;
|
||||
drivers[driver].stall_thresh = thresh;
|
||||
}
|
||||
|
||||
void set_stall_sample_time(int driver, uint16_t sample_time)
|
||||
{
|
||||
if (driver < 0 || DRIVERS <= driver) return;
|
||||
|
||||
switch (sample_time) {
|
||||
case 50: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_50; break;
|
||||
case 100: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_100; break;
|
||||
case 200: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_200; break;
|
||||
case 300: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_300; break;
|
||||
case 400: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_400; break;
|
||||
case 600: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_600; break;
|
||||
case 800: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_800; break;
|
||||
case 1000: drivers[driver].sample_time = DRV8711_TORQUE_SMPLTH_1000; break;
|
||||
default: return; // Invalid
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint16_t get_stall_sample_time(int driver)
|
||||
{
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
|
||||
uint16_t sample_time = 0;
|
||||
switch (drivers[driver].sample_time) {
|
||||
case DRV8711_TORQUE_SMPLTH_50: sample_time = 50; break;
|
||||
case DRV8711_TORQUE_SMPLTH_100: sample_time = 100; break;
|
||||
case DRV8711_TORQUE_SMPLTH_200: sample_time = 200; break;
|
||||
case DRV8711_TORQUE_SMPLTH_300: sample_time = 300; break;
|
||||
case DRV8711_TORQUE_SMPLTH_400: sample_time = 400; break;
|
||||
case DRV8711_TORQUE_SMPLTH_600: sample_time = 600; break;
|
||||
case DRV8711_TORQUE_SMPLTH_800: sample_time = 800; break;
|
||||
case DRV8711_TORQUE_SMPLTH_1000: sample_time = 1000; break;
|
||||
default: sample_time = 50; break;
|
||||
}
|
||||
|
||||
return sample_time;
|
||||
}
|
||||
|
||||
float get_stall_current(int driver) {
|
||||
if (driver < 0 || DRIVERS <= driver) return 0;
|
||||
return drivers[driver].stall.current;
|
||||
}
|
||||
|
||||
|
||||
void set_stall_current(int driver, float value) {
|
||||
if (driver < 0 || DRIVERS <= driver || value < 0) return;
|
||||
if (MAX_CURRENT < value) value = MAX_CURRENT;
|
||||
_current_set(&drivers[driver].stall, value);
|
||||
}
|
||||
188
src/avr/src/drv8711.h
Normal file
188
src/avr/src/drv8711.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "status.h"
|
||||
#include "motor.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
enum {
|
||||
DRV8711_CTRL_REG,
|
||||
DRV8711_TORQUE_REG,
|
||||
DRV8711_OFF_REG,
|
||||
DRV8711_BLANK_REG,
|
||||
DRV8711_DECAY_REG,
|
||||
DRV8711_STALL_REG,
|
||||
DRV8711_DRIVE_REG,
|
||||
DRV8711_STATUS_REG,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_CTRL_ENBL_bm = 1 << 0,
|
||||
DRV8711_CTRL_RDIR_bm = 1 << 1,
|
||||
DRV8711_CTRL_RSTEP_bm = 1 << 2,
|
||||
DRV8711_CTRL_MODE_1 = 0 << 3,
|
||||
DRV8711_CTRL_MODE_2 = 1 << 3,
|
||||
DRV8711_CTRL_MODE_4 = 2 << 3,
|
||||
DRV8711_CTRL_MODE_8 = 3 << 3,
|
||||
DRV8711_CTRL_MODE_16 = 4 << 3,
|
||||
DRV8711_CTRL_MODE_32 = 5 << 3,
|
||||
DRV8711_CTRL_MODE_64 = 6 << 3,
|
||||
DRV8711_CTRL_MODE_128 = 7 << 3,
|
||||
DRV8711_CTRL_MODE_256 = 8 << 3,
|
||||
DRV8711_CTRL_EXSTALL_bm = 1 << 7,
|
||||
DRV8711_CTRL_ISGAIN_5 = 0 << 8,
|
||||
DRV8711_CTRL_ISGAIN_10 = 1 << 8,
|
||||
DRV8711_CTRL_ISGAIN_20 = 2 << 8,
|
||||
DRV8711_CTRL_ISGAIN_40 = 3 << 8,
|
||||
DRV8711_CTRL_DTIME_400 = 0 << 10,
|
||||
DRV8711_CTRL_DTIME_450 = 1 << 10,
|
||||
DRV8711_CTRL_DTIME_650 = 2 << 10,
|
||||
DRV8711_CTRL_DTIME_850 = 3 << 10,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_TORQUE_SMPLTH_50 = 0 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_100 = 1 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_200 = 2 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_300 = 3 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_400 = 4 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_600 = 5 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_800 = 6 << 8,
|
||||
DRV8711_TORQUE_SMPLTH_1000 = 7 << 8,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_OFF_PWMMODE_bm = 1 << 8,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_BLANK_ABT_bm = 1 << 8,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_DECAY_DECMOD_SLOW = 0 << 8,
|
||||
DRV8711_DECAY_DECMOD_OPT = 1 << 8,
|
||||
DRV8711_DECAY_DECMOD_FAST = 2 << 8,
|
||||
DRV8711_DECAY_DECMOD_MIXED = 3 << 8,
|
||||
DRV8711_DECAY_DECMOD_AUTO_OPT = 4 << 8,
|
||||
DRV8711_DECAY_DECMOD_AUTO_MIXED = 5 << 8,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_STALL_SDCNT_1 = 0 << 8,
|
||||
DRV8711_STALL_SDCNT_2 = 1 << 8,
|
||||
DRV8711_STALL_SDCNT_4 = 2 << 8,
|
||||
DRV8711_STALL_SDCNT_8 = 3 << 8,
|
||||
DRV8711_STALL_VDIV_32 = 0 << 10,
|
||||
DRV8711_STALL_VDIV_16 = 1 << 10,
|
||||
DRV8711_STALL_VDIV_8 = 2 << 10,
|
||||
DRV8711_STALL_VDIV_4 = 3 << 10,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
DRV8711_DRIVE_OCPTH_250 = 0 << 0,
|
||||
DRV8711_DRIVE_OCPTH_500 = 1 << 0,
|
||||
DRV8711_DRIVE_OCPTH_750 = 2 << 0,
|
||||
DRV8711_DRIVE_OCPTH_1000 = 3 << 0,
|
||||
DRV8711_DRIVE_OCPDEG_1 = 0 << 2,
|
||||
DRV8711_DRIVE_OCPDEG_2 = 1 << 2,
|
||||
DRV8711_DRIVE_OCPDEG_4 = 2 << 2,
|
||||
DRV8711_DRIVE_OCPDEG_8 = 3 << 2,
|
||||
DRV8711_DRIVE_TDRIVEN_250 = 0 << 4,
|
||||
DRV8711_DRIVE_TDRIVEN_500 = 1 << 4,
|
||||
DRV8711_DRIVE_TDRIVEN_1000 = 2 << 4,
|
||||
DRV8711_DRIVE_TDRIVEN_2000 = 3 << 4,
|
||||
DRV8711_DRIVE_TDRIVEP_250 = 0 << 6,
|
||||
DRV8711_DRIVE_TDRIVEP_500 = 1 << 6,
|
||||
DRV8711_DRIVE_TDRIVEP_1000 = 2 << 6,
|
||||
DRV8711_DRIVE_TDRIVEP_2000 = 3 << 6,
|
||||
DRV8711_DRIVE_IDRIVEN_100 = 0 << 8,
|
||||
DRV8711_DRIVE_IDRIVEN_200 = 1 << 8,
|
||||
DRV8711_DRIVE_IDRIVEN_300 = 2 << 8,
|
||||
DRV8711_DRIVE_IDRIVEN_400 = 3 << 8,
|
||||
DRV8711_DRIVE_IDRIVEP_50 = 0 << 10,
|
||||
DRV8711_DRIVE_IDRIVEP_100 = 1 << 10,
|
||||
DRV8711_DRIVE_IDRIVEP_150 = 2 << 10,
|
||||
DRV8711_DRIVE_IDRIVEP_200 = 3 << 10,
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
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,
|
||||
};
|
||||
|
||||
|
||||
#define DRV8711_READ(ADDR) ((1 << 15) | ((ADDR) << 12))
|
||||
#define DRV8711_WRITE(ADDR, DATA) (((ADDR) << 12) | ((DATA) & 0xfff))
|
||||
#define DRV8711_CMD_ADDR(CMD) (((CMD) >> 12) & 7)
|
||||
#define DRV8711_CMD_IS_READ(CMD) ((1 << 15) & (CMD))
|
||||
|
||||
#define DRV8711_CTRL_ISGAIN_BM (3 << 8)
|
||||
#define DRV8711_CTRL_GET_GAIN(CTRL) ((CTRL) & DRV8711_CTRL_ISGAIN_BM)
|
||||
|
||||
#define DRV8711_CTRL_GAIN(CTRL) \
|
||||
(DRV8711_CTRL_GET_GAIN(CTRL) == DRV8711_CTRL_ISGAIN_5 ? 5 : \
|
||||
(DRV8711_CTRL_GET_GAIN(CTRL) == DRV8711_CTRL_ISGAIN_10 ? 10 : \
|
||||
(DRV8711_CTRL_GET_GAIN(CTRL) == DRV8711_CTRL_ISGAIN_20 ? 20 : 40)))
|
||||
|
||||
|
||||
typedef enum {
|
||||
DRV8711_DISABLED,
|
||||
DRV8711_IDLE,
|
||||
DRV8711_ACTIVE,
|
||||
} drv8711_state_t;
|
||||
|
||||
|
||||
typedef void (*stall_callback_t)(int driver);
|
||||
|
||||
|
||||
void drv8711_init();
|
||||
drv8711_state_t drv8711_get_state(int driver);
|
||||
void drv8711_set_state(int driver, drv8711_state_t state);
|
||||
void drv8711_set_microsteps(int driver, uint16_t msteps);
|
||||
void drv8711_set_stall_callback(int driver, stall_callback_t cb);
|
||||
36
src/avr/src/emu.h
Normal file
36
src/avr/src/emu.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#ifdef __AVR__
|
||||
#define emu_init()
|
||||
#define emu_callback()
|
||||
|
||||
#else
|
||||
void emu_init();
|
||||
void emu_callback();
|
||||
|
||||
#endif
|
||||
126
src/avr/src/estop.c
Normal file
126
src/avr/src/estop.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "estop.h"
|
||||
#include "motor.h"
|
||||
#include "stepper.h"
|
||||
#include "spindle.h"
|
||||
#include "switch.h"
|
||||
#include "hardware.h"
|
||||
#include "config.h"
|
||||
#include "state.h"
|
||||
#include "outputs.h"
|
||||
#include "jog.h"
|
||||
#include "exec.h"
|
||||
|
||||
|
||||
static stat_t estop_reason = STAT_OK;
|
||||
|
||||
|
||||
static void _switch_callback(switch_id_t id, bool active) {
|
||||
if (active) estop_trigger(STAT_ESTOP_SWITCH);
|
||||
else estop_clear();
|
||||
}
|
||||
|
||||
|
||||
void estop_init() {
|
||||
switch_set_callback(SW_ESTOP, _switch_callback);
|
||||
if (switch_is_active(SW_ESTOP)) estop_trigger(STAT_ESTOP_SWITCH);
|
||||
}
|
||||
|
||||
|
||||
bool estop_triggered() {return estop_reason != STAT_OK;}
|
||||
|
||||
|
||||
void estop_trigger(stat_t reason) {
|
||||
if (estop_triggered()) return;
|
||||
estop_reason = reason;
|
||||
|
||||
// Set fault signal
|
||||
outputs_set_active(FAULT_PIN, true);
|
||||
|
||||
// Shutdown peripherals
|
||||
st_shutdown();
|
||||
spindle_estop();
|
||||
jog_stop();
|
||||
outputs_stop();
|
||||
|
||||
// Set machine state
|
||||
state_estop();
|
||||
}
|
||||
|
||||
|
||||
void estop_clear() {
|
||||
// It is important that we don't clear the estop if it's not set because
|
||||
// it can cause a reboot loop.
|
||||
if (!estop_triggered()) return;
|
||||
|
||||
// Check if estop switch is set
|
||||
if (switch_is_active(SW_ESTOP)) {
|
||||
estop_reason = STAT_ESTOP_SWITCH;
|
||||
return; // Can't clear while estop switch is still active
|
||||
}
|
||||
|
||||
// Clear fault signal
|
||||
outputs_set_active(FAULT_PIN, false);
|
||||
|
||||
estop_reason = STAT_OK;
|
||||
|
||||
// Reboot
|
||||
// Note, hardware.c waits until any spindle stop command has been delivered
|
||||
hw_request_hard_reset();
|
||||
}
|
||||
|
||||
|
||||
// Var callbacks
|
||||
bool get_estop() {return estop_triggered();}
|
||||
|
||||
|
||||
void set_estop(bool value) {
|
||||
if (value == estop_triggered()) return;
|
||||
if (value) estop_trigger(STAT_ESTOP_USER);
|
||||
else estop_clear();
|
||||
}
|
||||
|
||||
|
||||
PGM_P get_estop_reason() {return status_to_pgmstr(estop_reason);}
|
||||
|
||||
|
||||
// Command callbacks
|
||||
stat_t command_estop(char *cmd) {
|
||||
estop_trigger(STAT_ESTOP_USER);
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
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;}
|
||||
42
src/avr/src/estop.h
Normal file
42
src/avr/src/estop.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "status.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
void estop_init();
|
||||
bool estop_triggered();
|
||||
void estop_trigger(stat_t reason);
|
||||
void estop_clear();
|
||||
|
||||
|
||||
#define ESTOP_ASSERT(COND, CODE) \
|
||||
do {if (!(COND)) estop_trigger(CODE);} while (0)
|
||||
306
src/avr/src/exec.c
Normal file
306
src/avr/src/exec.c
Normal file
@@ -0,0 +1,306 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "exec.h"
|
||||
|
||||
#include "stepper.h"
|
||||
#include "motor.h"
|
||||
#include "axis.h"
|
||||
#include "util.h"
|
||||
#include "command.h"
|
||||
#include "switch.h"
|
||||
#include "seek.h"
|
||||
#include "estop.h"
|
||||
#include "state.h"
|
||||
#include "spindle.h"
|
||||
#include "config.h"
|
||||
#include "SCurve.h"
|
||||
|
||||
|
||||
static struct {
|
||||
exec_cb_t cb;
|
||||
|
||||
float position[AXES];
|
||||
float velocity;
|
||||
float accel;
|
||||
float jerk;
|
||||
float peak_vel;
|
||||
float peak_accel;
|
||||
|
||||
float feed_override;
|
||||
|
||||
struct {
|
||||
float target[AXES];
|
||||
float time;
|
||||
float vel;
|
||||
float accel;
|
||||
float max_accel;
|
||||
float max_jerk;
|
||||
power_update_t power_updates[2 * POWER_MAX_UPDATES];
|
||||
exec_cb_t cb;
|
||||
} seg;
|
||||
} ex;
|
||||
|
||||
|
||||
static void _limit_switch_cb(switch_id_t sw, bool active) {
|
||||
if (sw == seek_get_switch()) return;
|
||||
if (ex.velocity && active) estop_trigger(STAT_ESTOP_SWITCH);
|
||||
}
|
||||
|
||||
|
||||
void exec_init() {
|
||||
memset(&ex, 0, sizeof(ex));
|
||||
ex.feed_override = 1; // TODO implement feed override
|
||||
|
||||
// Set callback for limit switches
|
||||
for (int sw = SW_MIN_0; sw <= SW_MAX_3; sw++)
|
||||
switch_set_callback((switch_id_t)sw, _limit_switch_cb);
|
||||
}
|
||||
|
||||
|
||||
void exec_get_position(float p[AXES]) {
|
||||
memcpy(p, ex.position, sizeof(ex.position));
|
||||
}
|
||||
|
||||
|
||||
float exec_get_axis_position(int axis) {return ex.position[axis];}
|
||||
|
||||
|
||||
void exec_set_velocity(float v) {
|
||||
ex.velocity = v;
|
||||
if (ex.peak_vel < v) ex.peak_vel = v;
|
||||
}
|
||||
|
||||
|
||||
float exec_get_velocity() {return ex.velocity;}
|
||||
|
||||
|
||||
void exec_set_acceleration(float a) {
|
||||
ex.accel = a;
|
||||
if (ex.peak_accel < a) ex.peak_accel = a;
|
||||
}
|
||||
|
||||
|
||||
float exec_get_acceleration() {return ex.accel;}
|
||||
void exec_set_jerk(float j) {ex.jerk = j;}
|
||||
|
||||
|
||||
void exec_set_cb(exec_cb_t cb) {ex.cb = cb;}
|
||||
|
||||
|
||||
void exec_move_to_target(const float target[]) {
|
||||
ESTOP_ASSERT(isfinite(target[AXIS_X]) && isfinite(target[AXIS_Y]) &&
|
||||
isfinite(target[AXIS_Z]) && isfinite(target[AXIS_A]) &&
|
||||
isfinite(target[AXIS_B]) && isfinite(target[AXIS_C]),
|
||||
STAT_BAD_FLOAT);
|
||||
|
||||
// Prep power updates
|
||||
st_prep_power(ex.seg.power_updates);
|
||||
|
||||
// Shift power updates
|
||||
for (unsigned i = 0; i < POWER_MAX_UPDATES; i++) {
|
||||
ex.seg.power_updates[i] = ex.seg.power_updates[i + POWER_MAX_UPDATES];
|
||||
ex.seg.power_updates[i + POWER_MAX_UPDATES].state = POWER_IGNORE;
|
||||
}
|
||||
|
||||
// Update position
|
||||
copy_vector(ex.position, target);
|
||||
|
||||
// Call the stepper prep function
|
||||
st_prep_line(target);
|
||||
}
|
||||
|
||||
|
||||
stat_t _segment_exec() {
|
||||
float t = ex.seg.time;
|
||||
float v = ex.seg.vel;
|
||||
float a = ex.seg.accel;
|
||||
|
||||
// Handle pause
|
||||
if (state_get() == STATE_STOPPING) {
|
||||
a = SCurve::nextAccel(SEGMENT_TIME, 0, ex.velocity, ex.accel,
|
||||
ex.seg.max_accel, ex.seg.max_jerk);
|
||||
v = ex.velocity + SEGMENT_TIME * a;
|
||||
t *= ex.seg.vel / v;
|
||||
|
||||
if (v < MIN_VELOCITY || seek_switch_found()) {
|
||||
t = v = 0;
|
||||
ex.seg.cb = 0;
|
||||
command_reset_position();
|
||||
state_holding();
|
||||
seek_end();
|
||||
spindle_update_speed();
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for next seg if time is too short and we are still moving
|
||||
if (t < SEGMENT_TIME && (!t || v)) {
|
||||
if (!v) {
|
||||
exec_set_velocity(0);
|
||||
exec_set_acceleration(0);
|
||||
exec_set_jerk(0);
|
||||
ex.seg.time = 0;
|
||||
}
|
||||
ex.cb = ex.seg.cb;
|
||||
return STAT_AGAIN;
|
||||
}
|
||||
|
||||
// Update velocity and accel
|
||||
exec_set_velocity(v);
|
||||
exec_set_acceleration(a);
|
||||
|
||||
if (t <= SEGMENT_TIME) {
|
||||
// Move
|
||||
exec_move_to_target(ex.seg.target);
|
||||
ex.seg.time = 0;
|
||||
|
||||
} else {
|
||||
// Compute next target
|
||||
float ratio = SEGMENT_TIME / t;
|
||||
float target[AXES];
|
||||
for (int axis = 0; axis < AXES; axis++) {
|
||||
float diff = ex.seg.target[axis] - ex.position[axis];
|
||||
target[axis] = ex.position[axis] + ratio * diff;
|
||||
}
|
||||
|
||||
// Move
|
||||
exec_move_to_target(target);
|
||||
|
||||
// Update time
|
||||
if (t == ex.seg.time) ex.seg.time -= SEGMENT_TIME;
|
||||
else ex.seg.time -= SEGMENT_TIME * v / ex.seg.vel;
|
||||
}
|
||||
|
||||
// Check switch
|
||||
if (seek_switch_found()) state_seek_hold();
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
stat_t exec_segment(float time, const float target[], float vel, float accel,
|
||||
float maxAccel, float maxJerk,
|
||||
const power_update_t power_updates[]) {
|
||||
// Copy power updates in to the correct position given the time offset
|
||||
float nextT = ex.seg.time + time;
|
||||
const float stepT = 1.0 / 60000; // 1ms in mins
|
||||
float t = 0.5 / 60000; // 0.5ms in mins
|
||||
unsigned j = 0;
|
||||
for (unsigned i = 0; t < nextT && j < POWER_MAX_UPDATES; i++) {
|
||||
if (ex.seg.time < t) ex.seg.power_updates[i] = power_updates[j++];
|
||||
t += stepT;
|
||||
}
|
||||
|
||||
copy_vector(ex.seg.target, target);
|
||||
ex.seg.time = nextT;
|
||||
ex.seg.vel = vel;
|
||||
ex.seg.accel = accel;
|
||||
ex.seg.max_accel = maxAccel;
|
||||
ex.seg.max_jerk = maxJerk;
|
||||
ex.seg.cb = ex.cb;
|
||||
ex.cb = _segment_exec;
|
||||
|
||||
// TODO To be precise, seek_end() should not be called until the current
|
||||
// segment has completed execution.
|
||||
if (!ex.seg.cb) seek_end(); // No callback when at line end
|
||||
|
||||
return _segment_exec();
|
||||
}
|
||||
|
||||
|
||||
// Called by stepper.c from low-level interrupt
|
||||
stat_t exec_next() {
|
||||
// Hold if we've reached zero velocity between commands and stopping
|
||||
if (!ex.cb && !exec_get_velocity() && state_get() == STATE_STOPPING)
|
||||
state_holding();
|
||||
|
||||
if (state_get() == STATE_HOLDING) return STAT_NOP;
|
||||
if (!ex.cb && !command_exec()) return STAT_NOP; // Queue empty
|
||||
if (!ex.cb) return STAT_AGAIN; // Non-exec command
|
||||
return ex.cb(); // Exec
|
||||
}
|
||||
|
||||
|
||||
// Variable callbacks
|
||||
float get_axis_position(int axis) {return ex.position[axis];}
|
||||
float get_velocity() {return ex.velocity / VELOCITY_MULTIPLIER;}
|
||||
float get_acceleration() {return ex.accel / ACCEL_MULTIPLIER;}
|
||||
float get_jerk() {return ex.jerk / JERK_MULTIPLIER;}
|
||||
float get_peak_vel() {return ex.peak_vel / VELOCITY_MULTIPLIER;}
|
||||
void set_peak_vel(float x) {ex.peak_vel = 0;}
|
||||
float get_peak_accel() {return ex.peak_accel / ACCEL_MULTIPLIER;}
|
||||
void set_peak_accel(float x) {ex.peak_accel = 0;}
|
||||
uint16_t get_feed_override() {return ex.feed_override * 1000;}
|
||||
void set_feed_override(uint16_t value) {ex.feed_override = value / 1000.0;}
|
||||
|
||||
|
||||
// Command callbacks
|
||||
typedef struct {
|
||||
uint8_t axis;
|
||||
float position;
|
||||
} set_axis_t;
|
||||
|
||||
|
||||
stat_t command_set_axis(char *cmd) {
|
||||
cmd++; // Skip command name
|
||||
|
||||
// Decode axis
|
||||
int axis = axis_get_id(*cmd++);
|
||||
if (axis < 0) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Decode position
|
||||
float position;
|
||||
if (!decode_float(&cmd, &position)) return STAT_BAD_FLOAT;
|
||||
|
||||
// Check for end of command
|
||||
if (*cmd) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Update command
|
||||
command_set_axis_position((uint8_t)axis, position);
|
||||
|
||||
// Queue
|
||||
set_axis_t set_axis = {(uint8_t)axis, position};
|
||||
command_push(COMMAND_set_axis, &set_axis);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
unsigned command_set_axis_size() {return sizeof(set_axis_t);}
|
||||
|
||||
|
||||
void command_set_axis_exec(void *data) {
|
||||
set_axis_t *cmd = (set_axis_t *)data;
|
||||
|
||||
// Update exec
|
||||
ex.position[cmd->axis] = cmd->position;
|
||||
|
||||
// Update motors
|
||||
for (int motor = 0; motor < MOTORS; motor++)
|
||||
if (motor_get_axis(motor) == cmd->axis)
|
||||
motor_set_position(motor, cmd->position);
|
||||
}
|
||||
59
src/avr/src/exec.h
Normal file
59
src/avr/src/exec.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "spindle.h"
|
||||
#include "status.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
typedef stat_t (*exec_cb_t)();
|
||||
|
||||
|
||||
void exec_init();
|
||||
|
||||
void exec_get_position(float p[AXES]);
|
||||
float exec_get_axis_position(int axis);
|
||||
float exec_get_power_scale();
|
||||
void exec_set_velocity(float v);
|
||||
float exec_get_velocity();
|
||||
void exec_set_acceleration(float a);
|
||||
float exec_get_acceleration();
|
||||
void exec_set_jerk(float j);
|
||||
|
||||
void exec_set_cb(exec_cb_t cb);
|
||||
|
||||
void exec_move_to_target(const float target[]);
|
||||
stat_t exec_segment(float time, const float target[], float vel, float accel,
|
||||
float maxAccel, float maxJerk,
|
||||
const power_update_t power_updates[]);
|
||||
stat_t exec_next();
|
||||
158
src/avr/src/hardware.c
Normal file
158
src/avr/src/hardware.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "rtc.h"
|
||||
#include "usart.h"
|
||||
#include "config.h"
|
||||
#include "pgmspace.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
char id[26];
|
||||
bool hard_reset; // flag to perform a hard reset
|
||||
} hw_t;
|
||||
|
||||
static hw_t hw = {{0}};
|
||||
|
||||
|
||||
#define PROD_SIGS (*(NVM_PROD_SIGNATURES_t *)0x0000)
|
||||
#define HEXNIB(x) "0123456789abcdef"[(x) & 0xf]
|
||||
|
||||
|
||||
static void _init_clock() {
|
||||
#if 0 // 32Mhz Int RC
|
||||
OSC.CTRL |= OSC_RC32MEN_bm | OSC_RC32KEN_bm; // Enable 32MHz & 32KHz osc
|
||||
while (!(OSC.STATUS & OSC_RC32KRDY_bm)); // Wait for 32Khz oscillator
|
||||
while (!(OSC.STATUS & OSC_RC32MRDY_bm)); // Wait for 32MHz oscillator
|
||||
|
||||
// Defaults to calibrate against internal 32Khz clock
|
||||
DFLLRC32M.CTRL = DFLL_ENABLE_bm; // Enable DFLL
|
||||
CCP = CCP_IOREG_gc; // Disable register security
|
||||
CLK.CTRL = CLK_SCLKSEL_RC32M_gc; // Switch to 32MHz clock
|
||||
|
||||
#else
|
||||
// 12-16 MHz crystal; 0.4-16 MHz XTAL w/ 16K CLK startup
|
||||
OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
|
||||
OSC.CTRL = OSC_XOSCEN_bm; // enable external crystal oscillator
|
||||
while (!(OSC.STATUS & OSC_XOSCRDY_bm)); // wait for oscillator ready
|
||||
|
||||
OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2; // PLL source, 2x (32 MHz sys clock)
|
||||
OSC.CTRL = OSC_PLLEN_bm | OSC_XOSCEN_bm; // Enable PLL & External Oscillator
|
||||
while (!(OSC.STATUS & OSC_PLLRDY_bm)); // wait for PLL ready
|
||||
|
||||
CCP = CCP_IOREG_gc;
|
||||
CLK.CTRL = CLK_SCLKSEL_PLL_gc; // switch to PLL clock
|
||||
#endif
|
||||
|
||||
OSC.CTRL &= ~OSC_RC2MEN_bm; // disable internal 2 MHz clock
|
||||
}
|
||||
|
||||
|
||||
#ifdef __AVR__
|
||||
static void _load_hw_id_byte(int i, register8_t *reg) {
|
||||
NVM.CMD = NVM_CMD_READ_CALIB_ROW_gc;
|
||||
uint8_t byte = pgm_read_byte(reg);
|
||||
NVM.CMD = NVM_CMD_NO_OPERATION_gc;
|
||||
|
||||
hw.id[i] = HEXNIB(byte >> 4);
|
||||
hw.id[i + 1] = HEXNIB(byte);
|
||||
}
|
||||
#endif // __AVR__
|
||||
|
||||
|
||||
static void _read_hw_id() {
|
||||
#ifdef __AVR__
|
||||
int i = 0;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM5); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM4); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM3); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM2); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM1); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.LOTNUM0); i += 2;
|
||||
hw.id[i++] = '-';
|
||||
_load_hw_id_byte(i, &PROD_SIGS.WAFNUM); i += 2;
|
||||
hw.id[i++] = '-';
|
||||
_load_hw_id_byte(i, &PROD_SIGS.COORDX1); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.COORDX0); i += 2;
|
||||
hw.id[i++] = '-';
|
||||
_load_hw_id_byte(i, &PROD_SIGS.COORDY1); i += 2;
|
||||
_load_hw_id_byte(i, &PROD_SIGS.COORDY0); i += 2;
|
||||
hw.id[i] = 0;
|
||||
|
||||
#else // __AVR__
|
||||
for (int i = 0; i < 25; i++)
|
||||
hw.id[i] = '0';
|
||||
hw.id[25] = 0;
|
||||
#endif // __AVR__
|
||||
}
|
||||
|
||||
|
||||
/// Lowest level hardware init
|
||||
void hw_init() {
|
||||
_init_clock(); // set system clock
|
||||
rtc_init(); // real time counter
|
||||
_read_hw_id();
|
||||
|
||||
// Round-robin, interrupts in application section, all interupts levels
|
||||
CCP = CCP_IOREG_gc;
|
||||
PMIC.CTRL =
|
||||
PMIC_RREN_bm | PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm;
|
||||
}
|
||||
|
||||
|
||||
void hw_request_hard_reset() {hw.hard_reset = true;}
|
||||
|
||||
|
||||
static void _hard_reset() {
|
||||
usart_flush();
|
||||
cli();
|
||||
CCP = CCP_IOREG_gc;
|
||||
RST.CTRL = RST_SWRST_bm;
|
||||
}
|
||||
|
||||
|
||||
/// Controller's rest handler
|
||||
void hw_reset_handler() {
|
||||
if (!hw.hard_reset) return;
|
||||
|
||||
// Flush serial port and wait for EEPROM writes to finish
|
||||
while (!usart_tx_empty() || !eeprom_is_ready())
|
||||
continue;
|
||||
|
||||
_hard_reset();
|
||||
}
|
||||
|
||||
|
||||
const char *get_hw_id() {return hw.id;}
|
||||
40
src/avr/src/hardware.h
Normal file
40
src/avr/src/hardware.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "status.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
void hw_init();
|
||||
void hw_request_hard_reset();
|
||||
void hw_reset_handler();
|
||||
|
||||
uint8_t hw_disable_watchdog();
|
||||
void hw_restore_watchdog(uint8_t state);
|
||||
301
src/avr/src/huanyang.c
Normal file
301
src/avr/src/huanyang.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "huanyang.h"
|
||||
#include "config.h"
|
||||
#include "modbus.h"
|
||||
#include "estop.h"
|
||||
|
||||
#include <util/atomic.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/*
|
||||
Huanyang is not quite Modbus compliant.
|
||||
|
||||
Message format is:
|
||||
|
||||
[id][func][length][data][checksum]
|
||||
|
||||
Where:
|
||||
|
||||
id - 1-byte Peer ID
|
||||
func - 1-byte One of hy_func_t
|
||||
length - 1-byte Length data in bytes
|
||||
data - length bytes - Command arguments
|
||||
checksum - 16-bit CRC: x^16 + x^15 + x^2 + 1 (0xa001) initial: 0xffff
|
||||
*/
|
||||
|
||||
|
||||
// See VFD manual pg56 3.1.3
|
||||
typedef enum {
|
||||
HUANYANG_FUNC_READ = 1, // [len=1][hy_addr_t]
|
||||
HUANYANG_FUNC_WRITE, // [len=3][hy_addr_t][data]
|
||||
HUANYANG_CTRL_WRITE, // [len=1][hy_ctrl_state_t]
|
||||
HUANYANG_CTRL_READ, // [len=1][hy_ctrl_addr_t]
|
||||
HUANYANG_FREQ_WRITE, // [len=2][freq]
|
||||
HUANYANG_RESERVED_1,
|
||||
HUANYANG_RESERVED_2,
|
||||
HUANYANG_LOOP_TEST,
|
||||
} hy_func_t;
|
||||
|
||||
|
||||
// Sent in HUANYANG_CTRL_WRITE
|
||||
// See VFD manual pg57 3.1.3.c
|
||||
typedef enum {
|
||||
HUANYANG_RUN = 1 << 0,
|
||||
HUANYANG_FORWARD = 1 << 1,
|
||||
HUANYANG_REVERSE = 1 << 2,
|
||||
HUANYANG_STOP = 1 << 3,
|
||||
HUANYANG_REV_FWD = 1 << 4,
|
||||
HUANYANG_JOG = 1 << 5,
|
||||
HUANYANG_JOG_FORWARD = 1 << 6,
|
||||
HUANYANG_JOG_REVERSE = 1 << 7,
|
||||
} hy_ctrl_state_t;
|
||||
|
||||
|
||||
// Returned by HUANYANG_CTRL_WRITE
|
||||
// See VFD manual pg57 3.1.3.c
|
||||
typedef enum {
|
||||
HUANYANG_STATUS_RUN = 1 << 0,
|
||||
HUANYANG_STATUS_JOG = 1 << 1,
|
||||
HUANYANG_STATUS_COMMAND_REV = 1 << 2,
|
||||
HUANYANG_STATUS_RUNNING = 1 << 3,
|
||||
HUANYANG_STATUS_JOGGING = 1 << 4,
|
||||
HUANYANG_STATUS_JOGGING_REV = 1 << 5,
|
||||
HUANYANG_STATUS_BRAKING = 1 << 6,
|
||||
HUANYANG_STATUS_TRACK_START = 1 << 7,
|
||||
} hy_ctrl_status_t;
|
||||
|
||||
|
||||
// Sent in HUANYANG_CTRL_READ
|
||||
// See VFD manual pg57 3.1.3.d
|
||||
typedef enum {
|
||||
HUANYANG_TARGET_FREQ,
|
||||
HUANYANG_ACTUAL_FREQ,
|
||||
HUANYANG_ACTUAL_CURRENT,
|
||||
HUANYANG_ACTUAL_RPM,
|
||||
HUANYANG_DCV,
|
||||
HUANYANG_ACV,
|
||||
HUANYANG_COUNTER,
|
||||
HUANYANG_TEMPERATURE,
|
||||
} hy_ctrl_addr_t;
|
||||
|
||||
|
||||
static struct {
|
||||
uint8_t state;
|
||||
|
||||
deinit_cb_t deinit_cb;
|
||||
bool shutdown;
|
||||
bool changed;
|
||||
float power;
|
||||
|
||||
float actual_freq;
|
||||
float actual_current;
|
||||
uint16_t actual_rpm;
|
||||
uint16_t temperature;
|
||||
|
||||
float max_freq;
|
||||
float min_freq;
|
||||
uint16_t rated_rpm;
|
||||
|
||||
uint8_t status;
|
||||
} hy;
|
||||
|
||||
|
||||
static void _func_read_response(hy_addr_t addr, uint16_t value) {
|
||||
switch (addr) {
|
||||
case HY_PD005_MAX_FREQUENCY: hy.max_freq = value * 0.01; break;
|
||||
case HY_PD011_FREQUENCY_LOWER_LIMIT: hy.min_freq = value * 0.01; break;
|
||||
case HY_PD144_RATED_MOTOR_RPM: hy.rated_rpm = value; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _ctrl_read_response(hy_ctrl_addr_t addr, uint16_t value) {
|
||||
switch (addr) {
|
||||
case HUANYANG_ACTUAL_FREQ: hy.actual_freq = value * 0.01; break;
|
||||
case HUANYANG_ACTUAL_CURRENT: hy.actual_current = value * 0.01; break;
|
||||
case HUANYANG_ACTUAL_RPM: hy.actual_rpm = value; break;
|
||||
case HUANYANG_TEMPERATURE: hy.temperature = value; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint16_t _read_word(const uint8_t *data) {
|
||||
return (uint16_t)data[0] << 8 | data[1];
|
||||
}
|
||||
|
||||
|
||||
static void _handle_response(hy_func_t func, const uint8_t *data) {
|
||||
switch (func) {
|
||||
case HUANYANG_FUNC_READ:
|
||||
_func_read_response((hy_addr_t)*data, _read_word(data + 1));
|
||||
break;
|
||||
|
||||
case HUANYANG_FUNC_WRITE: break;
|
||||
case HUANYANG_CTRL_WRITE: hy.status = *data; break;
|
||||
|
||||
case HUANYANG_CTRL_READ:
|
||||
_ctrl_read_response((hy_ctrl_addr_t)*data, _read_word(data + 1));
|
||||
break;
|
||||
|
||||
case HUANYANG_FREQ_WRITE: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void _next_command();
|
||||
|
||||
|
||||
static bool _shutdown() {
|
||||
if (!hy.shutdown && !estop_triggered()) return false;
|
||||
modbus_deinit();
|
||||
if (hy.deinit_cb) hy.deinit_cb();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _modbus_cb(uint8_t func, uint8_t bytes, const uint8_t *data) {
|
||||
if (!data) { // Modbus command failed
|
||||
if (_shutdown()) return;
|
||||
hy.state = 0;
|
||||
|
||||
} else if (bytes == *data + 1) {
|
||||
_handle_response((hy_func_t)func, data + 1);
|
||||
|
||||
if (func == HUANYANG_CTRL_WRITE && _shutdown()) return;
|
||||
|
||||
// Next command
|
||||
if (++hy.state == 9) {
|
||||
if (hy.shutdown || hy.changed) hy.state = 0;
|
||||
else hy.state = 5;
|
||||
hy.changed = false;
|
||||
}
|
||||
}
|
||||
|
||||
_next_command();
|
||||
}
|
||||
|
||||
|
||||
static void _func_read(hy_addr_t addr) {
|
||||
uint8_t data[2] = {1, addr};
|
||||
modbus_func(HUANYANG_FUNC_READ, 2, data, 4, _modbus_cb);
|
||||
}
|
||||
|
||||
|
||||
static void _ctrl_write(hy_ctrl_state_t state) {
|
||||
uint8_t data[2] = {1, state};
|
||||
modbus_func(HUANYANG_CTRL_WRITE, 2, data, 2, _modbus_cb);
|
||||
}
|
||||
|
||||
|
||||
static void _ctrl_read(hy_ctrl_addr_t addr) {
|
||||
uint8_t data[2] = {1, addr};
|
||||
modbus_func(HUANYANG_CTRL_READ, 2, data, 4, _modbus_cb);
|
||||
}
|
||||
|
||||
|
||||
static void _freq_write(uint16_t freq) {
|
||||
uint8_t data[3] = {2, (uint8_t)(freq >> 8), (uint8_t)freq};
|
||||
modbus_func(HUANYANG_FREQ_WRITE, 3, data, 3, _modbus_cb);
|
||||
}
|
||||
|
||||
|
||||
static void _next_command() {
|
||||
switch (hy.state) {
|
||||
case 0: { // Update direction
|
||||
hy_ctrl_state_t state = HUANYANG_STOP;
|
||||
if (!hy.shutdown && !estop_triggered()) {
|
||||
if (0 < hy.power)
|
||||
state = (hy_ctrl_state_t)(HUANYANG_RUN | HUANYANG_FORWARD);
|
||||
else if (hy.power < 0)
|
||||
state = (hy_ctrl_state_t)(HUANYANG_RUN | HUANYANG_REV_FWD);
|
||||
}
|
||||
|
||||
_ctrl_write(state);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: _func_read(HY_PD005_MAX_FREQUENCY); break;
|
||||
case 2: _func_read(HY_PD011_FREQUENCY_LOWER_LIMIT); break;
|
||||
case 3: _func_read(HY_PD144_RATED_MOTOR_RPM); break;
|
||||
|
||||
case 4: { // Update freqency
|
||||
// Compute frequency in Hz
|
||||
float freq = fabs(hy.power * hy.max_freq);
|
||||
|
||||
// Frequency write command
|
||||
_freq_write(freq * 100);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: _ctrl_read(HUANYANG_ACTUAL_FREQ); break;
|
||||
case 6: _ctrl_read(HUANYANG_ACTUAL_CURRENT); break;
|
||||
case 7: _ctrl_read(HUANYANG_ACTUAL_RPM); break;
|
||||
case 8: _ctrl_read(HUANYANG_TEMPERATURE); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void huanyang_init() {
|
||||
modbus_init();
|
||||
memset(&hy, 0, sizeof(hy));
|
||||
_next_command();
|
||||
}
|
||||
|
||||
|
||||
void huanyang_deinit(deinit_cb_t cb) {
|
||||
hy.deinit_cb = cb;
|
||||
hy.shutdown = true;
|
||||
}
|
||||
|
||||
|
||||
void huanyang_set(float power) {
|
||||
if (hy.power != power && !hy.shutdown)
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
hy.power = power;
|
||||
hy.changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float huanyang_get() {return hy.actual_freq / hy.max_freq;}
|
||||
uint8_t huanyang_get_status() {return hy.status;}
|
||||
|
||||
// Variable callbacks
|
||||
float get_hy_freq() {return hy.actual_freq;}
|
||||
float get_hy_current() {return hy.actual_current;}
|
||||
uint16_t get_hy_temp() {return hy.temperature;}
|
||||
float get_hy_max_freq() {return hy.max_freq;}
|
||||
float get_hy_min_freq() {return hy.min_freq;}
|
||||
uint16_t get_hy_rated_rpm() {return hy.rated_rpm;}
|
||||
226
src/avr/src/huanyang.h
Normal file
226
src/avr/src/huanyang.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "spindle.h"
|
||||
|
||||
|
||||
void huanyang_init();
|
||||
void huanyang_deinit(deinit_cb_t cb);
|
||||
void huanyang_set(float power);
|
||||
float huanyang_get();
|
||||
uint8_t huanyang_get_status();
|
||||
|
||||
|
||||
/// See Huanyang VFD user manual
|
||||
typedef enum {
|
||||
HY_PD000_PARAMETER_LOCK,
|
||||
HY_PD001_SOURCE_OF_OPERATION_COMMANDS,
|
||||
HY_PD002_SOURCE_OF_OPERATING_FREQUENCY,
|
||||
HY_PD003_MAIN_FREQUENCY,
|
||||
HY_PD004_BASE_FREQUENCY,
|
||||
HY_PD005_MAX_FREQUENCY,
|
||||
HY_PD006_INTERMEDIATE_FREQUENCY,
|
||||
HY_PD007_MIN_FREQUENCY,
|
||||
HY_PD008_MAX_VOLTAGE,
|
||||
HY_PD009_INTERMEDIATE_VOLTAGE,
|
||||
HY_PD010_MIN_VOLTAGE,
|
||||
HY_PD011_FREQUENCY_LOWER_LIMIT,
|
||||
HY_PD012_RESERVED,
|
||||
HY_PD013_PARAMETER_RESET,
|
||||
HY_PD014_ACCEL_TIME_1,
|
||||
HY_PD015_DECEL_TIME_1,
|
||||
HY_PD016_ACCEL_TIME_2,
|
||||
HY_PD017_DECEL_TIME_2,
|
||||
HY_PD018_ACCEL_TIME_3,
|
||||
HY_PD019_DECEL_TIME_3,
|
||||
HY_PD020_ACCEL_TIME_4,
|
||||
HY_PD021_DECEL_TIME_4,
|
||||
HY_PD022_FACTORY_RESERVED,
|
||||
HY_PD023_REV_ROTATION_SELECT,
|
||||
HY_PD024_STOP_KEY,
|
||||
HY_PD025_STARTING_MODE,
|
||||
HY_PD026_STOPPING_MODE,
|
||||
HY_PD027_STARTING_FREQUENCY,
|
||||
HY_PD028_STOPPING_FREQUENCY,
|
||||
HY_PD029_DC_BRAKING_TIME_AT_START,
|
||||
HY_PD030_DC_BRAKING_TIME_AT_STOP,
|
||||
HY_PD031_DC_BRAKING_VOLTAGE_LEVEL,
|
||||
HY_PD032_FREQUENCY_TRACK_TIME,
|
||||
HY_PD033_CURRENT_LEVEL_FOR_FREQUENCY_TRACK,
|
||||
HY_PD034_VOLTAGE_RISE_TIME_FOR_FREQUENCY_TRACK,
|
||||
HY_PD035_FREQUENCY_STEP_LENGTH,
|
||||
HY_PD036,
|
||||
HY_PD037,
|
||||
HY_PD038,
|
||||
HY_PD039,
|
||||
HY_PD040,
|
||||
HY_PD041_CARRIER_FREQUENCY,
|
||||
HY_PD042_JOGGING_FREQUENCY,
|
||||
HY_PD043_S_CURVE_TIME,
|
||||
HY_PD044_MULTI_INPUT_FOR,
|
||||
HY_PD045_MULTI_INPUT_REV,
|
||||
HY_PD046_MULTI_INPUT_RST,
|
||||
HY_PD047_MULTI_INPUT_SPH,
|
||||
HY_PD048_MULTI_INPUT_SPM,
|
||||
HY_PD049_MULTI_INPUT_SPL,
|
||||
HY_PD050_MULTI_OUTPUT_DRV,
|
||||
HY_PD051_MULTI_OUTPUT_UPF,
|
||||
HY_PD052_MULTI_OUTPUT_FA_FB_FC,
|
||||
HY_PD053_MULTI_OUTPUT_KA_KB,
|
||||
HY_PD054_MULTI_OUTPUT_AM,
|
||||
HY_PD055_AM_ANALOG_OUTPUT_GAIN,
|
||||
HY_PD056_SKIP_FREQUENCY_1,
|
||||
HY_PD057_SKIP_FREQUENCY_2,
|
||||
HY_PD058_SKIP_FREQUENCY_3,
|
||||
HY_PD059_SKIP_FREQUENCY_RANGE,
|
||||
HY_PD060_UNIFORM_FREQUENCY_1,
|
||||
HY_PD061_UNIFORM_FREQUENCY_2,
|
||||
HY_PD062_UNIFORM_FREQUENCY_RANGE,
|
||||
HY_PD063_TIMER_1_TIME,
|
||||
HY_PD064_TIMER_2_TIME,
|
||||
HY_PD065_COUNTING_VALUE,
|
||||
HY_PD066_INTERMEDIATE_COUNTER,
|
||||
HY_PD067,
|
||||
HY_PD068,
|
||||
HY_PD069,
|
||||
HY_PD070_ANALOG_INPUT,
|
||||
HY_PD071_ANALOG_FILTERING_CONSTANT,
|
||||
HY_PD072_HIGHER_ANALOG_FREQUENCY,
|
||||
HY_PD073_LOWER_ANALOG_FREQUENCY,
|
||||
HY_PD074_BIAS_DIRECTION_AT_HIGHER_FREQUENCY,
|
||||
HY_PD075_BIAS_DIRECTION_AT_LOWER_FREQUENCY,
|
||||
HY_PD076_ANALOG_NEGATIVE_BIAS_REVERSE,
|
||||
HY_PD077_UP_DOWN_FUNCTION,
|
||||
HY_PD078_UP_DOWN_SPEED,
|
||||
HY_PD079,
|
||||
HY_PD080_PLC_OPERATION,
|
||||
HY_PD081_AUTO_PLC,
|
||||
HY_PD082_PLC_RUNNING_DIRECTION,
|
||||
HY_PD083,
|
||||
HY_PD084_PLC_RAMP_TIME,
|
||||
HY_PD085,
|
||||
HY_PD086_FREQUENCY_2,
|
||||
HY_PD087_FREQUENCY_3,
|
||||
HY_PD088_FREQUENCY_4,
|
||||
HY_PD089_FREQUENCY_5,
|
||||
HY_PD090_FREQUENCY_6,
|
||||
HY_PD091_FREQUENCY_7,
|
||||
HY_PD092_FREQUENCY_8,
|
||||
HY_PD093,
|
||||
HY_PD094,
|
||||
HY_PD095,
|
||||
HY_PD096,
|
||||
HY_PD097,
|
||||
HY_PD098,
|
||||
HY_PD099,
|
||||
HY_PD100,
|
||||
HY_PD101_TIMER_1,
|
||||
HY_PD102_TIMER_2,
|
||||
HY_PD103_TIMER_3,
|
||||
HY_PD104_TIMER_4,
|
||||
HY_PD105_TIMER_5,
|
||||
HY_PD106_TIMER_6,
|
||||
HY_PD107_TIMER_7,
|
||||
HY_PD108_TIMER_8,
|
||||
HY_PD109,
|
||||
HY_PD110,
|
||||
HY_PD111,
|
||||
HY_PD112,
|
||||
HY_PD113,
|
||||
HY_PD114,
|
||||
HY_PD115,
|
||||
HY_PD116,
|
||||
HY_PD117_AUTOPLC_MEMORY_FUNCTION,
|
||||
HY_PD118_OVER_VOLTAGE_STALL_PREVENTION,
|
||||
HY_PD119_STALL_PREVENTION_LEVEL_AT_RAMP_UP,
|
||||
HY_PD120_STALL_PREVENTION_LEVEL_AT_CONSTANT_SPEED,
|
||||
HY_PD121_DECEL_TIME_FOR_STALL_PREVENTION_AT_CONSTANT_SPEED,
|
||||
HY_PD122_STALL_PREVENTION_LEVEL_AT_DECELERATION,
|
||||
HY_PD123_OVER_TORQUE_DETECT_MODE,
|
||||
HY_PD124_OVER_TORQUE_DETECT_LEVEL,
|
||||
HY_PD125_OVER_TORQUE_DETECT_TIME,
|
||||
HY_PD126,
|
||||
HY_PD127,
|
||||
HY_PD128,
|
||||
HY_PD129,
|
||||
HY_PD130_NUMBER_OF_AUXILIARY_PUMP,
|
||||
HY_PD131_CONTINUOUS_RUNNING_TIME_OF_AUXILIARY_PUMPS,
|
||||
HY_PD132_INTERLOCKING_TIME_OF_AUXILIARY_PUMP,
|
||||
HY_PD133_HIGH_SPEED_RUNNING_TIME,
|
||||
HY_PD134_LOW_SPEED_RUNNING_TIME,
|
||||
HY_PD135_STOPPING_VOLTAGE_LEVEL,
|
||||
HY_PD136_LASTING_TIME_OF_STOPPING_VOLTAGE_LEVEL,
|
||||
HY_PD137_WAKEUP_VOLTAGE_LEVEL,
|
||||
HY_PD138_SLEEP_FREQUENCY,
|
||||
HY_PD139_LASTING_TIME_OF_SLEEP_FREQUENCY,
|
||||
HY_PD140,
|
||||
HY_PD141_RATED_MOTOR_VOLTAGE,
|
||||
HY_PD142_RATED_MOTOR_CURRENT,
|
||||
HY_PD143_MOTOR_POLE_NUMBER,
|
||||
HY_PD144_RATED_MOTOR_RPM,
|
||||
HY_PD145_AUTO_TORQUE_COMPENSATION,
|
||||
HY_PD146_MOTOR_NO_LOAD_CURRENT,
|
||||
HY_PD147_MOTOR_SLIP_COMPENSATION,
|
||||
HY_PD148,
|
||||
HY_PD149,
|
||||
HY_PD150_AUTO_VOLTAGE_REGULATION,
|
||||
HY_PD151_AUTO_ENERGY_SAVING,
|
||||
HY_PD152_FAULT_RESTART_TIME,
|
||||
HY_PD153_RESTART_AFTER_INSTANTANEOUS_STOP,
|
||||
HY_PD154_ALLOWABLE_POWER_BREAKDOWN_TIME,
|
||||
HY_PD155_NUMBER_OF_ABNORMAL_RESTART,
|
||||
HY_PD156_PROPORTIONAL_CONSTANT,
|
||||
HY_PD157_INTEGRAL_TIME,
|
||||
HY_PD158_DIFFERENTIAL_TIME,
|
||||
HY_PD159_TARGET_VALUE,
|
||||
HY_PD160_PID_TARGET_VALUE,
|
||||
HY_PD161_PID_UPPER_LIMIT,
|
||||
HY_PD162_PID_LOWER_LIMIT,
|
||||
HY_PD163_COMMUNICATION_ADDRESSES,
|
||||
HY_PD164_COMMUNICATION_BAUD_RATE,
|
||||
HY_PD165_COMMUNICATION_DATA_METHOD,
|
||||
HY_PD166,
|
||||
HY_PD167,
|
||||
HY_PD168,
|
||||
HY_PD169,
|
||||
HY_PD170_DISPLAY_ITEMS,
|
||||
HY_PD171_DISPLAY_ITEMS_OPEN,
|
||||
HY_PD172_FAULT_CLEAR,
|
||||
HY_PD173,
|
||||
HY_PD174_RATED_CURRENT_OF_INVERTER,
|
||||
HY_PD175_INVERTER_MODEL,
|
||||
HY_PD176_INVERTER_FREQUENCY_STANDARD,
|
||||
HY_PD177_FAULT_RECORD_1,
|
||||
HY_PD178_FAULT_RECORD_2,
|
||||
HY_PD179_FAULT_RECORD_3,
|
||||
HY_PD180_FAULT_RECORD_4,
|
||||
HY_PD181_SOFTWARE_VERSION,
|
||||
HY_PD182_MANUFACTURE_DATE,
|
||||
HY_PD183_SERIAL_NO,
|
||||
} hy_addr_t;
|
||||
129
src/avr/src/i2c.c
Normal file
129
src/avr/src/i2c.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
i2c_read_cb_t read_cb;
|
||||
i2c_write_cb_t write_cb;
|
||||
uint8_t data[I2C_MAX_DATA + 1];
|
||||
uint8_t length;
|
||||
bool done;
|
||||
bool write;
|
||||
} i2c_t;
|
||||
|
||||
static i2c_t i2c = {0};
|
||||
|
||||
|
||||
static void _i2c_reset_command() {
|
||||
i2c.length = 0;
|
||||
i2c.done = true;
|
||||
i2c.write = false;
|
||||
}
|
||||
|
||||
|
||||
static void _i2c_end_command() {
|
||||
if (i2c.length && !i2c.write && i2c.read_cb) {
|
||||
i2c.data[i2c.length] = 0; // Null terminate
|
||||
i2c.read_cb(i2c.data, i2c.length);
|
||||
}
|
||||
|
||||
_i2c_reset_command();
|
||||
}
|
||||
|
||||
|
||||
static void _i2c_command_byte(uint8_t byte) {
|
||||
i2c.data[i2c.length++] = byte;
|
||||
}
|
||||
|
||||
|
||||
ISR(I2C_ISR) {
|
||||
uint8_t status = I2C_DEV.SLAVE.STATUS;
|
||||
|
||||
// Error or collision
|
||||
if (status & (TWI_SLAVE_BUSERR_bm | TWI_SLAVE_COLL_bm)) {
|
||||
_i2c_reset_command();
|
||||
return; // Ignore
|
||||
|
||||
} else if ((status & TWI_SLAVE_APIF_bm) && (status & TWI_SLAVE_AP_bm)) {
|
||||
// START + address match
|
||||
I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; // ACK address byte
|
||||
_i2c_end_command(); // Handle repeated START
|
||||
|
||||
} else if (status & TWI_SLAVE_APIF_bm) {
|
||||
// STOP
|
||||
I2C_DEV.SLAVE.STATUS = TWI_SLAVE_APIF_bm; // Clear interrupt flag
|
||||
_i2c_end_command();
|
||||
|
||||
} else if (status & TWI_SLAVE_DIF_bm) {
|
||||
i2c.write = status & TWI_SLAVE_DIR_bm;
|
||||
|
||||
// DATA
|
||||
if (i2c.write) { // Write
|
||||
// Check if master ACKed last byte sent
|
||||
if (i2c.length && (status & TWI_SLAVE_RXACK_bm || i2c.done))
|
||||
I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; // End transaction
|
||||
|
||||
else {
|
||||
// Send some data
|
||||
i2c.done = false;
|
||||
I2C_DEV.SLAVE.DATA = i2c.write_cb(i2c.length++, &i2c.done);
|
||||
I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; // Continue transaction
|
||||
}
|
||||
|
||||
} else { // Read
|
||||
_i2c_command_byte(I2C_DEV.SLAVE.DATA);
|
||||
|
||||
// ACK and continue transaction
|
||||
I2C_DEV.SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t _i2c_default_write_cb(uint8_t offset, bool *done) {
|
||||
*done = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void i2c_init() {
|
||||
i2c_set_write_callback(_i2c_default_write_cb);
|
||||
|
||||
I2C_DEV.SLAVE.CTRLA = TWI_SLAVE_INTLVL_LO_gc | TWI_SLAVE_DIEN_bm |
|
||||
TWI_SLAVE_ENABLE_bm | TWI_SLAVE_APIEN_bm | TWI_SLAVE_PIEN_bm;
|
||||
I2C_DEV.SLAVE.ADDR = I2C_ADDR << 1;
|
||||
}
|
||||
|
||||
|
||||
void i2c_set_read_callback(i2c_read_cb_t cb) {i2c.read_cb = cb;}
|
||||
void i2c_set_write_callback(i2c_write_cb_t cb) {i2c.write_cb = cb;}
|
||||
41
src/avr/src/i2c.h
Normal file
41
src/avr/src/i2c.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef void (*i2c_read_cb_t)(uint8_t *data, uint8_t length);
|
||||
typedef uint8_t (*i2c_write_cb_t)(uint8_t offset, bool *done);
|
||||
|
||||
|
||||
void i2c_init();
|
||||
void i2c_set_read_callback(i2c_read_cb_t cb);
|
||||
void i2c_set_write_callback(i2c_write_cb_t cb);
|
||||
118
src/avr/src/io.c
Normal file
118
src/avr/src/io.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "io.h"
|
||||
|
||||
#include "status.h"
|
||||
#include "util.h"
|
||||
#include "command.h"
|
||||
#include "exec.h"
|
||||
#include "rtc.h"
|
||||
#include "analog.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
int8_t port;
|
||||
bool digital;
|
||||
input_mode_t mode;
|
||||
float timeout;
|
||||
} input_cmd_t;
|
||||
|
||||
|
||||
static input_cmd_t active_cmd = {-1,};
|
||||
static uint32_t timeout;
|
||||
|
||||
|
||||
void io_callback() {
|
||||
if (active_cmd.port == -1) return;
|
||||
|
||||
bool done = false;
|
||||
float result = 0;
|
||||
if (active_cmd.mode == INPUT_IMMEDIATE || rtc_expired(timeout)) done = true;
|
||||
|
||||
// TODO handle modes
|
||||
|
||||
if (done) {
|
||||
if (active_cmd.digital) { // TODO
|
||||
} else result = analog_get(active_cmd.port);
|
||||
|
||||
printf_P(PSTR("{\"result\": %f}\n"), (double)result);
|
||||
active_cmd.port = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static stat_t _exec_cb() {
|
||||
if (active_cmd.port == -1) exec_set_cb(0);
|
||||
return STAT_NOP;
|
||||
}
|
||||
|
||||
|
||||
// Command callbacks
|
||||
stat_t command_input(char *cmd) {
|
||||
input_cmd_t input_cmd;
|
||||
cmd++; // Skip command
|
||||
|
||||
// Analog or digital
|
||||
if (*cmd == 'd') input_cmd.digital = true;
|
||||
else if (*cmd == 'a') input_cmd.digital = false;
|
||||
else return STAT_INVALID_ARGUMENTS;
|
||||
cmd++;
|
||||
|
||||
// Port index
|
||||
if (!isdigit(*cmd)) return STAT_INVALID_ARGUMENTS;
|
||||
input_cmd.port = *cmd - '0';
|
||||
cmd++;
|
||||
|
||||
// Mode
|
||||
if (!isdigit(*cmd)) return STAT_INVALID_ARGUMENTS;
|
||||
input_cmd.mode = (input_mode_t)(*cmd - '0');
|
||||
if (INPUT_LOW < input_cmd.mode) return STAT_INVALID_ARGUMENTS;
|
||||
cmd++;
|
||||
|
||||
// Timeout
|
||||
if (!decode_float(&cmd, &input_cmd.timeout)) return STAT_BAD_FLOAT;
|
||||
|
||||
command_push(COMMAND_input, &input_cmd);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
unsigned command_input_size() {return sizeof(input_cmd_t);}
|
||||
|
||||
|
||||
void command_input_exec(void *data) {
|
||||
active_cmd = *(input_cmd_t *)data;
|
||||
|
||||
timeout = rtc_get_time() + active_cmd.timeout * 1000;
|
||||
exec_set_cb(_exec_cb);
|
||||
}
|
||||
40
src/avr/src/io.h
Normal file
40
src/avr/src/io.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
typedef enum {
|
||||
INPUT_IMMEDIATE,
|
||||
INPUT_RISE,
|
||||
INPUT_FALL,
|
||||
INPUT_HIGH,
|
||||
INPUT_LOW,
|
||||
} input_mode_t;
|
||||
|
||||
|
||||
void io_callback();
|
||||
169
src/avr/src/jog.c
Normal file
169
src/avr/src/jog.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "jog.h"
|
||||
|
||||
#include "axis.h"
|
||||
#include "util.h"
|
||||
#include "exec.h"
|
||||
#include "state.h"
|
||||
#include "command.h"
|
||||
#include "config.h"
|
||||
#include "SCurve.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool holding;
|
||||
bool writing;
|
||||
|
||||
SCurve scurves[AXES];
|
||||
float next[AXES];
|
||||
float targetV[AXES];
|
||||
} jr_t;
|
||||
|
||||
jr_t jr = {0};
|
||||
|
||||
|
||||
stat_t jog_exec() {
|
||||
bool done = true;
|
||||
|
||||
// Compute per axis velocities and target positions
|
||||
float target[AXES] = {0,};
|
||||
float velocity_sqr = 0;
|
||||
|
||||
for (int axis = 0; axis < AXES; axis++) {
|
||||
if (!axis_is_enabled(axis)) continue;
|
||||
|
||||
// Load next velocity
|
||||
if (!jr.writing)
|
||||
jr.targetV[axis] = jr.next[axis] * axis_get_velocity_max(axis);
|
||||
|
||||
float p = exec_get_axis_position(axis);
|
||||
float vel = jr.scurves[axis].getVelocity();
|
||||
float targetV = jr.targetV[axis];
|
||||
float min = axis_get_soft_limit(axis, true);
|
||||
float max = axis_get_soft_limit(axis, false);
|
||||
bool softLimited = min != max && axis_get_homed(axis);
|
||||
|
||||
// Apply soft limits, if enabled and homed
|
||||
if (softLimited && MIN_VELOCITY < fabs(targetV)) {
|
||||
float dist = jr.scurves[axis].getStoppingDist() *
|
||||
(1 + (JOG_STOPPING_UNDERSHOOT / 100.0));
|
||||
|
||||
if (vel < 0 && p - dist <= min) targetV = -MIN_VELOCITY;
|
||||
if (0 < vel && max <= p + dist) targetV = MIN_VELOCITY;
|
||||
}
|
||||
|
||||
// Compute next velocity
|
||||
float v = jr.scurves[axis].next(SEGMENT_TIME, targetV);
|
||||
|
||||
// Don't overshoot soft limits
|
||||
float deltaP = v * SEGMENT_TIME;
|
||||
if (softLimited && 0 < deltaP && max < p + deltaP) p = max;
|
||||
else if (softLimited && deltaP < 0 && p + deltaP < min) p = min;
|
||||
else p += deltaP;
|
||||
|
||||
// Not done jogging if still moving
|
||||
if (MIN_VELOCITY < fabs(v) || MIN_VELOCITY < fabs(targetV)) done = false;
|
||||
|
||||
velocity_sqr += square(v);
|
||||
target[axis] = p;
|
||||
}
|
||||
|
||||
// Check if we are done
|
||||
if (done) {
|
||||
command_reset_position();
|
||||
exec_set_velocity(0);
|
||||
exec_set_cb(0);
|
||||
if (jr.holding) state_holding();
|
||||
else state_idle();
|
||||
|
||||
return STAT_NOP; // Done, no move executed
|
||||
}
|
||||
|
||||
// Set velocity and target
|
||||
exec_set_velocity(sqrt(velocity_sqr));
|
||||
exec_move_to_target(target);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
void jog_stop() {
|
||||
if (state_get() != STATE_JOGGING) return;
|
||||
jr.writing = true;
|
||||
for (int axis = 0; axis < AXES; axis++) jr.next[axis] = 0;
|
||||
jr.writing = false;
|
||||
}
|
||||
|
||||
|
||||
stat_t command_jog(char *cmd) {
|
||||
// Ignore jog commands when not READY, HOLDING or JOGGING
|
||||
if (state_get() != STATE_READY && state_get() != STATE_HOLDING &&
|
||||
state_get() != STATE_JOGGING)
|
||||
return STAT_NOP;
|
||||
|
||||
// Skip over command code
|
||||
cmd++;
|
||||
|
||||
// Get velocities
|
||||
float velocity[AXES] = {0,};
|
||||
stat_t status = decode_axes(&cmd, velocity);
|
||||
if (status) return status;
|
||||
|
||||
// Check for end of command
|
||||
if (*cmd) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Start jogging
|
||||
if (state_get() != STATE_JOGGING) {
|
||||
memset(&jr, 0, sizeof(jr));
|
||||
|
||||
jr.holding = state_get() == STATE_HOLDING;
|
||||
|
||||
for (int axis = 0; axis < AXES; axis++)
|
||||
if (axis_is_enabled(axis))
|
||||
jr.scurves[axis] =
|
||||
SCurve(axis_get_velocity_max(axis), axis_get_accel_max(axis),
|
||||
axis_get_jerk_max(axis));
|
||||
|
||||
state_jogging();
|
||||
exec_set_cb(jog_exec);
|
||||
}
|
||||
|
||||
// Set next velocities
|
||||
jr.writing = true;
|
||||
for (int axis = 0; axis < AXES; axis++) jr.next[axis] = velocity[axis];
|
||||
jr.writing = false;
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
34
src/avr/src/jog.h
Normal file
34
src/avr/src/jog.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "status.h"
|
||||
|
||||
|
||||
stat_t jog_exec();
|
||||
void jog_stop();
|
||||
143
src/avr/src/lcd.c
Normal file
143
src/avr/src/lcd.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "lcd.h"
|
||||
#include "rtc.h"
|
||||
#include "hardware.h"
|
||||
#include "command.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
void lcd_init(uint8_t addr) {
|
||||
// Enable I2C master
|
||||
TWIC.MASTER.BAUD = F_CPU / 2 / 100000 - 5; // 100 KHz
|
||||
TWIC.MASTER.CTRLA = TWI_MASTER_ENABLE_bm;
|
||||
TWIC.MASTER.CTRLB = TWI_MASTER_TIMEOUT_DISABLED_gc;
|
||||
TWIC.MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc;
|
||||
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
_delay_ms(50);
|
||||
lcd_nibble(addr, 3 << 4); // Home
|
||||
lcd_nibble(addr, 2 << 4); // 4-bit
|
||||
|
||||
lcd_write(addr,
|
||||
LCD_FUNCTION_SET | LCD_2_LINE | LCD_5x8_DOTS | LCD_4_BIT_MODE, 0);
|
||||
lcd_write(addr, LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON, 0);
|
||||
lcd_write(addr, LCD_ENTRY_MODE_SET | LCD_ENTRY_SHIFT_INC, 0);
|
||||
|
||||
lcd_write(addr, LCD_CLEAR_DISPLAY, 0);
|
||||
lcd_write(addr, LCD_RETURN_HOME, 0);
|
||||
}
|
||||
|
||||
|
||||
static void _master_wait() {
|
||||
#ifdef __AVR__
|
||||
while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm)) continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void _write_i2c(uint8_t addr, uint8_t data) {
|
||||
data |= BACKLIGHT_BIT;
|
||||
|
||||
TWIC.MASTER.ADDR = addr << 1;
|
||||
_master_wait();
|
||||
|
||||
TWIC.MASTER.DATA = data;
|
||||
_master_wait();
|
||||
|
||||
TWIC.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc;
|
||||
|
||||
_delay_us(100);
|
||||
}
|
||||
|
||||
|
||||
void lcd_nibble(uint8_t addr, uint8_t data) {
|
||||
_write_i2c(addr, data);
|
||||
_write_i2c(addr, data | ENABLE_BIT);
|
||||
_delay_us(500);
|
||||
_write_i2c(addr, data & ~ENABLE_BIT);
|
||||
_delay_us(100);
|
||||
}
|
||||
|
||||
|
||||
void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags) {
|
||||
lcd_nibble(addr, flags | (cmd & 0xf0));
|
||||
lcd_nibble(addr, flags | ((cmd << 4) & 0xf0));
|
||||
}
|
||||
|
||||
|
||||
void lcd_goto(uint8_t addr, uint8_t x, uint8_t y) {
|
||||
static uint8_t row[] = {0, 64, 20, 84};
|
||||
lcd_write(addr, LCD_SET_DDRAM_ADDR | (row[y] + x), 0);
|
||||
}
|
||||
|
||||
|
||||
void lcd_putchar(uint8_t addr, uint8_t c) {
|
||||
lcd_write(addr, c, REG_SELECT_BIT);
|
||||
}
|
||||
|
||||
|
||||
void lcd_pgmstr(uint8_t addr, const char *s) {
|
||||
while (true) {
|
||||
char c = pgm_read_byte(s++);
|
||||
if (!c) break;
|
||||
lcd_putchar(addr, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _splash(uint8_t addr) {
|
||||
lcd_init(addr);
|
||||
lcd_goto(addr, 1, 1);
|
||||
lcd_pgmstr(addr, PSTR("Controller booting"));
|
||||
lcd_goto(addr, 3, 2);
|
||||
lcd_pgmstr(addr, PSTR("Please wait..."));
|
||||
}
|
||||
|
||||
|
||||
void lcd_splash() {
|
||||
wdt_disable();
|
||||
_splash(0x27);
|
||||
_splash(0x3f);
|
||||
wdt_enable(WDTO_250MS);
|
||||
}
|
||||
|
||||
|
||||
void lcd_rtc_callback() {
|
||||
// Display the splash if we haven't gotten any commands in 1sec since boot
|
||||
if (!command_is_active() && rtc_get_time() == 1000)
|
||||
lcd_splash();
|
||||
}
|
||||
103
src/avr/src/lcd.h
Normal file
103
src/avr/src/lcd.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pgmspace.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// Control flags
|
||||
enum {
|
||||
REG_SELECT_BIT = 1 << 0,
|
||||
READ_BIT = 1 << 1,
|
||||
ENABLE_BIT = 1 << 2,
|
||||
BACKLIGHT_BIT = 1 << 3,
|
||||
};
|
||||
|
||||
|
||||
// Commands
|
||||
enum {
|
||||
LCD_CLEAR_DISPLAY = 1 << 0,
|
||||
LCD_RETURN_HOME = 1 << 1,
|
||||
LCD_ENTRY_MODE_SET = 1 << 2,
|
||||
LCD_DISPLAY_CONTROL = 1 << 3,
|
||||
LCD_CURSOR_SHIFT = 1 << 4,
|
||||
LCD_FUNCTION_SET = 1 << 5,
|
||||
LCD_SET_CGRAM_ADDR = 1 << 6,
|
||||
LCD_SET_DDRAM_ADDR = 1 << 7,
|
||||
};
|
||||
|
||||
|
||||
// Entry Mode Set flags
|
||||
#define LCD_ENTRY_SHIFT_DISPLAY (1 << 0)
|
||||
#define LCD_ENTRY_SHIFT_INC (1 << 1)
|
||||
#define LCD_ENTRY_SHIFT_DEC (0 << 1)
|
||||
|
||||
|
||||
// Display Control flags
|
||||
#define LCD_BLINK_ON (1 << 0)
|
||||
#define LCD_BLINK_OFF (0 << 0)
|
||||
#define LCD_CURSOR_ON (1 << 1)
|
||||
#define LCD_CURSOR_OFF (0 << 1)
|
||||
#define LCD_DISPLAY_ON (1 << 2)
|
||||
#define LCD_DISPLAY_OFF (0 << 2)
|
||||
|
||||
|
||||
// Cursor Shift flags
|
||||
#define LCD_SHIFT_RIGHT (1 << 2)
|
||||
#define LCD_SHIFT_LEFT (0 << 2)
|
||||
#define LCD_SHIFT_DISPLAY (1 << 3)
|
||||
#define LCD_SHIFT_CURSOR (0 << 3)
|
||||
|
||||
|
||||
// Function Set flags
|
||||
#define LCD_5x11_DOTS (1 << 2)
|
||||
#define LCD_5x8_DOTS (0 << 2)
|
||||
#define LCD_2_LINE (1 << 3)
|
||||
#define LCD_1_LINE (0 << 3)
|
||||
#define LCD_8_BIT_MODE (1 << 4)
|
||||
#define LCD_4_BIT_MODE (0 << 4)
|
||||
|
||||
|
||||
// Text justification flags
|
||||
enum {
|
||||
JUSTIFY_LEFT = 0,
|
||||
JUSTIFY_RIGHT = 1,
|
||||
JUSTIFY_CENTER = 2,
|
||||
};
|
||||
|
||||
|
||||
void lcd_init(uint8_t addr);
|
||||
void lcd_nibble(uint8_t addr, uint8_t data);
|
||||
void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags);
|
||||
void lcd_goto(uint8_t addr, uint8_t x, uint8_t y);
|
||||
void lcd_putchar(uint8_t addr, uint8_t c);
|
||||
void lcd_pgmstr(uint8_t addr, const char *s);
|
||||
void lcd_splash();
|
||||
void lcd_rtc_callback();
|
||||
274
src/avr/src/line.c
Normal file
274
src/avr/src/line.c
Normal file
@@ -0,0 +1,274 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
#include "exec.h"
|
||||
#include "command.h"
|
||||
#include "spindle.h"
|
||||
#include "util.h"
|
||||
#include "SCurve.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
float start[AXES];
|
||||
float target[AXES];
|
||||
float times[7];
|
||||
float target_vel;
|
||||
float max_accel;
|
||||
float max_jerk;
|
||||
|
||||
float unit[AXES];
|
||||
float length;
|
||||
} line_t;
|
||||
|
||||
|
||||
static struct {
|
||||
line_t line;
|
||||
|
||||
int section;
|
||||
int seg;
|
||||
|
||||
float iD; // Initial section distance
|
||||
float iV; // Initial section velocity
|
||||
float iA; // Initial section acceleration
|
||||
float jerk;
|
||||
float lV; // Last velocity
|
||||
float lD; // Last distance
|
||||
|
||||
power_update_t power_updates[POWER_MAX_UPDATES];
|
||||
} l;
|
||||
|
||||
|
||||
static void _segment_target(float target[AXES], float d) {
|
||||
for (int axis = 0; axis < AXES; axis++)
|
||||
target[axis] = l.line.start[axis] + l.line.unit[axis] * d;
|
||||
}
|
||||
|
||||
|
||||
static float _segment_distance(float t) {
|
||||
return l.iD + SCurve::distance(t, l.iV, l.iA, l.jerk);
|
||||
}
|
||||
|
||||
|
||||
static float _segment_velocity(float t) {
|
||||
return l.iV + SCurve::velocity(t, l.iA, l.jerk);
|
||||
}
|
||||
|
||||
|
||||
static float _segment_accel(float t) {
|
||||
return l.iA + SCurve::acceleration(t, l.jerk);
|
||||
}
|
||||
|
||||
|
||||
static bool _section_next() {
|
||||
while (++l.section < 7) {
|
||||
if (!l.line.times[l.section]) continue;
|
||||
|
||||
// Jerk
|
||||
switch (l.section) {
|
||||
case 0: case 6: l.jerk = l.line.max_jerk; break;
|
||||
case 2: case 4: l.jerk = -l.line.max_jerk; break;
|
||||
default: l.jerk = 0;
|
||||
}
|
||||
exec_set_jerk(l.jerk);
|
||||
|
||||
// Acceleration
|
||||
switch (l.section) {
|
||||
case 1: case 2: l.iA = l.line.max_jerk * l.line.times[0]; break;
|
||||
case 5: case 6: l.iA = -l.line.max_jerk * l.line.times[4]; break;
|
||||
default: l.iA = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static stat_t _exec_segment(float time, const float target[], float vel,
|
||||
float accel) {
|
||||
return exec_segment(time, target, vel, accel, l.line.max_accel,
|
||||
l.line.max_jerk, l.power_updates);
|
||||
}
|
||||
|
||||
|
||||
static stat_t _line_exec() {
|
||||
// Compute times
|
||||
float section_time = l.line.times[l.section];
|
||||
float seg_time = SEGMENT_TIME;
|
||||
float t = ++l.seg * SEGMENT_TIME;
|
||||
|
||||
// Don't exceed section time
|
||||
if (section_time < t) {
|
||||
seg_time = section_time - (l.seg - 1) * SEGMENT_TIME;
|
||||
t = section_time;
|
||||
}
|
||||
|
||||
// Compute distance and velocity
|
||||
float d = _segment_distance(t);
|
||||
float v = _segment_velocity(t);
|
||||
float a = _segment_accel(t);
|
||||
|
||||
// Don't allow overshoot
|
||||
if (l.line.length < d) d = l.line.length;
|
||||
|
||||
// Handle synchronous speeds
|
||||
spindle_load_power_updates(l.power_updates, l.lD, d);
|
||||
l.lD = d;
|
||||
|
||||
// Check if section complete
|
||||
if (t == section_time) {
|
||||
if (_section_next()) {
|
||||
// Setup next section
|
||||
l.seg = 0;
|
||||
l.iD = d;
|
||||
l.iV = v;
|
||||
|
||||
} else {
|
||||
exec_set_cb(0);
|
||||
|
||||
// Last segment of last section
|
||||
// Use exact target values to correct for floating-point errors
|
||||
return _exec_segment(seg_time, l.line.target, l.line.target_vel, a);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute target position from distance
|
||||
float target[AXES];
|
||||
_segment_target(target, d);
|
||||
|
||||
// Segment move
|
||||
return _exec_segment(seg_time, target, v, a);
|
||||
}
|
||||
|
||||
|
||||
stat_t command_line(char *cmd) {
|
||||
line_t line = {};
|
||||
|
||||
cmd++; // Skip command code
|
||||
|
||||
// Get start position
|
||||
command_get_position(line.start);
|
||||
|
||||
// Get target velocity
|
||||
if (!decode_float(&cmd, &line.target_vel)) return STAT_BAD_FLOAT;
|
||||
if (line.target_vel < 0) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Get max accel
|
||||
if (!decode_float(&cmd, &line.max_accel)) return STAT_BAD_FLOAT;
|
||||
if (line.max_accel < 0) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Get max jerk
|
||||
if (!decode_float(&cmd, &line.max_jerk)) return STAT_BAD_FLOAT;
|
||||
if (line.max_jerk < 0) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Get target position
|
||||
copy_vector(line.target, line.start);
|
||||
stat_t status = decode_axes(&cmd, line.target);
|
||||
if (status) return status;
|
||||
|
||||
// Get times
|
||||
bool has_time = false;
|
||||
while (*cmd) {
|
||||
if (*cmd < '0' || '6' < *cmd) break;
|
||||
int section = *cmd - '0';
|
||||
cmd++;
|
||||
|
||||
float time;
|
||||
if (!decode_float(&cmd, &time)) return STAT_BAD_FLOAT;
|
||||
|
||||
if (time < 0) return STAT_NEGATIVE_SCURVE_TIME;
|
||||
line.times[section] = time;
|
||||
if (time) has_time = true;
|
||||
}
|
||||
|
||||
if (!has_time) return STAT_ALL_ZERO_SCURVE_TIMES;
|
||||
|
||||
// Check for end of command
|
||||
if (*cmd) return STAT_INVALID_ARGUMENTS;
|
||||
|
||||
// Set next start position
|
||||
command_set_position(line.target);
|
||||
|
||||
// Compute direction vector
|
||||
for (int axis = 0; axis < AXES; axis++) {
|
||||
line.unit[axis] = line.target[axis] - line.start[axis];
|
||||
line.length += line.unit[axis] * line.unit[axis];
|
||||
}
|
||||
|
||||
line.length = sqrt(line.length);
|
||||
for (int axis = 0; axis < AXES; axis++)
|
||||
if (line.unit[axis]) line.unit[axis] /= line.length;
|
||||
|
||||
// Queue
|
||||
command_push(COMMAND_line, &line);
|
||||
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
|
||||
unsigned command_line_size() {return sizeof(line_t);}
|
||||
|
||||
|
||||
void command_line_exec(void *data) {
|
||||
l.line = *(line_t *)data;
|
||||
|
||||
// Setup first section
|
||||
l.seg = 0;
|
||||
l.iD = 0;
|
||||
l.lD = 0;
|
||||
// If current velocity is non-zero use last target velocity
|
||||
l.iV = exec_get_velocity() ? l.lV : 0;
|
||||
l.lV = l.line.target_vel;
|
||||
|
||||
// Find first section
|
||||
l.section = -1;
|
||||
if (!_section_next()) return;
|
||||
|
||||
#if 0
|
||||
// Compare start position to actual position
|
||||
float diff[AXES];
|
||||
bool report = false;
|
||||
exec_get_position(diff);
|
||||
for (int i = 0; i < AXES; i++) {
|
||||
diff[i] -= l.line.start[i];
|
||||
if (0.1 < fabs(diff[i])) report = true;
|
||||
}
|
||||
|
||||
if (report)
|
||||
STATUS_DEBUG("diff: %.4f %.4f %.4f %.4f",
|
||||
diff[0], diff[1], diff[2], diff[3]);
|
||||
#endif
|
||||
|
||||
// Set callback
|
||||
exec_set_cb(_line_exec);
|
||||
}
|
||||
101
src/avr/src/main.c
Normal file
101
src/avr/src/main.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
#include "hardware.h"
|
||||
#include "stepper.h"
|
||||
#include "motor.h"
|
||||
#include "switch.h"
|
||||
#include "usart.h"
|
||||
#include "drv8711.h"
|
||||
#include "vars.h"
|
||||
#include "rtc.h"
|
||||
#include "report.h"
|
||||
#include "command.h"
|
||||
#include "estop.h"
|
||||
#include "i2c.h"
|
||||
#include "pgmspace.h"
|
||||
#include "outputs.h"
|
||||
#include "analog.h"
|
||||
#include "modbus.h"
|
||||
#include "io.h"
|
||||
#include "exec.h"
|
||||
#include "state.h"
|
||||
#include "emu.h"
|
||||
|
||||
#include <avr/wdt.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
// For emu
|
||||
int __argc;
|
||||
char **__argv;
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
__argc = argc;
|
||||
__argv = argv;
|
||||
|
||||
wdt_enable(WDTO_250MS);
|
||||
|
||||
// Init
|
||||
cli(); // disable interrupts
|
||||
|
||||
emu_init(); // Init emulator
|
||||
hw_init(); // hardware setup - must be first
|
||||
outputs_init(); // output pins
|
||||
switch_init(); // switches
|
||||
estop_init(); // emergency stop handler
|
||||
analog_init(); // analog input pins
|
||||
usart_init(); // serial port
|
||||
i2c_init(); // i2c port
|
||||
drv8711_init(); // motor drivers
|
||||
stepper_init(); // steppers
|
||||
motor_init(); // motors
|
||||
exec_init(); // motion exec
|
||||
vars_init(); // configuration variables
|
||||
command_init(); // command queue
|
||||
|
||||
sei(); // enable interrupts
|
||||
|
||||
// Splash
|
||||
printf_P(PSTR("\n{\"firmware\":\"Buildbotics AVR\"}\n"));
|
||||
|
||||
// Main loop
|
||||
while (true) {
|
||||
emu_callback(); // Emulator callback
|
||||
hw_reset_handler(); // handle hard reset requests
|
||||
state_callback(); // manage state
|
||||
command_callback(); // process next command
|
||||
modbus_callback(); // handle modbus events
|
||||
io_callback(); // handle io input
|
||||
report_callback(); // report changes
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
62
src/avr/src/messages.def
Normal file
62
src/avr/src/messages.def
Normal file
@@ -0,0 +1,62 @@
|
||||
/******************************************************************************\
|
||||
|
||||
This file is part of the Buildbotics firmware.
|
||||
|
||||
Copyright (c) 2015 - 2018, Buildbotics LLC
|
||||
All rights reserved.
|
||||
|
||||
This file ("the software") is free software: you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License,
|
||||
version 2 as published by the Free Software Foundation. You should
|
||||
have received a copy of the GNU General Public License, version 2
|
||||
along with the software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
The software is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the software. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
For information regarding this software email:
|
||||
"Joseph Coffland" <joseph@buildbotics.com>
|
||||
|
||||
\******************************************************************************/
|
||||
|
||||
STAT_MSG(OK, "OK")
|
||||
STAT_MSG(AGAIN, "Run command again")
|
||||
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")
|
||||
STAT_MSG(TOO_MANY_ARGUMENTS, "Too many arguments")
|
||||
STAT_MSG(TOO_FEW_ARGUMENTS, "Too few arguments")
|
||||
STAT_MSG(MACHINE_ALARMED, "Machine alarmed - Command not processed")
|
||||
STAT_MSG(EXPECTED_MOVE, "A move expected but none queued")
|
||||
STAT_MSG(BAD_FLOAT, "Failed to parse float")
|
||||
STAT_MSG(BAD_INT, "Failed to parse integer")
|
||||
STAT_MSG(INVALID_VALUE, "Invalid value")
|
||||
STAT_MSG(INVALID_TYPE, "Invalid type")
|
||||
STAT_MSG(READ_ONLY, "Variable is read only")
|
||||
STAT_MSG(ALL_ZERO_SCURVE_TIMES, "All zero s-curve times")
|
||||
STAT_MSG(NEGATIVE_SCURVE_TIME, "Negative s-curve time")
|
||||
STAT_MSG(SEEK_NOT_ENABLED, "Switch not enabled")
|
||||
STAT_MSG(SEEK_NOT_FOUND, "Switch not found")
|
||||
STAT_MSG(MOTOR_ID_INVALID, "Invalid motor ID")
|
||||
STAT_MSG(MOTOR_NOT_PREPPED, "Motor move not prepped")
|
||||
STAT_MSG(MOTOR_NOT_READY, "Motor not ready for move")
|
||||
STAT_MSG(MOTOR_FAULT, "Motor fault")
|
||||
STAT_MSG(STEPPER_NULL_MOVE, "Null move in stepper driver")
|
||||
STAT_MSG(STEPPER_NOT_READY, "Stepper driver not ready for move")
|
||||
STAT_MSG(LONG_SEG_TIME, "Long segment time")
|
||||
STAT_MSG(MODBUS_BUF_LENGTH, "Modbus invalid buffer length")
|
||||
STAT_MSG(INVALID_QCMD, "Invalid command in queue")
|
||||
STAT_MSG(Q_OVERRUN, "Command queue overrun")
|
||||
STAT_MSG(Q_UNDERRUN, "Command queue underrun")
|
||||
STAT_MSG(Q_INVALID_PUSH, "Invalid command pushed to queue")
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user