├── .clang-format ├── .clang-tidy ├── .editorconfig ├── .github ├── bin │ ├── make-compilation-db.sh │ ├── run-clang-format.sh │ └── run-clang-tidy.sh └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── Development.md ├── G-code.md ├── INSTALL.md ├── LICENSE ├── Makefile ├── README.md ├── hardware ├── BUMPS │ ├── README.md │ ├── beagleg-pin-mapping.h │ ├── bumps.config │ ├── bumps.pins │ └── pru-io-routines.hp ├── CRAMPS │ ├── BeagleG-CRAMPS.dts │ ├── README.md │ ├── beagleg-pin-mapping.h │ ├── cramps.pins │ └── pru-io-routines.hp ├── Makefile ├── Pockegotion │ ├── README.md │ ├── beagleg-pin-mapping.h │ ├── pockegotion.pins │ └── pru-io-routines.hp ├── README.md ├── VGEN5 │ ├── README.md │ ├── beagleg-pin-mapping.h │ ├── pru-io-routines.hp │ ├── vgen5.config │ └── vgen5.pins ├── install-devicetree-overlay.sh ├── start-devicetree-overlay.sh └── template-pru-io-routines.hp ├── img ├── Makefile ├── beagleg-vid-thumb.jpg ├── bumps-connect.jpg ├── machine-control.dot ├── machine-control.svg ├── machine-origin.png ├── manual-ramps-cape.jpg ├── pockegotion.jpg ├── print-stats.dot ├── print-stats.svg ├── ramps-side.jpg ├── ramps-top.jpg ├── sample-gcode2ps-2.png ├── sample-gcode2ps-anim.gif ├── sample-gcode2ps-gcode-1.png ├── sample-gcode2ps-gcode.png ├── sample-gcode2ps-isometric.png ├── sample-gcode2ps-laser.png ├── sample-gcode2ps-topview.png ├── sample-gcode2ps.png ├── set-g55-update.png ├── set-g55.png └── test │ ├── coordinate-systems.png │ ├── rounded-bracket-parametrized.png │ ├── rounded-bracket-simple.png │ ├── spiral-cut.png │ ├── spline-character.png │ ├── spline-loop.png │ ├── splines.png │ ├── square-moves-direct.png │ └── superellipse.png ├── sample.config ├── shell.nix ├── src ├── .gitignore ├── Makefile ├── adc.cc ├── adc.h ├── common │ ├── Makefile │ ├── README.md │ ├── container.h │ ├── container_test.cc │ ├── fd-mux.cc │ ├── fd-mux.h │ ├── linebuf-reader.cc │ ├── linebuf-reader.h │ ├── linebuf-reader_test.cc │ ├── logging.cc │ ├── logging.h │ ├── string-util.cc │ ├── string-util.h │ └── string-util_test.cc ├── config-parser.cc ├── config-parser.h ├── config-parser_test.cc ├── determine-print-stats.cc ├── determine-print-stats.h ├── gcode-machine-control.cc ├── gcode-machine-control.h ├── gcode-machine-control_test.cc ├── gcode-parser │ ├── Makefile │ ├── README.md │ ├── arc-gen.cc │ ├── arc-gen_test.cc │ ├── gcode-parser-config.cc │ ├── gcode-parser.cc │ ├── gcode-parser.h │ ├── gcode-parser_test.cc │ ├── gcode-streamer.cc │ ├── gcode-streamer.h │ ├── gcode-streamer_test.cc │ ├── simple-lexer.cc │ ├── simple-lexer.h │ └── simple-lexer_test.cc ├── gcode-print-stats.cc ├── gcode2ps.cc ├── generic-gpio.cc ├── generic-gpio.h ├── hardware-mapping.cc ├── hardware-mapping.h ├── hershey.cc ├── hershey.h ├── idiv.hp ├── machine-control-config.cc ├── machine-control-config_test.cc ├── machine-control.cc ├── motion-queue-motor-operations.cc ├── motion-queue-motor-operations.h ├── motion-queue-motor-operations_test.cc ├── motion-queue.h ├── motor-interface-constants.h ├── motor-interface-pru.p ├── planner.cc ├── planner.h ├── planner_test.cc ├── pru-generic-io-routines.hp ├── pru-hardware-interface.h ├── pru-motion-queue.cc ├── pru-motion-queue_test.cc ├── pwm-timer.cc ├── pwm-timer.h ├── pwm-timer_test.cc ├── segment-queue.h ├── sim-audio-out.cc ├── sim-audio-out.h ├── sim-firmware.cc ├── sim-firmware.h ├── spindle-control.cc ├── spindle-control.h ├── test-create-html.sh ├── testdata │ ├── README.md │ ├── angle.gcode │ ├── circle.gcode │ ├── coordinate-systems.gcode │ ├── line-different-speeds.gcode │ ├── polygon-24-vs-arc.gcode │ ├── rounded-bracket-parametrized.gcode │ ├── rounded-bracket-simple.gcode │ ├── spiral-cut.gcode │ ├── spline-character.gcode │ ├── spline-loop.gcode │ ├── splines.gcode │ ├── square-moves-direct.gcode │ ├── square-moves-small-segments.gcode │ ├── step-speed-different.config │ ├── step-speed-same.config │ └── superellipse.gcode └── uio-pruss-interface.cc └── systemd ├── Makefile ├── README ├── beagleg.service └── run-beagleg.sh /.clang-format: -------------------------------------------------------------------------------- 1 | # Use the Google style in this project. 2 | # https://google.github.io/styleguide/cppguide.html 3 | BasedOnStyle: Google 4 | 5 | # ... adapt to our local style. 6 | ContinuationIndentWidth: 2 7 | IndentPPDirectives: None 8 | AllowShortCaseLabelsOnASingleLine: true 9 | AlignConsecutiveBitFields: true 10 | AlignConsecutiveMacros: true 11 | IndentCaseLabels: false 12 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | --- 2 | # Disabled some clang-analyzer static checks, need some more investigation. 3 | # TODO(hzeller) fix and re-enable clang-analyzer checks. 4 | # TODO(hzeller) Looking over magic numbers might be good, but probably 5 | # not worthwhile hard-failing 6 | # TODO(hzeller) Explore anofalloff suggestions. 7 | # 8 | # readability-make-member-function-const is great, but it also suggests that 9 | # in cases where we return a non-const pointer. So good to check, not by 10 | # default. 11 | # 12 | # readability-qualified-auto is useful in general, however it suggests 13 | # to convert iterators (e.g. std::string_view::begin()) to the pointer it 14 | # returns; however since the iterator is implementation defined, this is not 15 | # a valid assertion. Running the check every now and then manually and 16 | # fixing all the non-iterator cases is useful though. Off by default. 17 | ## 18 | Checks: > 19 | clang-diagnostic-*,clang-analyzer-*, 20 | -clang-analyzer-core.NonNullParamChecker, 21 | -clang-analyzer-cplusplus.NewDeleteLeaks, 22 | -clang-analyzer-unix.Malloc, 23 | -clang-analyzer-valist.Uninitialized, 24 | -clang-diagnostic-unused-const-variable, 25 | readability-*, 26 | -readability-braces-around-statements, 27 | -readability-else-after-return, 28 | -readability-function-cognitive-complexity, 29 | -readability-implicit-bool-conversion, 30 | -readability-isolate-declaration, 31 | -readability-magic-numbers, 32 | -readability-make-member-function-const, 33 | -readability-named-parameter, 34 | -readability-qualified-auto, 35 | -readability-redundant-access-specifiers, 36 | -readability-uppercase-literal-suffix, 37 | -readability-use-anyofallof, 38 | -readability-convert-member-functions-to-static, 39 | google-*, 40 | -google-readability-avoid-underscore-in-googletest-name, 41 | -google-readability-braces-around-statements, 42 | -google-readability-todo, 43 | -google-readability-casting, 44 | performance-*, 45 | bugprone-*, 46 | -bugprone-branch-clone, 47 | -bugprone-easily-swappable-parameters, 48 | -bugprone-exception-escape, 49 | -bugprone-move-forwarding-reference, 50 | -bugprone-narrowing-conversions, 51 | -bugprone-reserved-identifier, 52 | modernize-use-override, 53 | misc-*, 54 | -misc-no-recursion, 55 | -misc-non-private-member-variables-in-classes, 56 | -misc-redundant-expression, 57 | -misc-unused-parameters, 58 | 59 | WarningsAsErrors: '' 60 | HeaderFilterRegex: '' 61 | AnalyzeTemporaryDtors: false 62 | ... 63 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor config file, see http://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.{h,cc}] 12 | indent_size = 2 13 | 14 | [Makefile] 15 | indent_style = tab 16 | -------------------------------------------------------------------------------- /.github/bin/make-compilation-db.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | TMPDIR="${TMPDIR:-/tmp}" 5 | readonly BUILD_OUT=${TMPDIR}/build.out 6 | 7 | make clean > /dev/null 2>&1 8 | BEAR_COMMAND_SEPARATOR="--" 9 | if bear --version | grep "2\.4" ; then 10 | # Older versions of bear did not have the -- separator. The github actions 11 | # run on an Ubuntu which still has the 2.4 version. 12 | BEAR_COMMAND_SEPARATOR="" 13 | fi 14 | time bear ${BEAR_COMMAND_SEPARATOR} make -C src all test-binaries > ${BUILD_OUT} 2>&1 15 | 16 | if [ $? -ne 0 ]; then 17 | cat ${BUILD_OUT} 18 | echo "Build failure." 19 | exit 1 20 | fi 21 | echo "done." 22 | exit 0 23 | -------------------------------------------------------------------------------- /.github/bin/run-clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | PREFERRED_BINARY=clang-format-11 6 | 7 | CLANG_FORMAT=clang-format 8 | 9 | if command -v "${PREFERRED_BINARY}"; then 10 | CLANG_FORMAT="${PREFERRED_BINARY}" 11 | fi 12 | 13 | FORMAT_OUT=${TMPDIR:-/tmp}/clang-format-diff.out 14 | 15 | find src -name "*.h" -o -name "*.cc" | xargs ${CLANG_FORMAT} --verbose -i 16 | 17 | # Check if we got any diff, then print it out in in the CI. 18 | # TODO: make these suggested diffs in the pull request. 19 | git diff > ${FORMAT_OUT} 20 | 21 | if [ -s ${FORMAT_OUT} ]; then 22 | echo "== There were changes running the formatter ==" 23 | cat ${FORMAT_OUT} 24 | echo "To locally fix, run .github/bin/run-clang-format.sh then commit and push." 25 | exit 1 26 | fi 27 | 28 | exit 0 29 | -------------------------------------------------------------------------------- /.github/bin/run-clang-tidy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -u 4 | 5 | TMPDIR="${TMPDIR:-/tmp}" 6 | 7 | readonly PARALLEL_COUNT=$(nproc) 8 | readonly FILES_PER_INVOCATION=5 9 | 10 | readonly FILES_TO_PROCESS=${TMPDIR}/clang-tidy-files.list 11 | readonly TIDY_OUT=${TMPDIR}/clang-tidy.out 12 | 13 | # Using clang-tidy-11 as it is the last one still checking for 14 | # google-runtime-references, non-const references in parameters - which is 15 | # the preferred style in this project. 16 | PREFERRED_BINARY=clang-tidy-11 17 | 18 | CLANG_TIDY=clang-tidy 19 | if command -v "${PREFERRED_BINARY}"; then 20 | CLANG_TIDY="${PREFERRED_BINARY}" 21 | fi 22 | 23 | hash ${CLANG_TIDY} || exit 2 # make sure it is installed. 24 | 25 | echo ::group::Build compilation database 26 | 27 | $(dirname $0)/make-compilation-db.sh 28 | if [ $? -ne 0 ]; then 29 | echo "::error::Can't generate compilation database." 30 | exit 1 31 | fi 32 | 33 | find src -name "*.h" -o -name "*.cc" > ${FILES_TO_PROCESS} 34 | 35 | echo "::endgroup::" 36 | 37 | echo "::group::Run ${CLANG_TIDY} on $(wc -l < ${FILES_TO_PROCESS}) files" 38 | 39 | cat ${FILES_TO_PROCESS} \ 40 | | xargs -P${PARALLEL_COUNT} -n ${FILES_PER_INVOCATION} -- \ 41 | ${CLANG_TIDY} --quiet 2>/dev/null \ 42 | > ${TIDY_OUT}.tmp 43 | 44 | # Only modify at the end, so we can inspect the file manually while a new run 45 | # of this script is in progress. 46 | mv ${TIDY_OUT}.tmp ${TIDY_OUT} 47 | 48 | cat ${TIDY_OUT} 49 | 50 | echo "::endgroup::" 51 | 52 | if [ -s ${TIDY_OUT} ]; then 53 | 54 | # Tidy results were non-empty. Put a summary into a separate group. 55 | echo "::group::Summary" 56 | # Give a nice overview of how many counts of which problem found. 57 | sed 's|\(.*\)\(\[[a-zA-Z.-]*\]$\)|\2|p;d' < ${TIDY_OUT} | sort | uniq -c | sort -n 58 | echo "::endgroup::" 59 | 60 | echo "::error::There were clang-tidy warnings. Please fix" 61 | exit 1 62 | fi 63 | 64 | echo "No clang-tidy complaints.😎" 65 | exit 0 66 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | build-and-test: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | compiler: 16 | - g++ 17 | - clang++ 18 | optimization: [ 0, 1, 2, 3] 19 | 20 | name: Test ${{matrix.compiler}} -O${{matrix.optimization}} 21 | steps: 22 | - name: Prepare 23 | run: | 24 | sudo apt-get update -qq 25 | sudo apt install -y g++ clang pkg-config libgtest-dev libgmock-dev valgrind 26 | 27 | - uses: actions/checkout@v2 28 | with: 29 | submodules: recursive 30 | fetch-depth: 0 31 | 32 | - name: Configure shell 33 | # Since we're not compiling on the Beaglebone, disable arm specifics 34 | run: | 35 | echo "ARM_COMPILE_FLAGS=" >> $GITHUB_ENV 36 | echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV 37 | echo "BEAGLEG_OPT_CFLAGS=-O${{ matrix.optimization }} -Werror" >> $GITHUB_ENV 38 | 39 | - name: Build 40 | run: | 41 | make 42 | 43 | - name: Test 44 | run: | 45 | make test 46 | 47 | - name: Valgrind Test 48 | run: | 49 | make valgrind-test 50 | 51 | hardware-targets: 52 | runs-on: ubuntu-latest 53 | strategy: 54 | fail-fast: false 55 | matrix: 56 | hardware: # TODO: can the matrix be derived from directory hardware/* ? 57 | - BUMPS 58 | - CRAMPS 59 | - Pockegotion 60 | - VGEN5 61 | 62 | name: Hardware ${{matrix.hardware}} 63 | steps: 64 | - uses: actions/checkout@v2 65 | with: 66 | submodules: recursive 67 | fetch-depth: 0 68 | 69 | - name: Configure shell 70 | # Since we're not compiling on the Beaglebone, disable arm specifics 71 | run: | 72 | echo "ARM_COMPILE_FLAGS=" >> $GITHUB_ENV 73 | echo BEAGLEG_HARDWARE_TARGET="${{matrix.hardware}}" >> $GITHUB_ENV 74 | 75 | - name: Build 76 | run: | 77 | make 78 | 79 | Coverage: 80 | runs-on: ubuntu-latest 81 | 82 | name: Coverage prepare 83 | steps: 84 | - name: Prepare 85 | run: | 86 | sudo apt-get update -qq 87 | sudo apt install -y g++ pkg-config libgtest-dev libgmock-dev lcov 88 | 89 | - uses: actions/checkout@v2 90 | with: 91 | submodules: recursive 92 | fetch-depth: 0 93 | 94 | - name: Configure shell 95 | # Since we're not compiling on the Beaglebone, disable arm specifics 96 | run: | 97 | echo 'ARM_COMPILE_FLAGS=' >> $GITHUB_ENV 98 | 99 | - name: Coverage run 100 | run: | 101 | make -C src beagleg.coverage 102 | 103 | - name: Upload coverage 104 | uses: codecov/codecov-action@v2 105 | with: 106 | files: src/beagleg.coverage 107 | fail_ci_if_error: true 108 | verbose: true 109 | 110 | CodeFormatting: 111 | runs-on: ubuntu-latest 112 | 113 | steps: 114 | 115 | - name: Checkout code 116 | uses: actions/checkout@v2 117 | with: 118 | fetch-depth: 0 119 | 120 | - name: Install Dependencies 121 | run: | 122 | sudo apt-get install clang-format-11 123 | clang-format --version 124 | 125 | - name: Run formatting style check 126 | run: ./.github/bin/run-clang-format.sh 127 | 128 | ClangTidy: 129 | runs-on: ubuntu-latest 130 | 131 | steps: 132 | 133 | - name: Checkout code 134 | uses: actions/checkout@v2 135 | with: 136 | submodules: recursive 137 | fetch-depth: 0 138 | 139 | - name: Install Dependencies 140 | run: | 141 | sudo apt-get install pkg-config libgtest-dev libgmock-dev bear clang-tidy-11 142 | 143 | - name: Configure shell 144 | # Since we're not compiling on the Beaglebone, disable arm specifics 145 | run: | 146 | echo 'ARM_COMPILE_FLAGS=' >> $GITHUB_ENV 147 | 148 | - name: Run clang tidy 149 | run: ./.github/bin/run-clang-tidy.sh 150 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.d 4 | *.a 5 | machine-control 6 | gcode-print-stats 7 | gcode2ps 8 | test-out/ 9 | compile_commands.json 10 | .cache 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "am335x_pru_package"] 2 | path = am335x_pru_package 3 | url = https://github.com/hzeller/am335x_pru_package.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Author 2 | ------ 3 | Henner Zeller 4 | 5 | Contributors 6 | ------------ 7 | H Hartley Sweeten 8 | Leonardo Romor 9 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # INSTALLATION 2 | 3 | ## Get one of the latest linux Debian images 4 | 5 | Download one of the latest debian images provided by the following [**list**](https://beagleboard.org/latest-images). This installation guide refers to 6 | [AM3358 Debian 10.3 2020-04-06 4GB SD IoT](https://debian.beagleboard.org/images/bone-debian-10.3-iot-armhf-2020-04-06-4gb.img.xz) 7 | 8 | Always use the most minimal image you can find, e.g. no graphical user 9 | interface etc. 10 | 11 | ## Flash the SD card; Boot; SSH into your Beaglebone 12 | 13 | This documentation is provided elsewhere already, see 14 | https://beagleboard.org/getting-started 15 | 16 | In short: unpack the xz-packed image, and place as-is on the SD card (On 17 | Linux, use `dd`, on other platforms they have more complicated graphical tools). 18 | 19 | Then boot the Beaglebone and connect via ssh to it ( 20 | `ssh debian@beaglebone.local`, default password `temppwd`). 21 | 22 | ## Prepare the environment 23 | 24 | ### If you have an old Beaglebone 25 | 26 | If you have your Beaglebone lying around in a drawer for a while, it is probably 27 | good to update the uboot on the eMMC to the latest version. 28 | 29 | ``` 30 | sudo apt install bb-u-boot-am335x-evm 31 | sudo /opt/u-boot/bb-u-boot-am335x-evm/install-mmcblk0.sh 32 | sudo /opt/u-boot/bb-u-boot-am335x-evm/install-mmcblk1.sh 33 | ``` 34 | 35 | ### Enable PRU 36 | To enable the PRU the way we use it, we need to `/boot/uEnv.txt` and 37 | enable the correct `uboot_overlay_pru` line. 38 | 39 | We need to _disable_ the line containing `PRU-RPROC` (add a `#` in front) and 40 | _enable_ the line containing the `PRU-UIO` (remove `#` in front); so it will 41 | look like this: 42 | 43 | ``` 44 | ###PRUSS OPTIONS 45 | ###pru_rproc (4.4.x-ti kernel) 46 | #uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-4-TI-00A0.dtbo 47 | ###pru_uio (4.4.x-ti, 4.14.x-ti & mainline/bone kernel) 48 | uboot_overlay_pru=/lib/firmware/AM335X-PRU-UIO-00A0.dtbo 49 | ``` 50 | 51 | ## Install BeagleG 52 | 53 | 54 | Let's start from fetching the BeagleG repository with: 55 | 56 | ``` 57 | git clone --recursive https://github.com/hzeller/beagleg.git 58 | ``` 59 | 60 | change directory into the repository and run `make`. 61 | 62 | The resulting `machine-control` binary will be in the toplevel directory. You 63 | can `sudo make install` it, or run it right there. 64 | 65 | Then [set up your hardware](./hardware/) and possibly create the necessary 66 | systemd configuration for a set-up that starts on boot. 67 | 68 | # TROUBLESHOOTING 69 | 70 | In general, make sure to have the latest Beaglebone Debian image; most of 71 | earlier images have various problems that are not covered here for brevity. 72 | 73 | In any case of trouble, make sure to have your system up-to-date 74 | 75 | ``` 76 | sudo apt-get update 77 | sudo apt-get upgrade 78 | ``` 79 | 80 | ... and have a fresh kernel 81 | 82 | ``` 83 | cd /opt/scripts/tools/ 84 | git pull 85 | sudo ./update_kernel.sh 86 | ``` 87 | 88 | In particular if you see **`prussdrv_open() failed`** in the logs, this might 89 | indicate that either the wrong PRU config is enabled; check `/boot/uEnv.txt`. 90 | 91 | ## System locks up 92 | 93 | If you have some older debian image, then you might run into this: Some 94 | 4.4 linux kernel versions do not have the timers drivers enabled which results 95 | in a kernel panic when BeagleG initializes these. 96 | In order to be able to use the PWM you would need to recompile the kernel with 97 | `CONFIG_OMAP_DM_TIMER=y`. 98 | 99 | Alternatively, in order to use BeagleG without the PWM TIMERS support, you 100 | can compile beagleg with: 101 | 102 | ``` 103 | CONFIG_FLAGS=-D_DISABLE_PWM_TIMERS make 104 | ``` 105 | 106 | ## Empty am335x_pru_package folder 107 | 108 | When compiling, you might encounter the following error: 109 | ``` 110 | make -e -C src all 111 | make[1]: Entering directory '/home/debian/beagleg/src' 112 | g++ -std=c++11 -Wall -I. -I../am335x_pru_package/pru_sw/app_loader/include -I../hardware/BUMPS -D_XOPEN_SOURCE=500 -mtune=cortex-a8 -march=armv7-a -O3 -DCAPE_NAME='"BUMPS"' -DBEAGLEG_VERSION='"2018-06-16 (commit=51db5c7)"' -c machine-control.cc -o machine-control.o 113 | g++ -std=c++11 -Wall -I. -I../am335x_pru_package/pru_sw/app_loader/include -I../hardware/BUMPS -D_XOPEN_SOURCE=500 -mtune=cortex-a8 -march=armv7-a -O3 -DCAPE_NAME='"BUMPS"' -DBEAGLEG_VERSION='"2018-06-16 (commit=51db5c7)"' -c motor-operations.cc -o motor-operations.o 114 | g++ -std=c++11 -Wall -I. -I../am335x_pru_package/pru_sw/app_loader/include -I../hardware/BUMPS -D_XOPEN_SOURCE=500 -mtune=cortex-a8 -march=armv7-a -O3 -DCAPE_NAME='"BUMPS"' -DBEAGLEG_VERSION='"2018-06-16 (commit=51db5c7)"' -c sim-firmware.cc -o sim-firmware.o 115 | g++ -std=c++11 -Wall -I. -I../am335x_pru_package/pru_sw/app_loader/include -I../hardware/BUMPS -D_XOPEN_SOURCE=500 -mtune=cortex-a8 -march=armv7-a -O3 -DCAPE_NAME='"BUMPS"' -DBEAGLEG_VERSION='"2018-06-16 (commit=51db5c7)"' -c pru-motion-queue.cc -o pru-motion-queue.o 116 | make -C ../am335x_pru_package 117 | make[2]: Entering directory '/home/debian/beagleg/am335x_pru_package' 118 | make[2]: *** No targets specified and no makefile found. Stop. 119 | make[2]: Leaving directory '/home/debian/beagleg/am335x_pru_package' 120 | Makefile:141: recipe for target '../am335x_pru_package/pru_sw/utils/pasm' failed 121 | make[1]: *** [../am335x_pru_package/pru_sw/utils/pasm] Error 2 122 | make[1]: Leaving directory '/home/debian/beagleg/src' 123 | Makefile:32: recipe for target 'all' failed 124 | make: *** [all] Error 2 125 | ``` 126 | 127 | this means that you most probably forgot to clone the repository with the `--recursive` flag. 128 | 129 | If that's the case, you can simply run inside the repository folder 130 | `git submodule update --init --recursive` and run `make` again. 131 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # (c) 2013 h.zeller@acm.org 2 | # This is free software. License: GNU 3.0 3 | 4 | # Stuff based on the environment. This assumes stuff to be compiled on the 5 | # beaglebone and the am335x_pru_package checked out. 6 | # https://github.com/beagleboard/am335x_pru_package 7 | 8 | # -- 9 | # The following variables can be overwritten by environment variables 10 | # of the same name. 11 | # -- 12 | 13 | # Change here for which hardware you are compiling. See hardware/ directory. 14 | # Currently supported BUMPS, CRAMPS, and VGEN5 15 | #export BEAGLEG_HARDWARE_TARGET?=BUMPS 16 | 17 | # Disable PWM timers. See README.md. 18 | #export CONFIG_FLAGS?=-D_DISABLE_PWM_TIMERS 19 | 20 | # In case you cross compile this on a different architecture, uncomment this 21 | # and set the prefix of the compiler binary. 22 | #export CROSS_COMPILE?=arm-arago-linux-gnueabi- 23 | 24 | # Tuning options for ARM CPU. Unset this in an environment variable if not 25 | # compiled on the Beaglebone but on a different system. 26 | #export ARM_COMPILE_FLAGS?=-mtune=cortex-a8 -march=armv7-a 27 | 28 | PREFIX?=/usr/local 29 | BINDIR=$(PREFIX)/bin 30 | 31 | all machine-control: 32 | $(MAKE) -e -C src all 33 | 34 | install: machine-control 35 | mkdir -p $(BINDIR) 36 | install -m 755 machine-control $(BINDIR) 37 | 38 | clean test valgrind-test: 39 | $(MAKE) -C src/common $@ 40 | $(MAKE) -C src/gcode-parser $@ 41 | $(MAKE) -C src $@ 42 | 43 | dist-clean: 44 | $(MAKE) -C src dist-clean 45 | -------------------------------------------------------------------------------- /hardware/BUMPS/README.md: -------------------------------------------------------------------------------- 1 | BUMPS hardware definition 2 | ========================= 3 | 4 | The BUMPS cape was designed together with BeagleG. 5 | 6 | ![Bumps board][BUMPS-img] 7 | 8 | This cape uses the [beaglebone-universal-io] device tree overlay. 9 | 10 | ## Overlay and I/O configuration 11 | 12 | The I/O pins can then be configured using the config-pin utility. Refer to the 13 | [beaglebone-universal-io] for details. 14 | 15 | The pin configuration can also be setup from a file such as 16 | [bumps.pins](./bumps.pins). 17 | 18 | ``` 19 | # Configure the I/O pins 20 | /opt/source/bb.org-overlays/tools/beaglebone-universal-io/config-pin -f bumps.pins 21 | ``` 22 | 23 | ## Default configuration 24 | 25 | An example default configuration [bumps.config](./bumps.config) has been 26 | provided as a starting point. 27 | 28 | ## Pinout 29 | 30 | These are the GPIO bits associated with the motor outputs on the BUMPS board. 31 | The actual physical pins are all over the place on the Beaglebone Black extension headers 32 | P8 and P9, see table below. 33 | 34 | Before we can use all pins, we need to install the device-tree overlay, see the 35 | [hardware page](../) for details. 36 | 37 | After that, all pins are mapped to be used by beagleg. This is the pinout 38 | 39 | |Motor connector | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 40 | |----------------------:|:---:|:---:|:---:|:----:|:---:|:---:|:---:|:-----:| 41 | |**Step** `GPIO-0` | 4 | 5 | 3 | 7 | 2 | 14 | 15 | 20 | 42 | | ...on BBB Header |P9-18|P9-17|P9-21|P9-42A|P9-22|P9-26|P9-24|P9-41A | 43 | |**Direction** `GPIO-1` | 14 | 15 | 13 | 16 | 12 | 17 | 18 | 19 | 44 | | ...on BBB Header |P8-16|P8-15|P8-11| P9-15|P8-12|P9-23|P9-14| P9-16 | 45 | 46 | Motor enable for all motors is on `GPIO-1`, bit 28, P9-12 47 | (The mapping right now was done because these are consecutive GPIO pins that 48 | can be used, but the mapping to P9-42A (P11-22) and P9-41A (P11-21) should 49 | probably move to an unambiguated pin) 50 | 51 | The mapping of motor number to axis happens in the `[Motor-Mapping]` section 52 | of the configuration file, then the axes can be configured with steps etc. 53 | 54 | If you build your own cape: note all logic levels are 3.3V (and assume not more 55 | than ~4mA). The RAMPS driver board for instance only works if you power the 56 | 5V input with 3.3V, so that the Pololu inputs detect the logic level properly. 57 | 58 | This is how the early experimental manual cape interfacing to a RAMPS adapter 59 | looked like. 60 | ![Manual Cape][manual-cape] 61 | 62 | At the middle/bottom of the test board you see a headpone connector: many of 63 | the early experiments didn't have yet a stepper motor installed, but just 64 | listening to the step-frequency :) 65 | 66 | Other pins: 67 | * Two AUX outputs on GPIO-0 30, 31. This controls the medium current Aux open drain connectors at the bottom left on the [Bumps board][BUMPS]. 68 | * 3 end-switch inputs on GPIO-0 23, 26, 27 69 | * The PWM outputs are on GPIO-2 2, 3, 4, 5 which are also pins Timer 4, 5, 6, 7. Plan is to 70 | use the AM335x Timer functionality in their PWM mode (yeah, but I have not looked at the data 71 | sheet yet to see if this would actually work). These control the two high current 72 | PWM outputs (screw terminals top right) and the two medium current open drain pwm connectors 73 | on the Bumps board (connector top left).w 74 | * Analog inputs AIN0, AIN1, AIN2 will be used for temperature reading. 75 | 76 | [BUMPS]: https://github.com/hzeller/bumps 77 | [BUMPS-img]: ../../img/bumps-connect.jpg 78 | [manual-cape]: ../../img/manual-ramps-cape.jpg 79 | [beaglebone-universal-io]: https://github.com/cdsteinkuehler/beaglebone-universal-io 80 | -------------------------------------------------------------------------------- /hardware/BUMPS/beagleg-pin-mapping.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | // (c) 2013, 2014 Henner Zeller 3 | // 4 | // This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | // 6 | // BeagleG is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // BeagleG is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with BeagleG. If not, see . 18 | // 19 | // see motor-interface-constants.h for available PINs 20 | 21 | // This contains the defines the GPIO mappings for BUMPS 22 | // https://github.com/hzeller/bumps 23 | 24 | #define MOTOR_1_STEP_GPIO PIN_P9_18 // motor 1 25 | #define MOTOR_2_STEP_GPIO PIN_P9_17 // motor 2 26 | #define MOTOR_3_STEP_GPIO PIN_P9_21 // motor 3 27 | #define MOTOR_4_STEP_GPIO PIN_P9_42 // motor 4 28 | #define MOTOR_5_STEP_GPIO PIN_P9_22 // motor 5 29 | #define MOTOR_6_STEP_GPIO PIN_P9_26 // (extern 6) 30 | #define MOTOR_7_STEP_GPIO PIN_P9_24 // (extern 7) 31 | #define MOTOR_8_STEP_GPIO PIN_P9_41 // (extern 8) 32 | 33 | #define MOTOR_1_DIR_GPIO PIN_P8_16 // motor 1 34 | #define MOTOR_2_DIR_GPIO PIN_P8_15 // motor 2 35 | #define MOTOR_3_DIR_GPIO PIN_P8_11 // motor 3 36 | #define MOTOR_4_DIR_GPIO PIN_P9_15 // motor 4 37 | #define MOTOR_5_DIR_GPIO PIN_P8_12 // motor 5 38 | #define MOTOR_6_DIR_GPIO PIN_P9_23 // (extern 6) 39 | #define MOTOR_7_DIR_GPIO PIN_P9_14 // (extern 7) 40 | #define MOTOR_8_DIR_GPIO PIN_P9_16 // (extern 8) 41 | 42 | #define MOTOR_ENABLE_GPIO PIN_P9_12 // ENn 43 | #define MOTOR_ENABLE_IS_ACTIVE_HIGH 0 // 1 if EN, 0 if ~EN 44 | 45 | #define AUX_1_GPIO PIN_P9_11 // AUX_1 "Aux, Open Collector" 46 | #define AUX_2_GPIO PIN_P9_13 // AUX_2 "Aux, Open Collector" 47 | 48 | #define PWM_1_GPIO PIN_P8_9 // PWM_1 "Power PWM" 49 | #define PWM_2_GPIO PIN_P8_10 // PWM_2 "Power PWM" 50 | #define PWM_3_GPIO PIN_P8_7 // PWM_3 "PWM, Open Collector" 51 | #define PWM_4_GPIO PIN_P8_8 // PWM_4 "PWM, Open Collector" 52 | 53 | #define IN_1_GPIO PIN_P8_13 // END_X 54 | #define IN_2_GPIO PIN_P8_14 // END_Y 55 | #define IN_3_GPIO PIN_P8_17 // END_Z 56 | -------------------------------------------------------------------------------- /hardware/BUMPS/bumps.config: -------------------------------------------------------------------------------- 1 | [ General ] 2 | home-order = ZXY 3 | require-homing = yes # require homing after first switch on 4 | range-check = yes # Dangerous if no 5 | auto-motor-disable-seconds = 10 6 | 7 | [ X-Axis ] 8 | steps-per-mm = 32*200 / 60 9 | max-feedrate = 450 10 | max-acceleration = 800 11 | range = 355 12 | home-pos = min 13 | 14 | [ Y-Axis ] 15 | steps-per-mm = 32*200 / 60 16 | max-feedrate = 450 17 | max-acceleration = 800 18 | range = 335 19 | home-pos = min 20 | 21 | [ Z-Axis ] 22 | steps-per-mm = 32*200 / 2 23 | max-feedrate = 4 24 | max-acceleration = 100 25 | range = 95 26 | home-pos = max 27 | 28 | # -- hardware mapping 29 | 30 | [ Motor-Mapping ] 31 | motor_1 = axis:z 32 | #motor_2 = axis:e 33 | motor_3 = axis:y 34 | #motor_4 = axis:a 35 | motor_5 = axis:x 36 | 37 | [ Switch-Mapping ] 38 | switch_1 = active:low min_x 39 | switch_2 = active:low min_y 40 | switch_3 = active:low max_z 41 | 42 | [ Aux-Mapping ] 43 | aux_1 = vacuum 44 | aux_2 = fan 45 | 46 | [ Pwm-Mapping ] 47 | pwm_2 = spindle-speed 48 | -------------------------------------------------------------------------------- /hardware/BUMPS/bumps.pins: -------------------------------------------------------------------------------- 1 | # Run with /opt/source/bb.org-overlays/tools/beaglebone-universal-io/config-pin -f bumps.pins 2 | # 3 | # Step signals. 4 | P9.18 low # motor 1 (top left Pololu; BUMPS v0.1 label "Z") 5 | P9.17 low # motor 2 (bottom left Pololu; BUMPS v0.1 label "E") 6 | P9.21 low # motor 3 (top center Pololu; BUMPS v0.1 label "Y") 7 | P9.42 low # motor 4 (bottom last Pololu; BUMPS v0.1 label "A") 8 | P9.22 low # motor 5 (top right Pololu; BUMPS v0.1 label "X") 9 | P9.26 low # motor 6 (extern) 10 | P9.24 low # motor 7 (extern) 11 | P9.41 low # motor 8 (extern) 12 | 13 | # Dir signals 14 | P8.16 low # motor 1 15 | P8.15 low # motor 2 16 | P8.11 low # motor 3 17 | P9.15 low # motor 4 18 | P8.12 low # motor 5 19 | P9.23 low # motor 6 (extern) 20 | P9.14 low # motor 7 (extern) 21 | P9.16 low # motor 8 (extern) 22 | 23 | # Output 24 | P9.12 high # Motor enable 25 | P9.11 low # AUX 1 26 | P9.13 low # AUX 2 27 | P8.09 timer # PWM1 Power PWM 28 | P8.10 timer # PWM2 Power PWM 29 | P8.07 timer # PWM3 Open Collector PWM 30 | P8.08 timer # PWM4 Open Collector PWM 31 | 32 | # Input 33 | P8.13 in+ # END_X 34 | P8.14 in+ # END_Y 35 | P8.17 in+ # END_Z 36 | 37 | # (TODO: Analog) 38 | -------------------------------------------------------------------------------- /hardware/BUMPS/pru-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | ;;; BUMPS specific PRU routines. 3 | 4 | ;; For now, we just use the generic ones. 5 | #include "../../src/pru-generic-io-routines.hp" 6 | 7 | // Dummy function 8 | CheckForEStop: 9 | RET 10 | -------------------------------------------------------------------------------- /hardware/CRAMPS/BeagleG-CRAMPS.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Based on github.com/jadonk/validation-scripts/tree/master/test-capemgr 3 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 4 | * 5 | * This program is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Purpose License Version 2 as 7 | * published by the Free Software Foundation 8 | * 9 | * To create the binary representation that the device manager can handle, run 10 | * make BeagleG-CRAMPS-00A0.dtbo 11 | * See beagleg-cramps-cape-pinmux.sh how to enable. 12 | */ 13 | 14 | /dts-v1/; 15 | /plugin/; 16 | 17 | /{ 18 | compatible = "ti,beaglebone", "ti,beaglebone-black", "ti,beaglebone-green"; 19 | part-number = "BeagleG-CRAMPS"; /* BeagleG/CRAMPS 'cape' */ 20 | version = "00A0"; 21 | 22 | exclusive-use = "pruss", // Programmable realtime unit 23 | "P9.23", "P9.14", "P8.26", "P8.17", "P9.25", // power control 24 | "P8.13", "P8.15", "P8.19", "P9.16", "P9.17", "P9.24", "P9.42A", "P9.31", "P9.29", // step 25 | "P8.12", "P8.14", "P8.18", "P9.12", "P9.18", "P9.26", "P9.16", "P9.28", "P9.30", // direction 26 | "P8.8", "P8.7", "P9.10", "P8.9", "P9.13", "P9.11", // endstops 27 | "P8.11", "P9.15", "P9.27", "P9.21", "P9.41A", "P9.22", // fets 28 | "tscadc"; // Analog digital converter 29 | 30 | fragment@0 { 31 | target = <&am33xx_pinmux>; 32 | __overlay__ { 33 | beagleg_gpio_pins: BeagleG_Pins { 34 | pinctrl-single,pins = < 35 | /* P9.9 PWR_BUT */ 36 | /* P9.10 SYS_RESETn */ 37 | 0x044 0x07 /* P9.23 GPIO1[17] out, pd machine_pwr MACHINE_PWR */ 38 | 0x048 0x17 /* P9.14 GPIO1[18] out, pu ~axis_ena MOTOR_ENABLE */ 39 | 0x07c 0x07 /* P8.26 GPIO1[29] out, pd estop_sw ESTOP_SW */ 40 | 0x02c 0x2f /* P8.17 GPIO0[27] in estop ESTOP */ 41 | 0x1ac 0x07 /* P9.25 GPIO3[21] out, pd led LED */ 42 | 43 | 0x024 0x07 /* P8.13 GPIO0[23] out, pd x_step MOTOR_1_STEP */ 44 | 0x03c 0x07 /* P8.15 GPIO1[15] out, pd y_step MOTOR_2_STEP */ 45 | 0x020 0x07 /* P8.19 GPIO0[22] out, pd z_step MOTOR_3_STEP */ 46 | 0x04c 0x07 /* P9.16 GPIO1[19] out, pd e0_step MOTOR_4_STEP */ 47 | 0x15c 0x07 /* P9.17 GPIO0[5] out, pd e1_step MOTOR_5_STEP */ 48 | 0x184 0x07 /* P9.24 GPIO0[15] out, pd e2_step MOTOR_6_STEP */ 49 | 0x164 0x07 /* P9.42A GPIO0[7] out, pd step_u MOTOR_7_STEP (external driver) */ 50 | /* P9.31 GPIO3[14] step_v MOTOR_8_STEP (external driver) */ 51 | /* P9.29 GPIO3[15] step_w MOTOR_9_STEP (external driver) */ 52 | 53 | 0x030 0x07 /* P8.12 GPIO1[12] out, pd x_dir MOTOR_1_DIR */ 54 | 0x028 0x07 /* P8.14 GPIO0[26] out, pd y_dir MOTOR_2_DIR */ 55 | 0x08c 0x07 /* P8.18 GPIO2[1] out, pd z_dir MOTOR_3_DIR */ 56 | 0x078 0x07 /* P9.12 GPIO1[28] out, pd e0_dir MOTOR_4_DIR */ 57 | 0x158 0x07 /* P9.18 GPIO0[4] out, pd e1_dir MOTOR_5_DIR */ 58 | 0x180 0x07 /* P9.26 GPIO0[14] out, pd e2_dir MOTOR_6_DIR */ 59 | 0x038 0x07 /* P8.16 GPIO1[14] out, pd dir_u MOTOR_7_DIR (external driver) */ 60 | /* P9.28 GPIO3[17] dir_v MOTOR_8_DIR (external driver) */ 61 | /* P9.30 GPIO3[16] dir_w MOTOR_9_DIR (external driver) */ 62 | 63 | 0x094 0x2f /* P8.8 GPIO2[3] in x-min END_X_MIN */ 64 | 0x090 0x2f /* P8.7 GPIO2[2] in x-max END_X_MAX */ 65 | 0x098 0x2f /* P8.10 GPIO2[4] in y-min END_Y_MIN */ 66 | 0x09c 0x2f /* P8.9 GPIO2[5] in y-max END_Y_MAX */ 67 | 0x074 0x2f /* P9.13 GPIO0[31] in z-min END_Z_MIN */ 68 | 0x070 0x2f /* P9.11 GPIO0[30] in z-max END_Z_MAX */ 69 | 70 | 0x034 0x07 /* P8.11 GPIO1[13] out, pd fet1 */ 71 | 0x040 0x07 /* P9.15 GPIO1[16] out, pd fet2 */ 72 | 0x1a4 0x07 /* P9.27 GPIO3[19] out, pd fet3 */ 73 | 0x154 0x07 /* P9.21 GPIO0[3] out, pd fet4 */ 74 | 0x1b4 0x07 /* P9.41A GPIO0[20] out, pd fet5 */ 75 | 0x150 0x07 /* P9.22 GPIO0[2] out, pd fet6 */ 76 | 77 | /* P9.20 GPIO0[12] sda */ 78 | /* P9.19 GPIO0[13] scl */ 79 | 80 | /* P9.31 GPIO3[14] sck */ 81 | /* P9.29 GPIO3[15] miso */ 82 | /* P9.30 GPIO3[16] mosi */ 83 | /* P9.28 GPIO3[17] spi_cs0 */ 84 | 85 | /* P9.33 AIN4 therm0 */ 86 | /* P9.35 AIN6 therm2 */ 87 | /* P9.36 AIN5 therm1 */ 88 | /* P9.37 AIN2 ain2 */ 89 | /* P9.38 AIN3 ain3 */ 90 | /* P9.39 AIN0 ain0 */ 91 | /* P9.40 AIN1 ain1 */ 92 | >; 93 | }; 94 | }; 95 | }; 96 | 97 | // TODO: some other fragment mentioning adc 0, 1, 2 ? 98 | 99 | fragment@1 { 100 | target = <&ocp>; 101 | __overlay__ { 102 | test_helper: helper { 103 | compatible = "bone-pinmux-helper"; 104 | pinctrl-names = "default"; 105 | pinctrl-0 = <&beagleg_gpio_pins>; 106 | status = "okay"; 107 | }; 108 | }; 109 | }; 110 | 111 | fragment@2{ 112 | target = <&pruss>; 113 | __overlay__ { 114 | status = "okay"; 115 | }; 116 | }; 117 | }; 118 | -------------------------------------------------------------------------------- /hardware/CRAMPS/README.md: -------------------------------------------------------------------------------- 1 | CRAMPS hardware definition 2 | ========================== 3 | 4 | The [CRAMPS] board is a popular BeagleBone Black cape by Charles Steinkuehler 5 | 6 | ![Cramps picture][CRAMPS-img] 7 | 8 | ## Credits for this Hardware definition 9 | The BeagleG hardware definition for CRAMPS was contributed 10 | by Hartley Sweeten , together with code that 11 | separates out the pin definition to make supporting various capes possible 12 | in the first place. 13 | 14 | [CRAMPS]: http://reprap.org/wiki/CRAMPS 15 | [CRAMPS-img]: http://reprap.org/mediawiki/images/thumb/e/e7/CRAMPS.v2.2.assembled.JPG/800px-CRAMPS.v2.2.assembled.JPG 16 | -------------------------------------------------------------------------------- /hardware/CRAMPS/beagleg-pin-mapping.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | // (c) 2013, 2014 Henner Zeller 3 | // 4 | // This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | // 6 | // BeagleG is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // BeagleG is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with BeagleG. If not, see . 18 | // 19 | // see motor-interface-constants.h for available PINs 20 | 21 | // CRAMPS cape Generic GPIO mapping 22 | // http://reprap.org/wiki/CRAMPS 23 | 24 | #define MOTOR_1_STEP_GPIO PIN_P8_13 // X_STEP 25 | #define MOTOR_2_STEP_GPIO PIN_P8_15 // Y_STEP 26 | #define MOTOR_3_STEP_GPIO PIN_P8_19 // Z_STEP 27 | #define MOTOR_4_STEP_GPIO PIN_P9_16 // E0_STEP 28 | #define MOTOR_5_STEP_GPIO PIN_P9_17 // E1_STEP 29 | #define MOTOR_6_STEP_GPIO PIN_P9_24 // E2_STEP 30 | #define MOTOR_7_STEP_GPIO PIN_P9_42 // STEP_U (external) 31 | #define MOTOR_8_STEP_GPIO PIN_P9_31 // STEP_V (external) 32 | 33 | #define MOTOR_1_DIR_GPIO PIN_P8_12 // X_DIR 34 | #define MOTOR_2_DIR_GPIO PIN_P8_14 // Y_DIR 35 | #define MOTOR_3_DIR_GPIO PIN_P8_18 // Z_DIR 36 | #define MOTOR_4_DIR_GPIO PIN_P9_12 // E0_DIR 37 | #define MOTOR_5_DIR_GPIO PIN_P9_18 // E1_DIR 38 | #define MOTOR_6_DIR_GPIO PIN_P9_26 // E2_DIR 39 | #define MOTOR_7_DIR_GPIO PIN_P8_16 // DIR_U (external) 40 | #define MOTOR_8_DIR_GPIO PIN_P9_28 // DIR_V (external) 41 | 42 | #define MOTOR_ENABLE_GPIO PIN_P9_14 // AXIS_ENAn 43 | #define MOTOR_ENABLE_IS_ACTIVE_HIGH 0 // 1 if EN, 0 if ~EN 44 | 45 | #define AUX_1_GPIO PIN_P9_41 // FET5 46 | #define AUX_2_GPIO PIN_P9_22 // FET6 47 | #define AUX_3_GPIO PIN_P9_29 // STEP_W (external) 48 | #define AUX_4_GPIO PIN_P9_30 // DIR_W (external) 49 | #define AUX_14_GPIO PIN_P8_26 // ESTOP_SW 50 | #define AUX_15_GPIO PIN_P9_23 // MACHINE_PWR 51 | #define AUX_16_GPIO PIN_P9_25 // LED 52 | 53 | #define PWM_1_GPIO PIN_P8_11 // FET1 54 | #define PWM_2_GPIO PIN_P9_15 // FET2 55 | #define PWM_3_GPIO PIN_P9_27 // FET3 56 | #define PWM_4_GPIO PIN_P9_21 // FET4 57 | 58 | #define IN_1_GPIO PIN_P8_8 // X-MIN 59 | #define IN_2_GPIO PIN_P8_10 // Y-MIN 60 | #define IN_3_GPIO PIN_P9_13 // Z-MIN 61 | #define IN_4_GPIO PIN_P8_7 // X-MAX 62 | #define IN_5_GPIO PIN_P8_9 // Y-MAX 63 | #define IN_6_GPIO PIN_P9_11 // Z-MAX 64 | #define IN_7_GPIO PIN_P8_17 // ESTOP 65 | -------------------------------------------------------------------------------- /hardware/CRAMPS/cramps.pins: -------------------------------------------------------------------------------- 1 | # Run with 2 | # /opt/source/bb.org-overlays/tools/beaglebone-universal-io/config-pin -f cramps.pins 3 | ## 4 | 5 | # Step signals. 6 | P8.13 low # X_STEP 7 | P8.15 low # Y_STEP 8 | P8.19 low # Z_STEP 9 | P9.16 low # E0_STEP 10 | P9.17 low # E1_STEP 11 | P9.24 low # E2_STEP 12 | P9.42 low # STEP_U 13 | P9.31 low # STEP_V 14 | 15 | # Dir signals 16 | P8.12 low # X_DIR 17 | P8.14 low # Y_DIR 18 | P8.18 low # Z_DIR 19 | P9.12 low # E0_DIR 20 | P9.18 low # E1_DIR 21 | P9.26 low # E2_DIR 22 | P8.16 low # DIR_U 23 | P9.28 low # DIR_V 24 | 25 | # Output (TODO: maybe some of the FETs can be PWM'ed ?) 26 | P9.14 low # AXIS_ENAn (motor enable) 27 | P9.41 low # FET5 28 | P9.22 low # FET6 29 | P9.29 low # STEP_W (external. Not covered by PRU) 30 | P9.30 low # DIR_W (externa. Not covered by PRU) 31 | P8.26 low # ESTOP_SW 32 | P9.23 low # MACHINE_PWR 33 | P9.25 low # LED 34 | P8.11 low # FET1 35 | P9.15 low # FET2 36 | P9.27 low # FET3 37 | P9.21 low # FET4 38 | 39 | # Input 40 | P8.08 in # X-MIN 41 | P8.10 in # Y-MIN 42 | P9.13 in # Z-MIN 43 | P8.07 in # X-MAX 44 | P8.09 in # Y-MAX 45 | P9.11 in # Z-MAX 46 | P8.17 in # ESTOP 47 | -------------------------------------------------------------------------------- /hardware/CRAMPS/pru-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | ;;; CRAMPS specific PRU routines. 3 | 4 | ;; Just use the generic ones. 5 | #include "../../src/pru-generic-io-routines.hp" 6 | 7 | // Dummy function 8 | CheckForEStop: 9 | RET 10 | -------------------------------------------------------------------------------- /hardware/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all : BUMPS/BeagleG-BUMPS-00A0.dtbo CRAMPS/BeagleG-CRAMPS-00A0.dtbo 3 | 4 | # Making a binary devicetree 5 | %-00A0.dtbo: %.dts 6 | dtc -I dts -O dtb -o $@ -b 0 -@ $^ 7 | -------------------------------------------------------------------------------- /hardware/Pockegotion/README.md: -------------------------------------------------------------------------------- 1 | Pockegotion hardware definition 2 | =============================== 3 | 4 | *(work in progress)* 5 | 6 | This is for Pockegotion, the PocketCape to interface with an [Quadrigotion] 7 | board. In addition to the Quadrigotion interface, it 8 | will have a couple of opto-coupled inputs and PWM outputs. 9 | 10 | Pins are defined with the universal overlay, so can be loaded with 11 | 12 | ``` 13 | /opt/source/bb.org-overlays/tools/beaglebone-universal-io/config-pin -f pockegotion.pins 14 | ``` 15 | 16 | The 'cape' is pretty much experimental right now: 17 | 18 | [![Breadboard](../../img/pockegotion.jpg)][G+post] 19 | 20 | 21 | [Quadrigotion]: http://quadrigotion.org/ 22 | [G+post]: https://plus.google.com/u/0/+HennerZeller/posts/DC3vYcE9zw8 23 | -------------------------------------------------------------------------------- /hardware/Pockegotion/beagleg-pin-mapping.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | // (c) 2018 Henner Zeller 3 | // 4 | // This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | // 6 | // BeagleG is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // BeagleG is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with BeagleG. If not, see . 18 | // 19 | // see motor-interface-constants.h for available PINs 20 | 21 | // Definition file for Pockegotion 22 | 23 | #define MOTOR_1_STEP_GPIO PIN_P1_29 // motor 1 24 | #define MOTOR_2_STEP_GPIO PIN_P1_31 // motor 2 25 | #define MOTOR_3_STEP_GPIO PIN_P1_33 // motor 3 26 | #define MOTOR_4_STEP_GPIO PIN_P1_34 // motor 4 27 | 28 | #define MOTOR_1_DIR_GPIO PIN_P2_24 // motor 1 29 | #define MOTOR_2_DIR_GPIO PIN_P2_33 // motor 2 30 | #define MOTOR_3_DIR_GPIO PIN_P2_22 // motor 3 31 | #define MOTOR_4_DIR_GPIO PIN_P2_18 // motor 4 32 | 33 | #define MOTOR_ENABLE_GPIO PIN_P2_10 // ENn 34 | #define MOTOR_ENABLE_IS_ACTIVE_HIGH 0 // 1 if EN, 0 if ~EN 35 | 36 | #define IN_1_GPIO PIN_P2_05 37 | #define IN_2_GPIO PIN_P2_07 38 | #define IN_3_GPIO PIN_P2_09 39 | #define IN_4_GPIO PIN_P2_11 40 | -------------------------------------------------------------------------------- /hardware/Pockegotion/pockegotion.pins: -------------------------------------------------------------------------------- 1 | P2.10 out # Motor ~Enable 2 | 3 | # Step signals 4 | P1.29 out # Step 0 5 | P1.31 out # Step 1 6 | P1.33 out # Step 2 7 | P1.34 out # Step 3 8 | 9 | # Direction bits 10 | P2.24 out # Dir 0 11 | P2.33 out # Dir 1 12 | P2.22 out # Dir 2 13 | P2.18 out # Dir 3 14 | 15 | # Switch inputs. 16 | P2.05 in # Switch 0 17 | P2.07 in # Switch 1 18 | P2.09 in # Switch 2 19 | P2.11 in # Switch 3 20 | -------------------------------------------------------------------------------- /hardware/Pockegotion/pru-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | 3 | ;; For now, we just use the generic ones. 4 | #include "../../src/pru-generic-io-routines.hp" 5 | 6 | // Dummy function 7 | CheckForEStop: 8 | RET 9 | -------------------------------------------------------------------------------- /hardware/README.md: -------------------------------------------------------------------------------- 1 | Hardware support 2 | ================ 3 | 4 | While BeagleG currently is tied to the BeagleBone Black **am335x** CPU family 5 | utilizing its neat PRU, it can support various hardware that wire up the 6 | outputs to stepmotor drivers. 7 | 8 | There are various [BeagleBone-Black] capes that provide such stepper motor 9 | drivers for 3D printers and CNC machines. 10 | 11 | This directory contains sub-directories with the name of the particular hardware. Each directory 12 | contains the necessary hardware description used by BeagleG. You need to enable the hardware 13 | you intend to use in the toplevel Makefile. 14 | 15 | * [BUMPS/](./BUMPS/) The [BUMPS] board was initially developed for BeagleG 16 | before there were any other boards available. 17 | * [CRAMPS/](./CRAMPS/) The [CRAMPS] board by Charles Steinkuehler is a 18 | popular cape. 19 | * [Pockegotion](./Pockegotion/) Work in progress for a cape for the 20 | [PocketBeagle]. 21 | 22 | (If you have access to other boards and run them with BeagleG, consider adding the support and 23 | send a pull request) 24 | 25 | ## Set up the pins needed 26 | 27 | Load the pin-mapping with the `config-pin` script from the directory that 28 | contains your hardware mapping; for BUMPS, this would be: 29 | 30 | ``` 31 | /opt/source/bb.org-overlays/tools/beaglebone-universal-io/config-pin -f BUMPS/bumps.pins 32 | ``` 33 | 34 | (Note: Older versions of this documentation were loading a device tree here, 35 | but these days things are simpler making use of the [beaglebone-universal-io] 36 | GPIO pin-mapper.) 37 | 38 | ## Adding support for new hardware 39 | 40 | To add support for a new cape, you need to create a subdirectory with the name 41 | of the cape you want to add. 42 | 43 | The directory should contain at least a README or README.md describing the 44 | board and provide references where it can be found. 45 | 46 | Provide a `*.pins` file for the pin-mapping to be loaded with `config-pin`. 47 | 48 | In order to make things compile, each hardware subdirectory requires the 49 | following files with these exact names: 50 | 51 | * `beagleg-pin-mapping.h`: mapping of GPIO pins to logical pins (e.g. `MOTOR_1_STEP`). 52 | As an example, see the BUMPS [beagleg-pin-mapping.h](./BUMPS/beagleg-pin-mapping.h) 53 | 54 | * `pru-io-routines.hp`: a file containing a set of PRU subroutines to set 55 | certain values. You can write this file yourself or just use the generic 56 | version provided in this directory: 57 | 58 | ```bash 59 | cd hardware # Where this README.md is; subdirectory of the beagleg/ toplevel dir 60 | cp template-pru-io-routines.hp MyCapeName/pru-io-routines.hp 61 | ``` 62 | 63 | You can enable compilation for your new cape by setting the variable 64 | `BEAGLEG_HARDWARE_TARGET` in the toplevel Makefile to your cape name: 65 | 66 | BEAGLEG_HARDWARE_TARGET=MyCapeName 67 | 68 | Please check out the existing subdirectories to get an idea. If you added a new board, consider sending a patch. 69 | 70 | [BeagleBone-Black]: http://beagleboard.org/BLACK 71 | [BUMPS]: http://github.com/hzeller/bumps 72 | [CRAMPS]: http://reprap.org/wiki/CRAMPS 73 | [PocketBeagle]: https://beagleboard.org/pocket 74 | [beaglebone-universal-io]: https://github.com/cdsteinkuehler/beaglebone-universal-io 75 | -------------------------------------------------------------------------------- /hardware/VGEN5/beagleg-pin-mapping.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | // (c) 2015 H Hartley Sweeten 3 | // 4 | // This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | // 6 | // BeagleG is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // BeagleG is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with BeagleG. If not, see . 18 | // 19 | // see motor-interface-constants.h for available PINs 20 | 21 | // VISION GEN5 cape Generic GPIO mapping 22 | 23 | #define MOTOR_1_STEP_GPIO PIN_P9_41 // X_STEP 24 | #define MOTOR_2_STEP_GPIO PIN_P9_27 // Y_STEP 25 | #define MOTOR_3_STEP_GPIO PIN_P9_11 // Z_STEP 26 | #define MOTOR_4_STEP_GPIO PIN_P9_23 // Xb/Yb_STEP 27 | #define MOTOR_5_STEP_GPIO PIN_P9_13 // A_STEP 28 | 29 | #define MOTOR_1_DIR_GPIO PIN_P9_42 // X_DIR 30 | #define MOTOR_2_DIR_GPIO PIN_P9_30 // Y_DIR 31 | #define MOTOR_3_DIR_GPIO PIN_P9_12 // Z_DIR 32 | #define MOTOR_4_DIR_GPIO PIN_P9_25 // Xb/Yb_DIR 33 | #define MOTOR_5_DIR_GPIO PIN_P9_15 // A_DIR 34 | 35 | #define MOTOR_ENABLE_GPIO PIN_P9_16 // ENA (output) 36 | #define MOTOR_ENABLE_IS_ACTIVE_HIGH 1 // 1 if EN, 0 if ~EN 37 | 38 | #define AUX_1_GPIO PIN_P8_7 // OUT0 - GPIO 39 | #define AUX_2_GPIO PIN_P8_8 // OUT1 - GPIO 40 | #define AUX_3_GPIO PIN_P8_9 // OUT2 - GPIO 41 | #define AUX_4_GPIO PIN_P8_10 // OUT3 - GPIO 42 | #define AUX_5_GPIO PIN_P9_14 // OUT4 - GPIO 43 | #define AUX_6_GPIO PIN_P9_17 // not routed (SPI0_CS0) 44 | #define AUX_7_GPIO PIN_P9_18 // not routed (SPI0_D1) 45 | #define AUX_8_GPIO PIN_P9_21 // not routed (SPI0_D0) 46 | #define AUX_9_GPIO PIN_P9_22 // not routed (SPI0_SCLK) 47 | #define AUX_10_GPIO PIN_P9_24 // not routed (UART1_TXD) 48 | #define AUX_11_GPIO PIN_P9_26 // not routed (UART1_RXD) 49 | #define AUX_12_GPIO PIN_P9_28 // not routed (SPI1_CS0) 50 | #define AUX_13_GPIO PIN_P9_29 // not routed (SPI1_DO) 51 | #define AUX_14_GPIO PIN_P9_31 // SPINDLE_ON 52 | #define AUX_16_GPIO PIN_P8_26 // LED 53 | 54 | #define PWM_1_GPIO AUX_1_GPIO // OUT0 - TIMER PWM 55 | #define PWM_2_GPIO AUX_2_GPIO // OUT1 - TIMER PWM 56 | #define PWM_3_GPIO AUX_3_GPIO // OUT2 - TIMER PWM 57 | #define PWM_4_GPIO AUX_4_GPIO // OUT3 - TIMER PWM 58 | 59 | #define IN_1_GPIO PIN_P8_15 // IN0 - X home (min) 60 | #define IN_2_GPIO PIN_P8_16 // IN1 - Y home (max) 61 | #define IN_3_GPIO PIN_P8_11 // IN2 - Z home (max) 62 | #define IN_4_GPIO PIN_P8_12 // IN3 - Z suface (min) 63 | #define IN_5_GPIO PIN_P8_13 // IN4 - LIM4 64 | #define IN_6_GPIO PIN_P8_14 // IN5 - LIM5 65 | #define IN_7_GPIO PIN_P8_17 // ESTOP 66 | #define IN_8_GPIO PIN_P8_18 // PAUSE 67 | #define IN_9_GPIO PIN_P8_19 // START 68 | -------------------------------------------------------------------------------- /hardware/VGEN5/pru-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | ;;; Vision GEN5 specific PRU routines. 3 | 4 | ;; Just use the generic ones. 5 | #include "../../src/pru-generic-io-routines.hp" 6 | 7 | // HARDCODED function to check the E-Stop input on the VGEN5 board 8 | // IN_7_GPIO (GPIO_0_BASE | 27) is the dedicated E-Stop input 9 | // 10 | // NOTE: two reads are done for a minimal debouce 11 | // 12 | // Available registers: 13 | // r0 = used to return the E-Stop status (0=ok, 1=E-Stop active) 14 | // r4 = GPIO_DATAIN register for the EStop input 15 | // r5 = EStop input bit 16 | // r6 = GPIO_DATAIN register value 17 | CheckForEStop: 18 | MOV r4, (IN_7_GPIO & 0xfffff000) 19 | QBEQ estop_ok, r4.w2, GPIO_NOT_MAPPED 20 | MOV r5, GPIO_DATAIN 21 | ADD r4, r4, r5 22 | MOV r5, (IN_7_GPIO & 0x1f) 23 | debounce: 24 | LBBO r6, r4, 0, 4 25 | QBBC estop_ok, r6, r5 26 | QBEQ estop_active, r0, 1 27 | MOV r0, 1 28 | JMP debounce 29 | estop_ok: 30 | MOV r0, 0 31 | estop_active: 32 | RET 33 | -------------------------------------------------------------------------------- /hardware/VGEN5/vgen5.config: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Sample configuration for the VGEN5 cape 3 | ## 4 | 5 | [ General ] 6 | home-order = ZXY # CNC machine, home Z first then XY 7 | require-homing = yes # Require homing (G28) is executed before first move 8 | range-check = yes # Check that axes are within range 9 | enable-pause = yes # Enable pause switch detection 10 | auto-motor-disable-seconds = 120 # Switch off motors after 2 minutes of inactivity 11 | auto-fan-disable-seconds = 240 # Switch off fan 4 minutes after motors 12 | auto-fan-pwm = 5 # Enable fan at a PWM of 5 when a GCode program is started 13 | 14 | [ X-Axis ] 15 | steps-per-mm = 200 * 16 * 4 / 25.4 # 16 microsteps 1/4 pitch screw 16 | max-feedrate = 100 # mm/s (~3.9 in/sec) 17 | max-acceleration = 381 # mm/s^2 (~15 in/sec^2) 18 | range = 6.5 * 25.4 # mm (6.5 in) 19 | home-pos = min # home at X- 20 | 21 | [ Y-Axis ] 22 | steps-per-mm = 200 * 16 * 4 / 25.4 # 16 microsteps 1/4 pitch screw 23 | max-feedrate = 100 # mm/s (~3.9 in/sec) 24 | max-acceleration = 381 # mm/s^2 (~15 in/sec^2) 25 | range = 7.5 * 25.4 # mm (7.5 in) 26 | home-pos = min # home at Y- 27 | 28 | [ Z-Axis ] 29 | steps-per-mm = 200 * 16 * 4 / 25.4 # 16 microsteps 1/4 pitch screw 30 | max-feedrate = 100 # mm/s (~3.9 in/sec) 31 | max-acceleration = 381 # mm/s^2 (~15 in/sec^2) 32 | range = 0.75 * 25.4 # mm (0.75 in) 33 | home-pos = max # home at Z+ 34 | 35 | [ Motor-Mapping ] 36 | motor_1 = axis:x # X axis 37 | motor_2 = axis:-y # Y axis 38 | motor_3 = axis:-z # Z axis 39 | 40 | [ Switch-Mapping ] 41 | switch_1 = active:low min_x # X home limit 42 | switch_2 = active:low min_y # Y home limit 43 | switch_3 = active:low max_z # Z home limit 44 | switch_4 = active:low min_z # Z prox (surface detect) 45 | #switch_5 = # IN4 46 | #switch_6 = # IN5 47 | switch_7 = active:high e-stop # n/c e-stop switch to gnd 48 | switch_8 = active:low pause # n/o pause switch to gnd 49 | switch_9 = active:low start # n/o start switch to gnd 50 | 51 | [ Aux-Mapping ] 52 | aux_1 = vacuum # Aux Vacuum (M10=on; M11=off) 53 | aux_2 = mist # Aux Mist Coolant (M7=on; M9=off) 54 | aux_3 = cooler # General Purpose Aux Output (M245=on; M246=off) 55 | #aux_4 = fan # Fan is GPIO controlled (M106 Sn=on (n > 0); M107=off) 56 | aux_14 = spindle-on # Spindle on 57 | aux_16 = led # User LED 58 | 59 | [ PWM-Mapping ] 60 | pwm_4 = fan # Fan is PWM controlled (M106 Sn=on at Sn (0-255) PWM; M107=off) 61 | -------------------------------------------------------------------------------- /hardware/VGEN5/vgen5.pins: -------------------------------------------------------------------------------- 1 | # output signals (set these first so that the outputs get turned off) 2 | P8.07 low # OUT0 output low, 2.5A FET to GND, HI = on 3 | P8.08 low # OUT1 output low, 2.5A FET to GND, HI = on 4 | P8.09 low # OUT2 output low, 2.5A FET to GND, HI = on 5 | P8.10 timer # OUT3 timer, 2.5A FET to GND, HI = on 6 | P9.14 low # OUT4 output low, 2.5A FET to GND, HI = on 7 | P9.16 low # ENA output low, 2N7002 to ESTOP, HI = enable drivers 8 | P8.26 low # LED output low, 2N7002 to GND, HI = on 9 | 10 | # step signals 11 | P9.41 low # STEP0 output low, direct to Pololu 12 | P9.27 low # STEP1 output low, direct to Pololu 13 | P9.11 low # STEP2 output low, direct to Pololu 14 | P9.23 low # STEP3 output low, direct to Pololu 15 | P9.13 low # STEP4 output low, direct to Pololu 16 | 17 | # direction signals 18 | P9.42 low # DIR0 output low, direct to Pololu 19 | P9.30 low # DIR1 output low, direct to Pololu 20 | P9.12 low # DIR2 output low, direct to Pololu 21 | P9.25 low # DIR3 output low, direct to Pololu 22 | P9.15 low # DIR4 output low, direct to Pololu 23 | P9.31 low # SPINDLE_ON output low, to 2N7002 which enables P-FET 24 | 25 | # input signals 26 | P8.17 in # ESTOP input, 4K7 pu, LO = ok 27 | P8.19 in # START input. 4K7 pu, LO = pressed 28 | P8.18 in # PAUSE input, 4K7 pu, LO = pressed 29 | P8.15 in # IN0 input, from 74AC14 shmitt trigger inverter 30 | P8.16 in # IN1 input, from 74AC14 shmitt trigger inverter 31 | P8.11 in # IN2 input, from 74AC14 shmitt trigger inverter 32 | P8.12 in # IN3 input, from 74AC14 shmitt trigger inverter 33 | P8.13 in # IN4 input, from 74AC14 shmitt trigger inverter 34 | P8.14 in # IN5 input, from 74AC14 shmitt trigger inverter 35 | 36 | # unmapped signals 37 | #P9.17 # SPI0_CS0 38 | #P9.18 # SPI0_D1 39 | #P9.21 # SPI0_D0 40 | #P9.22 # SPI0_SCLK 41 | #P9.24 # UART1_TXD 42 | #P9.26 # UART1_RXD 43 | #P9.28 # SPI1_CS0 44 | #P9.29 # SPI1_D0 45 | -------------------------------------------------------------------------------- /hardware/install-devicetree-overlay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # (Deprecated: once all hardware mappings are switched to universal overlay, 3 | # this is not needed anymore) 4 | # 5 | # TODO: make more robust - this might change depending on the distribution. 6 | # Maybe there are already standard scripts available on the distribution that 7 | # do these things ? 8 | # 9 | # Essentially what we are doing is to embed the DTBO file in the initrd file, so that it 10 | # is available right away on boot-up. That is the quickest way to enable the cape at boot-up 11 | # short of compiling the device-tree file into the kernel. 12 | ## 13 | 14 | set -e 15 | 16 | DT_VERSION=00A0 17 | UENV_FILE=/boot/uEnv.txt 18 | 19 | usage() { 20 | echo "Usage: $0 " 21 | echo "Available:" 22 | for f in $(ls `dirname $0`/*/*.dts) ; do 23 | echo " $f" 24 | done 25 | exit 1 26 | } 27 | 28 | if [ $# -ne 1 ] ; then 29 | usage 30 | fi 31 | 32 | DTS_FILE=$1 33 | if [[ ! $DTS_FILE =~ \.dts$ ]] ; then 34 | echo "This does not seem to be a *.dts file". 35 | usage 36 | fi 37 | 38 | # ... there must be a simpler way to extract this... 39 | CAPE_NAME=$(sed 's/.*part-number\s*=\s*"\([^"]*\)".*/\1/p;d' < $DTS_FILE) 40 | 41 | if [ -z "$CAPE_NAME" ] ; then 42 | echo "Didn't find any part-number in $DTS_FILE ?" 43 | exit 44 | fi 45 | 46 | DTBO_FILE=$(echo "$DTS_FILE" | sed "s/.dts$/-$DT_VERSION.dtbo/") 47 | 48 | make $DTBO_FILE 49 | if [ $? -ne 0 ] ; then 50 | echo "Failed to produce $DTBO_FILE" 51 | fi 52 | 53 | # The initramfs script will pick up dtbos from /lib/firmware. 54 | # Let's put it there. 55 | cp $DTBO_FILE /lib/firmware 56 | 57 | if uname -r | grep -q "^4" ; then 58 | MAGIC_ENABLE=cape_enable=bone_capemgr.enable_partno= 59 | else 60 | MAGIC_ENABLE=cape_enable=capemgr.enable_partno= 61 | fi 62 | 63 | # First: set up UENV_FILE. 64 | echo "* Setting up $UENV_FILE" 65 | # Note, this only works properly if optargs is not set yet. 66 | if grep "^${MAGIC_ENABLE}.*${CAPE_NAME}" $UENV_FILE > /dev/null ; then 67 | echo " * Already configured in $UENV_FILE" 68 | else 69 | if grep "^$MAGIC_ENABLE" $UENV_FILE > /dev/null ; then 70 | echo " * Adding $CAPE_NAME to cape-enable line in $UENV_FILE" 71 | sed -i "s/^${MAGIC_ENABLE}.*/\0,${CAPE_NAME}/g" $UENV_FILE 72 | else 73 | echo " * Adding cape-enable line to $UENV_FILE" 74 | echo "${MAGIC_ENABLE}${CAPE_NAME}" >> $UENV_FILE 75 | fi 76 | fi 77 | 78 | update-initramfs -tu -k `uname -r` 79 | 80 | sync 81 | 82 | echo "Now reboot for the cape to be initialized at boot time" 83 | -------------------------------------------------------------------------------- /hardware/start-devicetree-overlay.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # (Deprecated: once all hardware mappings are switched to universal overlay, 3 | # this is not needed anymore) 4 | # 5 | # Run as root. 6 | # What is happening here is well explained in Derek Molloy's excellent 7 | # video http://www.youtube.com/watch?v=wui_wU1AeQc 8 | ## 9 | 10 | VERBOSE=0 11 | DT_VERSION=00A0 12 | 13 | usage() { 14 | echo "Usage: $0 " 15 | echo "Available:" 16 | for f in $(ls `dirname $0`/*/*.dts) ; do 17 | echo " $f" 18 | done 19 | exit 1 20 | } 21 | 22 | if [ $# -ne 1 ] ; then 23 | usage 24 | fi 25 | 26 | DTS_FILE=$1 27 | if [[ ! $DTS_FILE =~ \.dts$ ]] ; then 28 | echo "This does not seem to be a *.dts file". 29 | usage 30 | fi 31 | 32 | # ... there must be a simpler way to extract this... 33 | CAPE_NAME=$(sed 's/.*part-number\s*=\s*"\([^"]*\)".*/\1/p;d' < $DTS_FILE) 34 | 35 | if [ -z "$CAPE_NAME" ] ; then 36 | echo "Didn't find any part-number in $DTS_FILE ?" 37 | exit 38 | fi 39 | 40 | DTBO_FILE=$(echo "$DTS_FILE" | sed "s/.dts$/-$DT_VERSION.dtbo/") 41 | 42 | make $DTBO_FILE 43 | if [ $? -ne 0 ] ; then 44 | echo "Failed to produce $DTBO_FILE" 45 | fi 46 | 47 | PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins 48 | if [ -e /sys/devices/platform/bone_capemgr/slots ] ; then 49 | SLOTS=/sys/devices/platform/bone_capemgr/slots 50 | else 51 | # 3.x way of doing things. 52 | SLOTS=/sys/devices/bone_capemgr.*/slots 53 | fi 54 | 55 | # Some dance around minimal tools available on the system. We get the offsets 56 | # and add 44e10800 to it, so that we can grep these in the $PINS 57 | OFFSETS_800=$(for f in $(cat $DTS_FILE | grep "^\s*0x" | awk '{print $1}') ; do \ 58 | printf "%0d" $f | awk '{printf("44e10%03x\n", $1 + 2048)}'; \ 59 | done) 60 | 61 | if [ $VERBOSE -ne 0 ] ; then 62 | echo "This is how these pins look before." 63 | for f in $OFFSETS_800 ; do 64 | grep $f $PINS 65 | done 66 | fi 67 | 68 | cp $DTBO_FILE /lib/firmware 69 | 70 | echo 71 | echo "Adding $CAPE_NAME overlay" 72 | echo "$CAPE_NAME" > $SLOTS 73 | cat $SLOTS 74 | 75 | if [ $VERBOSE -ne 0 ] ; then 76 | echo 77 | echo "This is how these pins look afterwards." 78 | for f in $OFFSETS_800 ; do 79 | grep $f $PINS 80 | done 81 | fi 82 | -------------------------------------------------------------------------------- /hardware/template-pru-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | ;;; This is a template to be copied to a new hardware 3 | ;;; subdirectory. 4 | 5 | ;; For now, we just use the generic ones. 6 | #include "../../src/pru-generic-io-routines.hp" 7 | -------------------------------------------------------------------------------- /img/Makefile: -------------------------------------------------------------------------------- 1 | all : machine-control.svg print-stats.svg 2 | 3 | %.svg : %.dot 4 | dot -Tsvg $^ > $@ 5 | 6 | %.png : %.dot 7 | dot -Tpng $^ > $@ 8 | 9 | %.svg : %.dot 10 | dot -Tsvg $^ > $@ 11 | -------------------------------------------------------------------------------- /img/beagleg-vid-thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/beagleg-vid-thumb.jpg -------------------------------------------------------------------------------- /img/bumps-connect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/bumps-connect.jpg -------------------------------------------------------------------------------- /img/machine-control.dot: -------------------------------------------------------------------------------- 1 | digraph beagleg { 2 | node [fontsize=10, fontname="Helvetica"]; 3 | edge [fontsize=10, fontname="Helvetica"]; 4 | 5 | { 6 | node [ shape=oval ]; 7 | TCP [label = "TCP socket"]; 8 | } 9 | 10 | // All the processing nodes, displayed as boxes. 11 | { 12 | node [ shape=box ]; 13 | GCodeParser; 14 | GCodeMachineControl [ label = "GCodeMachineControl\nGCode Actions"]; 15 | HardwareMapping; 16 | Planner; 17 | 18 | SegmentQueue [label = "SegmentQueue\nPass LinearSegmentSteps\nto backend"]; 19 | 20 | MotionQueueMotorOperations [label = "MotionQueueMotorOperations\nConvert segments\ninto MotionSegment commands\nfor MotionQueue implementations."]; 21 | 22 | DummyMotionQueue [label = "DummyMotionQueue\nfor dryrun.", style=dotted]; 23 | PRUMotionQueue; 24 | SimFirmwareQueue [label = "SimFirmwareQueue\nSimulating PRU", style=dotted]; 25 | SimFirmwareAudioQueue [label = "SimFirmwareAudioQueue\nOutputs stepper clocks as *.wav file.", style=dotted]; 26 | GCode2PS [ style=dotted]; 27 | //PrintStats [ style=dotted, label="gcode-print-stats\nutility"]; 28 | 29 | PruHardwareInterface; 30 | } 31 | 32 | // Inputs, and configuration files 33 | { 34 | node [ shape=oval ]; 35 | GCodeFile [label = "GCode File"]; 36 | CapeConfig [ label = "Cape config in\nhardware/"]; 37 | UserMapConfig [ label = "User config file:\nMapping sections"]; 38 | UserAxisConfig [ label = "User config file:\nAxis sections"]; 39 | } 40 | 41 | // Final action nodes 42 | { 43 | node [ shape=box, style=rounded ]; 44 | GNUPlotOutput [ style = "dotted" ]; 45 | PinToggeling [ label = "Pin Toggling,\nPWM control." ]; 46 | PRU [ label = "PRU firmware\n(motor-interface-pru.p)" ]; 47 | } 48 | 49 | GCodeFile -> GCodeParser [ label="G-Code", style=dotted]; 50 | TCP -> GCodeParser [ label="G-Code"]; 51 | 52 | { 53 | GCodeParser -> GCodeMachineControl [ label=" Parse Events;\l Metric coordinates.\l Logic axes (X, Y, Z..)"] 54 | GCodeMachineControl -> Planner [ label=" Absolute target position sequence\l with desired speed." ]; 55 | 56 | Planner -> SegmentQueue [ label = " Delta LinearSegmentSteps\l Step coordinates.\l Logic axes assigned to motors 1, 2, 3..." ] 57 | // Various SegmentQueue backends 58 | SegmentQueue -> MotionQueueMotorOperations 59 | MotionQueueMotorOperations -> PRUMotionQueue; 60 | MotionQueueMotorOperations -> SimFirmwareQueue -> GNUPlotOutput; 61 | MotionQueueMotorOperations -> SimFirmwareAudioQueue; 62 | MotionQueueMotorOperations -> DummyMotionQueue; 63 | SegmentQueue -> GCode2PS; 64 | //SegmentQueue -> PrintStats; 65 | PRUMotionQueue -> PruHardwareInterface; 66 | PruHardwareInterface -> PRU [ label = " Host → PRU\lringbuffer"]; 67 | } 68 | 69 | { 70 | rank = same; 71 | GCodeMachineControl -> HardwareMapping [ label="Request Output\nPWM, Spindle, Fan...", rank=0]; 72 | HardwareMapping -> GCodeMachineControl [ label = "Switch status." ]; 73 | } 74 | 75 | HardwareMapping -> Planner [ label = "Axis -> motor mapping."]; 76 | 77 | { 78 | rank = same; 79 | UserAxisConfig -> GCodeMachineControl; 80 | } 81 | 82 | CapeConfig -> HardwareMapping; 83 | UserMapConfig -> HardwareMapping; 84 | HardwareMapping -> PinToggeling; 85 | } 86 | -------------------------------------------------------------------------------- /img/machine-origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/machine-origin.png -------------------------------------------------------------------------------- /img/manual-ramps-cape.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/manual-ramps-cape.jpg -------------------------------------------------------------------------------- /img/pockegotion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/pockegotion.jpg -------------------------------------------------------------------------------- /img/print-stats.dot: -------------------------------------------------------------------------------- 1 | digraph beagleg { 2 | node [fontsize=10, fontname="Helvetica"]; 3 | edge [fontsize=10, fontname="Helvetica"]; 4 | 5 | { 6 | node [ shape=box ]; 7 | GCodeParser; 8 | GCodeMachineControl [ label = "GCodeMachineControl\nGCode Actions"]; 9 | Planner [ label = "Path planning"]; 10 | MotorOperations [label = "StatsMotorOperations\lPretend to operate motors\lcalculate exact time."]; 11 | } 12 | 13 | CSVOut [ label = "CSV output\nJob runtime info."] 14 | File -> GCodeParser [ label="G-Code"]; 15 | 16 | { 17 | GCodeParser -> GCodeMachineControl [ label=" Parse Events;\l Metric coordinates.\l Logic axes (X, Y, Z..)"]; 18 | GCodeMachineControl -> Planner; 19 | Planner -> MotorOperations [ label = " LinearSegmentSteps\l Step coordinates." ] 20 | MotorOperations -> CSVOut; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /img/print-stats.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | beagleg 11 | 12 | 13 | 14 | GCodeParser 15 | 16 | GCodeParser 17 | 18 | 19 | 20 | GCodeMachineControl 21 | 22 | GCodeMachineControl 23 | GCode Actions 24 | 25 | 26 | 27 | GCodeParser->GCodeMachineControl 28 | 29 | 30 | Parse Events; 31 | Metric coordinates. 32 | Logic axes (X, Y, Z..) 33 | 34 | 35 | 36 | Planner 37 | 38 | Path planning 39 | 40 | 41 | 42 | GCodeMachineControl->Planner 43 | 44 | 45 | 46 | 47 | 48 | MotorOperations 49 | 50 | StatsMotorOperations 51 | Pretend to operate motors 52 | calculate exact time. 53 | 54 | 55 | 56 | Planner->MotorOperations 57 | 58 | 59 | LinearSegmentSteps 60 | Step coordinates. 61 | 62 | 63 | 64 | CSVOut 65 | 66 | CSV output 67 | Job runtime info. 68 | 69 | 70 | 71 | MotorOperations->CSVOut 72 | 73 | 74 | 75 | 76 | 77 | File 78 | 79 | File 80 | 81 | 82 | 83 | File->GCodeParser 84 | 85 | 86 | G-Code 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /img/ramps-side.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/ramps-side.jpg -------------------------------------------------------------------------------- /img/ramps-top.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/ramps-top.jpg -------------------------------------------------------------------------------- /img/sample-gcode2ps-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-2.png -------------------------------------------------------------------------------- /img/sample-gcode2ps-anim.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-anim.gif -------------------------------------------------------------------------------- /img/sample-gcode2ps-gcode-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-gcode-1.png -------------------------------------------------------------------------------- /img/sample-gcode2ps-gcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-gcode.png -------------------------------------------------------------------------------- /img/sample-gcode2ps-isometric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-isometric.png -------------------------------------------------------------------------------- /img/sample-gcode2ps-laser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-laser.png -------------------------------------------------------------------------------- /img/sample-gcode2ps-topview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps-topview.png -------------------------------------------------------------------------------- /img/sample-gcode2ps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/sample-gcode2ps.png -------------------------------------------------------------------------------- /img/set-g55-update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/set-g55-update.png -------------------------------------------------------------------------------- /img/set-g55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/set-g55.png -------------------------------------------------------------------------------- /img/test/coordinate-systems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/coordinate-systems.png -------------------------------------------------------------------------------- /img/test/rounded-bracket-parametrized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/rounded-bracket-parametrized.png -------------------------------------------------------------------------------- /img/test/rounded-bracket-simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/rounded-bracket-simple.png -------------------------------------------------------------------------------- /img/test/spiral-cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/spiral-cut.png -------------------------------------------------------------------------------- /img/test/spline-character.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/spline-character.png -------------------------------------------------------------------------------- /img/test/spline-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/spline-loop.png -------------------------------------------------------------------------------- /img/test/splines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/splines.png -------------------------------------------------------------------------------- /img/test/square-moves-direct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/square-moves-direct.png -------------------------------------------------------------------------------- /img/test/superellipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hzeller/beagleg/f67974b1dacb666b97afb32dd5c76fac26cfab35/img/test/superellipse.png -------------------------------------------------------------------------------- /sample.config: -------------------------------------------------------------------------------- 1 | # -*- conf -*- 2 | # Some annotated BeagleG sample configuration file. 3 | # Adapt to your own needs. 4 | # You can configure logical axes X, Y, Z, E, A, B, C, U, V, W 5 | # Pass to machine-control with -c option. 6 | ## 7 | 8 | [ General ] 9 | # Homing order. For 3D printers, you'd probably home Z last, while CNC machines 10 | # typically home Z first. 11 | home-order = XYZ 12 | require-homing = yes # Require homing (G28) is executed before first move. 13 | range-check = yes # Check that axes are within range. Dangerous if no. 14 | 15 | # It is possible to clamp movements that would leave the machine cube to 16 | # range; that way the range-check will not trigger for them, but movements don't 17 | # will not end up where they were intended to be in that case, so configure 18 | # with care. Typically it makes most sense in 2.5D applications where the 19 | # Z-axis is less important. Thus this feature is limited to the Z-axis 20 | #clamp-to-range = Z 21 | 22 | auto-motor-disable-seconds = 120 # Switch off motors after 2min of inactivity. 23 | 24 | # -- Logical axis configuration 25 | 26 | [ X-Axis ] 27 | # The step motor has 200 full steps per turn. We do 32x microstepping 28 | # One turn of a gear moves the toothed belt 60mm. The configuration understands 29 | # a simple division expression: 30 | steps-per-mm = 32 * 200 / 60 31 | max-feedrate = 400 # mm/s 32 | max-acceleration = 2000 # mm/s^2 33 | range = 300 # mm - the travel of this axis 34 | home-pos = min # This is where the home switch is. At min position. 35 | 36 | [ Y-Axis ] 37 | # Another example: each turn moves the ACME screw 1/4 inch on 8x microstepping 38 | steps-per-mm = 8*200 / (1/4 * 25.4) 39 | max-feedrate = 400 # mm/s 40 | max-acceleration = 800 # mm/s^2 41 | range = 300 # mm 42 | home-pos = min 43 | 44 | [ Z-Axis ] 45 | # Our Z-axis; here, our screw only moves 2mm per turn. 46 | steps-per-mm = 32*200 / 2 47 | max-feedrate = 4 # mm/s - our Z-axis is not very fast. 48 | max-acceleration = 30 # mm/s^2 49 | range = 120 # mm 50 | home-pos = min # For CNC machines, that typically would be max on Z 51 | 52 | [ A-Axis ] 53 | # The A-Axis is a rotational axis, so instead of steps-per-mm, we give 54 | # steps per degree. 200 full steps, 32x microstepping per 360 degrees. 55 | steps-per-degree = 32*200 / 360 56 | max-feedrate = 720 # degree/s 57 | max-acceleration = 1000 # degree/s^2 58 | 59 | [ E-Axis ] 60 | # 3D printers have an 'E'-xtrusion axis. 61 | steps-per-mm = 32*200 / 30 62 | max-feedrate = 15 63 | max-acceleration = 100 64 | 65 | # Hardware mapping; which axes and switches are connected to which logical units. 66 | 67 | [ Motor-Mapping ] 68 | # If you don't happen to have a motor-mapping section, motors are assigned 69 | # for the configured axis above in sequence XYZEABCUVW 70 | motor_1 = axis:x # X axis connected to motor 1 71 | # We double up the y axis by connecting it to two motor driver, 2 and 3. 72 | # One of it shall be mirrored. 73 | motor_2 = axis:y 74 | motor_3 = axis:-y # negative, because we mirror this motor. 75 | motor_4 = axis:z 76 | motor_5 = axis:e 77 | motor_6 = axis:a 78 | 79 | [ Switch-Mapping ] 80 | # These switches trigger on high: when activated, they generate a pos level. 81 | switch_1 = active:high min_x 82 | switch_2 = active:high min_y 83 | switch_3 = active:high min_z 84 | 85 | # You can have multiple switches wired together in case you only have a limited 86 | # number of inputs or want to simplify wiring (put them electrically in series 87 | # or parallel to get a logical 'or' to reach the switching level if either 88 | # of these trigger). It is probably a good idea to have home-switches independent 89 | # of each other, while lumping together all the limit switches (only used for 90 | # exceptions anyway) can simplify wiring. 91 | #switch_4 = active:high max_y max_y 92 | 93 | # An example of a switch that triggers on low. 94 | #switch_5 = active:low max_z 95 | 96 | # In the beagleg-pin-mapping.h, additional AUX pins are chosen that can 97 | # be connected to various functions here. Valid logical names are one of 98 | # mist, flood, vacuum, spindle, spindle-speed, spindle-dir, cooler, case-lights, 99 | # fan, hotend, heatedbed, led, atx-power, estop. 100 | # All of these can be GCode controlled with various G or M codes (See G-code.md). 101 | [ Aux-Mapping ] 102 | aux_1 = mist 103 | aux_2 = flood 104 | aux_3 = spindle 105 | aux_12 = atx-power 106 | 107 | # Some of these functions make more sense with an analog output via pulse 108 | # width modulation (PWM) instead of a switching AUX output. 109 | [ PWM-Mapping ] 110 | pwm_1 = spindle-speed 111 | 112 | [ Spindle ] 113 | type = simple-pwm # Other supported type: pololu-smc 114 | max-rpm = 4800 # Maximum speed at full PWM. See also PWM-mapping section. 115 | pwr-delay-msec = 400 116 | on-delay-msec = 100 117 | off-delay-msec = 100 118 | allow-ccw = false -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | # This is a nix-shell for use with the nix package manager. 2 | # If you have nix installed, you may simply run `nix-shell` 3 | # in this repo, and have all dependencies ready in the new shell. 4 | 5 | { pkgs ? import {} }: 6 | pkgs.mkShell { 7 | buildInputs = with pkgs; 8 | [ 9 | stdenv 10 | pkg-config 11 | git 12 | lcov 13 | bear 14 | gtest 15 | valgrind 16 | ghostscript 17 | clang-tools_11 18 | graphviz 19 | ]; 20 | shellHook = 21 | '' 22 | # When compiling on a non-machine, switch off these options. 23 | export ARM_COMPILE_FLAGS="" 24 | ''; 25 | } 26 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.d 4 | *_test 5 | motor-interface-pru_bin.h 6 | compiler-flags 7 | gtest 8 | -------------------------------------------------------------------------------- /src/adc.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 H Hartley Sweeten 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | /* 21 | * $ echo PyBBIO-ADC > $SLOTS 22 | * $ cat in_voltage?_raw 23 | */ 24 | 25 | #include "adc.h" 26 | 27 | #include 28 | #include 29 | 30 | #include "common/logging.h" 31 | 32 | static const char kSysNode[] = "/sys/bus/iio/devices/iio:device0"; 33 | 34 | int arc_read_raw(int chan) { 35 | if (chan < 0 || chan > 7) { 36 | Log_error("arc_read_raw: invalid channel %d", chan); 37 | return -1; 38 | } 39 | 40 | char node[256]; 41 | snprintf(node, sizeof(node), "%s/in_voltage%d_raw", kSysNode, chan); 42 | FILE *fp = fopen(node, "r"); 43 | if (!fp) { 44 | Log_error("arc_read_raw: unable to open %s", node); 45 | return -1; 46 | } 47 | 48 | char buf[32]; 49 | if (!fgets(buf, sizeof(buf), fp)) { 50 | Log_error("arc_read_raw: unable to read %s", node); 51 | sprintf(buf, "-1"); 52 | } 53 | fclose(fp); 54 | 55 | return atoi(buf); 56 | } 57 | -------------------------------------------------------------------------------- /src/adc.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 H Hartley Sweeten 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef BEAGLEG_ADC_ 21 | #define BEAGLEG_ADC_ 22 | 23 | int arc_read_raw(int chan); 24 | 25 | #endif // BEAGLEG_ADC_ 26 | -------------------------------------------------------------------------------- /src/common/Makefile: -------------------------------------------------------------------------------- 1 | # (c) 2013 h.zeller@acm.org 2 | # This is free software. License: GNU 3.0 3 | 4 | # Location of testing framework 5 | GTEST_INCLUDE=$(shell pkg-config --cflags-only-I gtest gmock 2>/dev/null || echo "-I/usr/include") 6 | GTEST_LIBS=$(shell pkg-config --libs gtest gmock 2>/dev/null || echo "-lgtest -lgmock") 7 | 8 | # Optmization flags. Typically, that should be -O3 for regluar use, but for 9 | # debugging and development "-g -O0" can be more helpful. Overridable by 10 | # environment variable. 11 | BEAGLEG_OPT_CFLAGS?=-O3 12 | 13 | CFLAGS+=-Wall -Wextra -W -Wno-unused-result -Wno-unused-parameter -D_XOPEN_SOURCE=500 $(ARM_COMPILE_FLAGS) $(BEAGLEG_OPT_CFLAGS) -I$(shell pwd)/.. 14 | 15 | CXXFLAGS+=-std=c++17 $(CFLAGS) 16 | CXX?=g++ 17 | 18 | LDFLAGS+=-lpthread -lm 19 | 20 | # Assembled binary from *.p file. 21 | PRU_BIN=motor-interface-pru_bin.h 22 | 23 | OBJECTS=logging.o string-util.o fd-mux.o linebuf-reader.o 24 | GENLIB=libbeaglegbase.a 25 | 26 | UNITTEST_BINARIES=string-util_test linebuf-reader_test container_test 27 | 28 | DEPENDENCY_RULES=$(OBJECTS:=.d) $(UNITTEST_BINARIES:=.o.d) $(MAIN_OBJECTS:=.d) 29 | 30 | all : $(GENLIB) 31 | 32 | $(GENLIB): $(OBJECTS) 33 | $(AR) rcs $@ $^ 34 | 35 | test-binaries: $(UNITTEST_BINARIES) 36 | 37 | test: test-binaries 38 | for test_bin in $(UNITTEST_BINARIES) ; do echo ; echo $$test_bin; ./$$test_bin || exit 1 ; done 39 | 40 | valgrind-test: test-binaries 41 | for test_bin in $(UNITTEST_BINARIES) ; do valgrind --track-origins=yes --leak-check=full --error-exitcode=1 -q ./$$test_bin || exit 1; done 42 | 43 | 44 | %_test: %_test.o $(GENLIB) compiler-flags 45 | $(CROSS_COMPILE)$(CXX) -o $@ $< $(GENLIB) $(GTEST_LIBS) $(LDFLAGS) 46 | 47 | %.o: %.cc compiler-flags 48 | $(CROSS_COMPILE)$(CXX) $(CXXFLAGS) -c $< -o $@ 49 | @$(CROSS_COMPILE)$(CXX) $(CXXFLAGS) -MM $< > $@.d 50 | 51 | %_test.o: %_test.cc compiler-flags 52 | $(CROSS_COMPILE)$(CXX) $(GTEST_INCLUDE) $(CXXFLAGS) -c $< -o $@ 53 | @$(CROSS_COMPILE)$(CXX) $(GTEST_INCLUDE) $(CXXFLAGS) -MM $< > $@.d 54 | 55 | %_bin.h : %.p $(PASM) 56 | $(PASM) -I$(CAPE_INCLUDE) -V3 -c $< 57 | 58 | $(PASM): 59 | make -C $(AM335_BASE) 60 | 61 | # Useful to convert gcode2ps output. 62 | %.png : %.ps 63 | gs -q -r144 -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dEPSCrop -dBATCH -dNOPAUSE -sDEVICE=png16m -sOutputFile=$@ $< 64 | 65 | # Auto generated dependencies 66 | -include $(DEPENDENCY_RULES) 67 | 68 | clean: 69 | rm -rf $(GENLIB) $(MAIN_OBJECTS) $(OBJECTS) $(UNITTEST_BINARIES) $(UNITTEST_BINARIES:=.o) $(DEPENDENCY_RULES) *.gcda *.gcov *.gcno *.cc.html *.h.html 70 | 71 | compiler-flags: FORCE 72 | @echo '$(CXX) $(CXXFLAGS) $(GTEST_INCLUDE)' | cmp -s - $@ || echo '$(CXX) $(CXXFLAGS) $(GTEST_INCLUDE)' > $@ 73 | 74 | .PHONY: FORCE 75 | 76 | .SECONDARY: $(UNITTEST_BINARIES:=.o) 77 | -------------------------------------------------------------------------------- /src/common/README.md: -------------------------------------------------------------------------------- 1 | Libraries that don't depend on other libraries. -------------------------------------------------------------------------------- /src/common/container.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef _BEAGLEG_CONTAINER_H_ 21 | #define _BEAGLEG_CONTAINER_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | // Fixed array of POD types (that can be zeroed with bzero()). 30 | // Allows to have the index be a specific type (typically an enum instad of 31 | // int). Use for compile-defined small arrays, such as for axes and motors. 32 | template 33 | class FixedArray { 34 | public: 35 | typedef T *iterator; 36 | typedef const T *const_iterator; 37 | 38 | FixedArray() { zero(); } 39 | FixedArray(const std::initializer_list &in_list) { 40 | zero(); 41 | auto it = in_list.begin(); 42 | for (int i = 0; i < N && it != in_list.end(); ++i, ++it) { 43 | data_[i] = *it; 44 | } 45 | } 46 | FixedArray(const FixedArray &other) { CopyFrom(other); } 47 | 48 | FixedArray &operator=(const FixedArray &other) { 49 | if (&other == this) return *this; 50 | CopyFrom(other); 51 | return *this; 52 | } 53 | T &operator[](IDX i) { 54 | assert((int)i < N); 55 | return data_[(int)i]; 56 | } 57 | const T &operator[](IDX i) const { 58 | assert((int)i < N); 59 | return data_[(int)i]; 60 | } 61 | bool operator==(const FixedArray &other) const { 62 | return memcmp(data_, other.data_, sizeof(data_)) == 0; 63 | } 64 | 65 | constexpr size_t size() const { return N; } 66 | 67 | void zero() { bzero(data_, sizeof(data_)); } 68 | 69 | iterator begin() { return data_; } 70 | iterator end() { return data_ + N; } 71 | 72 | const_iterator begin() const { return data_; } 73 | const_iterator end() const { return data_ + N; } 74 | 75 | private: 76 | void CopyFrom(const FixedArray &other) { 77 | // Unary + to decay array to pointer and avoid array-comparison warning. 78 | if (+data_ != +other.data_) memcpy(data_, other.data_, sizeof(data_)); 79 | } 80 | 81 | T data_[N]; 82 | }; 83 | 84 | // A simple fixed size, compile-time allocated deque. 85 | // Any positiv CAPACITY parameter above 1 should work. Choosing a power of 86 | // two will typically generate faster code as modulo ops can become bit-AND ops. 87 | // 88 | // For a cheap empty() and size() implementation, the actual capacity() is one 89 | // less than the chosen CAPACITY template parameter. 90 | template 91 | class RingDeque { 92 | public: 93 | RingDeque() { 94 | static_assert(CAPACITY > 1, "Capacity needs to be > 1"); 95 | // intentionally not initializing memory to better see if users do. 96 | } 97 | 98 | size_t size() const { return (write_pos_ + CAPACITY - read_pos_) % CAPACITY; } 99 | bool empty() const { return write_pos_ == read_pos_; } 100 | constexpr size_t capacity() const { return CAPACITY - 1; } 101 | 102 | // Add a new element and return pointer to it. 103 | // Element is not initialized. 104 | T *append() { 105 | assert(size() < capacity()); 106 | T *result = buffer_ + write_pos_; 107 | write_pos_ = (write_pos_ + 1) % CAPACITY; 108 | return result; 109 | } 110 | 111 | // Return the content relative to the read position. 112 | T *operator[](size_t pos) { 113 | assert(size() > pos); 114 | return &buffer_[(read_pos_ + pos) % CAPACITY]; 115 | } 116 | 117 | // Return last inserted position 118 | T *back() { 119 | assert(!empty()); 120 | return &buffer_[(write_pos_ + CAPACITY - 1) % CAPACITY]; 121 | } 122 | 123 | void pop_front() { 124 | assert(!empty()); 125 | read_pos_ = (read_pos_ + 1) % CAPACITY; 126 | } 127 | 128 | void pop_back() { 129 | assert(!empty()); 130 | write_pos_ = (write_pos_ + CAPACITY - 1) % CAPACITY; 131 | } 132 | 133 | private: 134 | unsigned write_pos_ = 0; 135 | unsigned read_pos_ = 0; 136 | T buffer_[CAPACITY]; 137 | }; 138 | 139 | // This class provides a way to iterate over enumeration values. Assumes enum 140 | // values to be contiguous. 141 | template 142 | class EnumIterable { 143 | public: 144 | class const_iterator { 145 | public: 146 | explicit const_iterator(T value) : val_(value) {} 147 | T operator*() const { return val_; } 148 | void operator++() { val_ = static_cast(val_ + 1); } 149 | bool operator!=(const const_iterator &other) { return other.val_ != val_; } 150 | 151 | private: 152 | T val_; 153 | }; 154 | 155 | const_iterator begin() const { return const_iterator(first_val); } 156 | const_iterator end() const { return const_iterator(after_last_val); } 157 | }; 158 | #endif // _BEAGLEG_CONTAINER_H_ 159 | -------------------------------------------------------------------------------- /src/common/container_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2022 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "common/container.h" 21 | 22 | #include 23 | 24 | TEST(FixedArray, BasicOp) { 25 | FixedArray buffer; 26 | EXPECT_EQ(buffer.size(), 3u); 27 | static_assert(buffer.size() == 3); // compile-time constexpr 28 | 29 | buffer[0] = 1; 30 | buffer[1] = 2; 31 | buffer[2] = 3; 32 | 33 | int count = 0; 34 | int sum = 0; 35 | for (int val : buffer) { 36 | count++; 37 | sum += val; 38 | } 39 | EXPECT_EQ(count, 3); 40 | EXPECT_EQ(sum, 1 + 2 + 3); 41 | } 42 | 43 | TEST(RingDeque, BasicOp) { 44 | RingDeque buffer; 45 | EXPECT_TRUE(buffer.empty()); 46 | EXPECT_EQ(buffer.size(), 0u); 47 | 48 | *buffer.append() = 42; 49 | EXPECT_EQ(buffer.size(), 1u); 50 | EXPECT_FALSE(buffer.empty()); 51 | EXPECT_EQ(*buffer.back(), 42); 52 | 53 | *buffer.append() = 1; 54 | EXPECT_EQ(buffer.size(), 2u); 55 | EXPECT_EQ(*buffer.back(), 1); 56 | buffer.pop_back(); 57 | EXPECT_EQ(*buffer.back(), 42); 58 | buffer.pop_front(); 59 | EXPECT_TRUE(buffer.empty()); 60 | } 61 | 62 | TEST(RingDeque, Wrapping) { 63 | RingDeque buffer; 64 | EXPECT_EQ(buffer.capacity(), 3u); // one less than CAPACITY 65 | static_assert(buffer.capacity() == 3); // compile-time constexpr 66 | 67 | // Advance the internal positions so that we force wrapping. 68 | *buffer.append() = 42; 69 | *buffer.append() = 42; 70 | buffer.pop_front(); 71 | buffer.pop_front(); 72 | 73 | *buffer.append() = 1; 74 | *buffer.append() = 2; 75 | *buffer.append() = 3; 76 | EXPECT_EQ(buffer.size(), buffer.capacity()); 77 | 78 | EXPECT_EQ(*buffer[0], 1); 79 | EXPECT_EQ(*buffer[1], 2); 80 | EXPECT_EQ(*buffer[2], 3); 81 | } 82 | 83 | int main(int argc, char *argv[]) { 84 | ::testing::InitGoogleTest(&argc, argv); 85 | return RUN_ALL_TESTS(); 86 | } 87 | -------------------------------------------------------------------------------- /src/common/fd-mux.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef FD_MUX_H_ 21 | #define FD_MUX_H_ 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | // This needs a better name. 30 | class FDMultiplexer { 31 | public: 32 | explicit FDMultiplexer(unsigned idle_ms = 50) : idle_ms_(idle_ms) {} 33 | 34 | // Handlers for events from this multiplexer. 35 | // Returns true if we want to continue to be called in the future or false 36 | // if we wish to be taken out of the multiplexer. 37 | typedef std::function Handler; 38 | 39 | // These can only be set before Loop() is called or from a 40 | // running handler itself. 41 | // Returns false if that filedescriptor is already registered. 42 | bool RunOnReadable(int fd, const Handler &handler); 43 | bool RunOnWritable(int fd, const Handler &handler); 44 | 45 | // Handler called regularly every idle_ms in case there's nothing to do. 46 | void RunOnIdle(const Handler &handler); 47 | 48 | // Run the main loop. Blocks while there is still a filedescriptor 49 | // registered (return 0) or until a signal is triggered (return 1). 50 | int Loop(); 51 | 52 | protected: 53 | // Run a single cycle resulting in exactly one call of a handler function. 54 | // This means that one of these happened: 55 | // (1) The next file descriptor became ready and its Handler is called 56 | // (2) We encountered a timeout and the idle-Handler has been called. 57 | // (3) Signal received or select() issue. Returns false in this case. 58 | // 59 | // This is broken out to make it simple to test steps in unit tests. 60 | bool SingleCycle(unsigned timeout_ms); 61 | 62 | private: 63 | typedef std::map HandlerMap; 64 | 65 | // Call all the handlers available in fd_set, removing the ones that 66 | // return 'false'. "available_fds" is an optimizatin that tells CallHandlers 67 | // how many fds there are in the first place. 68 | void CallHandlers(fd_set *to_call_fd_set, int *available_fds, 69 | HandlerMap *handlers); 70 | 71 | const unsigned idle_ms_; 72 | HandlerMap read_handlers_; 73 | HandlerMap write_handlers_; 74 | std::list idle_handlers_; 75 | }; 76 | 77 | #endif // FD_MUX_H_ 78 | -------------------------------------------------------------------------------- /src/common/linebuf-reader.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #include "common/linebuf-reader.h" 20 | 21 | #include "common/string-util.h" 22 | 23 | LinebufReader::LinebufReader(size_t buffer_size) 24 | : len_(buffer_size), 25 | buffer_start_(new char[len_]), 26 | buffer_end_(buffer_start_ + len_), 27 | content_start_(buffer_start_), 28 | content_end_(buffer_start_), 29 | cr_seen_(false) {} 30 | LinebufReader::~LinebufReader() { delete[] buffer_start_; } 31 | 32 | ssize_t LinebufReader::Update(const ReadFun &read_fun) { 33 | if (content_start_ - buffer_start_ > (int)(len_ / 2)) { 34 | const size_t copy_len = size(); 35 | memmove(buffer_start_, content_start_, copy_len); 36 | content_start_ = buffer_start_; 37 | content_end_ = buffer_start_ + copy_len; 38 | } 39 | const ssize_t r = read_fun(content_end_, buffer_end_ - content_end_); 40 | // TODO(hzeller): if we get zero, we should consider this as end-of-stream 41 | // and potentially regard the buffer as 'complete' even if it doesn't have a 42 | // full line yet. 43 | if (r >= 0) content_end_ += r; // so, what if r < 0 ? 44 | return r; 45 | } 46 | 47 | const char *LinebufReader::IncompleteLine() { 48 | *content_end_ = '\n'; 49 | content_end_++; 50 | return ReadAndConsumeLine(); 51 | } 52 | 53 | const char *LinebufReader::ReadAndConsumeLine() { 54 | for (char *i = content_start_; i < content_end_; ++i) { 55 | if (cr_seen_ && *i == '\n') { 56 | cr_seen_ = false; 57 | content_start_ = i + 1; 58 | continue; 59 | } 60 | if (*i == '\r' || *i == '\n') { 61 | cr_seen_ = (*i == '\r'); 62 | *i = '\0'; 63 | const char *line = content_start_; 64 | content_start_ = i + 1; 65 | return line; 66 | } 67 | } 68 | return nullptr; 69 | } 70 | -------------------------------------------------------------------------------- /src/common/linebuf-reader.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_LINEBUF_READER_H 20 | #define _BEAGLEG_LINEBUF_READER_H 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | // Tokenizes a non-contiguous sequence of incoming data into lines. 28 | // 29 | // A buffer that can be updated with new bytes and then allows for extracting 30 | // lines separated by newlines up to that point. 31 | // 32 | // This is to be used in conjunction with file descriptor event management 33 | // such as select() or poll() which yield a random amount of bytes from a 34 | // file-descriptor. 35 | // 36 | // Usage: 37 | // void NewDataReady() { 38 | // reader.Update(/* with new data, see method signatures */); 39 | // // Get all the lines we have available now 40 | // while ((line = reader.ReadAndConsumeLine()) { 41 | // // do something with line 42 | // } 43 | // } 44 | class LinebufReader { 45 | public: 46 | // A function to read from some data source. Similar to read(2), it gets 47 | // a buffer and a maximums size it can write to and returns the number 48 | // of bytes it has actually written. 49 | // Returns a positive number for read bytes, zero if we are end-of-stream 50 | // and a negative number to indicate error. 51 | typedef std::function ReadFun; 52 | 53 | // The "buffer_size" determines the longest line we expect at maximum. 54 | // TODO(hzeller): right now, we don't gracefully deal with overlong lines. 55 | explicit LinebufReader(size_t buffer_size = 16384); 56 | ~LinebufReader(); 57 | 58 | // Update content. It will be calling the ReadFun exactly once and updates 59 | // its internal buffer. 60 | // After this, you may call ReadLine() to extract as many lines as had 61 | // been waiting. 62 | // If you made sure that there is data available before calling Update(), 63 | // this will not block. 64 | // Returns the value returned by ReadFun. 65 | ssize_t Update(const ReadFun &read_fun); 66 | 67 | // The tpical way this will be called: with a file descriptor that has some 68 | // bytes ready. 69 | ssize_t Update(int fd) { 70 | return Update([fd](char *buf, size_t len) { return read(fd, buf, len); }); 71 | } 72 | 73 | // Return a current line if it is available. The line is a nul terminated 74 | // c-string without the newline character(s). 75 | // 76 | // If there is no current line pending, or it is incomplete, returns NULL. 77 | // It is a good idea to call this after a call to Update() in a loop until 78 | // you reach NULL to empty the buffer before the next Update() comes in. 79 | // 80 | // Returned data is only valid until next call to Update() or 81 | // ReadAndConsumeLine().. 82 | const char *ReadAndConsumeLine(); 83 | 84 | // Get the current incomplete line. This is useful to receive the final 85 | // data when finishing in case of a missing newline. 86 | // TODO(hzeller): maybe a function to get the remaining buffer when we 87 | // are closing the connection ? There might be some incomplete line in there. 88 | const char *IncompleteLine(); 89 | 90 | void Flush() { 91 | content_start_ = buffer_start_; 92 | content_end_ = buffer_start_; 93 | } 94 | 95 | // Currently stored in buffer. 96 | size_t size() const { return content_end_ - content_start_; } 97 | 98 | private: 99 | const size_t len_; 100 | char *const buffer_start_; 101 | const char *const buffer_end_; 102 | char *content_start_; 103 | char *content_end_; 104 | 105 | bool cr_seen_; 106 | }; 107 | 108 | #endif // _BEAGLEG_LINEBUF_READER_H 109 | -------------------------------------------------------------------------------- /src/common/logging.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #include "common/logging.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | static int log_fd = 2; // Allow logging before Log_init(). 35 | 36 | static const char *const kInfoHighlight = "\033[1mINFO "; 37 | static const char *const kDebugHighlight = "\033[1m\033[34mDEBUG "; 38 | static const char *const kErrorHighlight = "\033[1m\033[31mERROR "; 39 | static const char *const kTermReset = "\033[0m"; 40 | 41 | static const char *debug_markup_start_ = "DEBUG "; 42 | static const char *info_markup_start_ = "INFO "; 43 | static const char *error_markup_start_ = "ERROR "; 44 | static const char *markup_end_ = ""; 45 | 46 | void Log_init(const char *filename) { 47 | if (filename == NULL || strlen(filename) == 0) { 48 | openlog(NULL, LOG_PID | LOG_CONS, LOG_DAEMON); 49 | log_fd = -1; 50 | } else { 51 | log_fd = open(filename, O_CREAT | O_APPEND | O_WRONLY, 0644); 52 | if (log_fd < 0) { 53 | perror("Cannot open logfile"); 54 | openlog(NULL, LOG_PID | LOG_CONS, LOG_DAEMON); // fallback. 55 | return; 56 | } 57 | bool enable_color = isatty(log_fd); 58 | if (enable_color) { 59 | info_markup_start_ = kInfoHighlight; 60 | debug_markup_start_ = kDebugHighlight; 61 | error_markup_start_ = kErrorHighlight; 62 | markup_end_ = kTermReset; 63 | } 64 | } 65 | } 66 | 67 | static void Log_internal(int fd, const char *markup_start, const char *format, 68 | va_list ap) { 69 | struct timeval now; 70 | gettimeofday(&now, NULL); 71 | struct tm time_breakdown; 72 | localtime_r(&now.tv_sec, &time_breakdown); 73 | char fmt_buf[128]; 74 | strftime(fmt_buf, sizeof(fmt_buf), "%F %T", &time_breakdown); 75 | struct iovec parts[3]; 76 | parts[0].iov_len = asprintf((char **)&parts[0].iov_base, "%s[%s.%06ld]%s ", 77 | markup_start, fmt_buf, now.tv_usec, markup_end_); 78 | parts[1].iov_len = vasprintf((char **)&parts[1].iov_base, format, ap); 79 | parts[2].iov_base = (void *)"\n"; 80 | parts[2].iov_len = 1; 81 | int already_newline = 82 | (parts[1].iov_len > 0 && 83 | ((const char *)parts[1].iov_base)[parts[1].iov_len - 1] == '\n'); 84 | if (writev(fd, parts, already_newline ? 2 : 3) < 0) { 85 | // Logging trouble. Ignore. 86 | } 87 | 88 | free(parts[0].iov_base); 89 | free(parts[1].iov_base); 90 | } 91 | 92 | void Log_debug(const char *format, ...) { 93 | if (log_fd < 0) return; 94 | va_list ap; 95 | va_start(ap, format); 96 | Log_internal(log_fd, debug_markup_start_, format, ap); 97 | va_end(ap); 98 | } 99 | 100 | void Log_info(const char *format, ...) { 101 | va_list ap; 102 | va_start(ap, format); 103 | if (log_fd < 0) { 104 | vsyslog(LOG_INFO, format, ap); 105 | } else { 106 | Log_internal(log_fd, info_markup_start_, format, ap); 107 | } 108 | va_end(ap); 109 | } 110 | 111 | void Log_error(const char *format, ...) { 112 | va_list ap; 113 | va_start(ap, format); 114 | if (log_fd < 0) { 115 | vsyslog(LOG_ERR, format, ap); 116 | } else { 117 | Log_internal(log_fd, error_markup_start_, format, ap); 118 | } 119 | va_end(ap); 120 | } 121 | -------------------------------------------------------------------------------- /src/common/logging.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef BEAGLEG_LOGGING_H 21 | #define BEAGLEG_LOGGING_H 22 | 23 | #include 24 | 25 | // With filename given, logs debug, info and error to that file. 26 | // If filename is NULL, info and errors are logged to syslog. 27 | void Log_init(const char *filename); 28 | 29 | // Define this with empty, if you're not using gcc. 30 | #define PRINTF_FMT_CHECK(fmt_pos, args_pos) \ 31 | __attribute__((format(printf, fmt_pos, args_pos))) 32 | 33 | void Log_debug(const char *format, ...) PRINTF_FMT_CHECK(1, 2); 34 | void Log_info(const char *format, ...) PRINTF_FMT_CHECK(1, 2); 35 | void Log_error(const char *format, ...) PRINTF_FMT_CHECK(1, 2); 36 | 37 | #undef PRINTF_FMT_CHECK 38 | 39 | #endif /* BEAGLEG_LOGGING_H */ 40 | -------------------------------------------------------------------------------- /src/common/string-util.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_STRING_UTIL_H 20 | #define _BEAGLEG_STRING_UTIL_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | // Define this with empty, if you're not using gcc. 32 | #define PRINTF_FMT_CHECK(fmt_pos, args_pos) \ 33 | __attribute__((format(printf, fmt_pos, args_pos))) 34 | 35 | // Trim std::string_view of whitespace font and back and returned trimmed 36 | // string. 37 | std::string_view TrimWhitespace(std::string_view s); 38 | 39 | // Lowercase the string (simple ASCII) and return as newly allocated 40 | // std::string 41 | std::string ToLower(std::string_view in); 42 | 43 | // Test if given std::string_view is prefix of the other. 44 | bool HasPrefix(std::string_view s, std::string_view prefix); 45 | 46 | // Formatted printing into a string. 47 | std::string StringPrintf(const char *format, ...) PRINTF_FMT_CHECK(1, 2); 48 | 49 | // Split a string at any of the given separator characters. 50 | std::vector SplitString(std::string_view s, 51 | std::string_view separators); 52 | 53 | // Parse a number from a std::string_view into "result". Returns the 54 | // end of the number on success, nullptr otherwise. 55 | // So this can be used in a simple boolean context for simple success 56 | // testing, but as well in parsing context where advancing to the next position 57 | // is needed. 58 | const char *convert_strto32(std::string_view s, int32_t *result); 59 | const char *convert_strto64(std::string_view s, int64_t *result); 60 | const char *convert_strtof(std::string_view s, float *result); 61 | const char *convert_strtod(std::string_view s, double *result); 62 | 63 | // Possible convenience functions 64 | // bool consume_strtof(std::string_view *s, float *result); 65 | 66 | // Parse integer. On success, return parsed number, fallback otherwise. 67 | int64_t ParseInt64(std::string_view s, int64_t fallback); 68 | 69 | #undef PRINTF_FMT_CHECK 70 | #endif // _BEAGLEG_STRING_UTIL_H 71 | -------------------------------------------------------------------------------- /src/common/string-util_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "common/string-util.h" 21 | 22 | #include 23 | 24 | TEST(StringUtilTest, TrimWhitespace) { 25 | EXPECT_EQ("hello", TrimWhitespace(" \t hello \n\r ")); 26 | EXPECT_TRUE(TrimWhitespace(" \t ").empty()); 27 | } 28 | 29 | TEST(StringUtilTest, ASCIIToLower) { 30 | EXPECT_EQ("hello world", ToLower("Hello WORLD")); 31 | EXPECT_EQ("hello world", ToLower("Hello WORLD")); 32 | } 33 | 34 | TEST(StringUtilTest, HasPrefix) { 35 | EXPECT_TRUE(HasPrefix("hello world", "hello")); 36 | EXPECT_FALSE(HasPrefix("hello world", "hellO")); 37 | } 38 | 39 | TEST(StringUtilTest, SplitString) { 40 | std::vector result = SplitString("foo", ","); 41 | EXPECT_EQ(1, (int)result.size()); 42 | EXPECT_EQ("foo", result[0]); 43 | 44 | result = SplitString(",hello, world", ","); 45 | EXPECT_EQ(3, (int)result.size()); 46 | EXPECT_EQ("", result[0]); 47 | EXPECT_EQ("hello", result[1]); 48 | EXPECT_EQ(" world", result[2]); 49 | 50 | // Also test with trailing, empty field 51 | result = SplitString(",hello, world,", ","); 52 | EXPECT_EQ(4, (int)result.size()); 53 | EXPECT_EQ("", result[0]); 54 | EXPECT_EQ("hello", result[1]); 55 | EXPECT_EQ(" world", result[2]); 56 | EXPECT_EQ("", result[3]); 57 | } 58 | 59 | TEST(StringUtilTest, ParseDecimalInt) { 60 | int64_t value; 61 | EXPECT_FALSE(convert_strto64("hello", &value)); 62 | EXPECT_TRUE(convert_strto64("123", &value)); 63 | EXPECT_EQ(123, value); 64 | EXPECT_TRUE(convert_strto64("+456", &value)); 65 | EXPECT_EQ(456, value); 66 | EXPECT_TRUE(convert_strto64("-789", &value)); 67 | EXPECT_EQ(-789, value); 68 | EXPECT_TRUE(convert_strto64(" 123 ", &value)); 69 | EXPECT_EQ(123, value); 70 | 71 | // Make sure we can parse beyond 32 bit. 72 | EXPECT_EQ(12345678901234LL, ParseInt64("12345678901234", -1)); 73 | 74 | // Make sure we're not assumming a nul-byte at a particular point 75 | std::string_view longer_string("4255"); 76 | EXPECT_EQ(42, ParseInt64(longer_string.substr(0, 2), -1)); 77 | 78 | // Make sure the returned value points to the characters after the number. 79 | const std::string_view input = " +314cm"; 80 | const std::string_view expected_remain = input.substr(input.find("cm")); 81 | const char *remain_string = convert_strto64(input, &value); 82 | ASSERT_TRUE(remain_string); 83 | EXPECT_EQ(314, value); 84 | EXPECT_EQ(remain_string, expected_remain.data()); // pointers must match. 85 | } 86 | 87 | TEST(StringUtilTest, ParseFloat) { 88 | float value; 89 | EXPECT_FALSE(convert_strtof("hello", &value)); 90 | EXPECT_TRUE(convert_strtof("123", &value)); 91 | EXPECT_EQ(123, value); 92 | EXPECT_TRUE(convert_strtof("+456.5", &value)); 93 | EXPECT_EQ(456.5, value); 94 | EXPECT_TRUE(convert_strtof("-789", &value)); 95 | EXPECT_EQ(-789, value); 96 | EXPECT_TRUE(convert_strtof(" 123 ", &value)); // leading space 97 | EXPECT_EQ(123, value); 98 | 99 | // Make sure the returned value points to the characters after the number. 100 | const std::string_view input = " +314.159cm"; 101 | const std::string_view expected_remain = input.substr(input.find("cm")); 102 | const char *remain_string = convert_strtof(input, &value); 103 | ASSERT_TRUE(remain_string); 104 | EXPECT_NEAR(314.159, value, 0.0001); 105 | EXPECT_EQ(remain_string, expected_remain.data()); // pointers must match. 106 | } 107 | 108 | TEST(StringUtilTest, ParseDouble) { 109 | double value; 110 | EXPECT_FALSE(convert_strtod("hello", &value)); 111 | EXPECT_TRUE(convert_strtod("123", &value)); 112 | EXPECT_EQ(123, value); 113 | EXPECT_TRUE(convert_strtod("+456.5", &value)); 114 | EXPECT_EQ(456.5, value); 115 | EXPECT_TRUE(convert_strtod("-789", &value)); 116 | EXPECT_EQ(-789, value); 117 | EXPECT_TRUE(convert_strtod(" 123 ", &value)); 118 | EXPECT_EQ(123, value); 119 | 120 | // Make sure the returned value points to the characters after the number. 121 | const std::string_view input = " +314.159cm"; 122 | const std::string_view expected_remain = input.substr(input.find("cm")); 123 | const char *remain_string = convert_strtod(input, &value); 124 | ASSERT_TRUE(remain_string); 125 | EXPECT_NEAR(314.159, value, 0.00001); 126 | EXPECT_EQ(remain_string, expected_remain.data()); // pointers must match. 127 | } 128 | 129 | int main(int argc, char *argv[]) { 130 | ::testing::InitGoogleTest(&argc, argv); 131 | return RUN_ALL_TESTS(); 132 | } 133 | -------------------------------------------------------------------------------- /src/config-parser.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_CONFIG_PARSER_H 20 | #define _BEAGLEG_CONFIG_PARSER_H 21 | 22 | #include 23 | #include 24 | 25 | #include "common/string-util.h" 26 | 27 | // The config parser reads a configuration file and passes tokenized 28 | // values to a ConfigParser::Reader. 29 | // The configuration is organized in sections, starting with a [section] 30 | // header. Within each section, there are name = value pairs (and optional 31 | // #-comments.) 32 | // 33 | // A reader is informed whenever a new section comes up and asked if it is 34 | // interested in the values. If so, all name/value pairs in that section are 35 | // passed on to the reader. 36 | // 37 | // With this set-up, we can have one configuration file that is easily 38 | // extendable with new sections without any of the configuration readers being 39 | // confused about content not meant for them. 40 | class ConfigParser { 41 | public: 42 | // A reader has to be implemented by a subsystem that needs configuration 43 | // from the file. 44 | class Reader { 45 | public: 46 | virtual ~Reader() {} 47 | 48 | // Inform about new section. If the Reader is interested in 49 | // name/value pairs seen in that section, it should return 'true'. 50 | virtual bool SeenSection(int line_no, const std::string §ion_name) = 0; 51 | 52 | // SeenNameValue() is only called if this Reader expressed interest 53 | // in the current section. Returns 'true' if it could deal with the 54 | // name/value, 'false' if there was an error and the configuration should 55 | // be deemed invalid. 56 | virtual bool SeenNameValue(int line_no, const std::string &name, 57 | const std::string &value) = 0; 58 | 59 | virtual void ReportError(int line_no, const std::string &msg); 60 | 61 | protected: 62 | // Convenience functions that can be used in derived readers. 63 | // All the Accept() functions are done in the way that they always return 64 | // 'true' if the expected name is not matched, otherwise they return the 65 | // outcome of parsing the value. That way, they can be chained with && 66 | static bool ParseString(std::string_view value, std::string *result); 67 | static bool ParseInt(std::string_view value, int32_t *result); 68 | static bool ParseBool(std::string_view value, bool *result); 69 | static bool ParseFloatExpr(const std::string &value, float *result); 70 | }; 71 | 72 | // Create a config parser. 73 | ConfigParser() = default; 74 | 75 | // Set content of configuration by reading from the file. Returns 'true' 76 | // if reading the file was successful. 77 | // (Note, this will read in the whole configuration file in memory, but 78 | // they are by their very nature smallish in size). 79 | // Overwrites any previous content. 80 | bool SetContentFromFile(const char *filename); 81 | 82 | // Set content of configuration file as one string. Typically useful in 83 | // unit tests. 84 | // Overwrites any previous content. 85 | void SetContent(std::string_view content); 86 | 87 | // Emit configuration values to the Reader for all sections it is interested 88 | // in. 89 | // 90 | // This method can be called many times with different Readers. The 91 | // ConfigParser is handed to various subsystems of the machine-config for 92 | // each of them to configure itself. This allows the ConfigParser to focus on 93 | // tokenization and the configured subsections to ingest name/values. 94 | // 95 | // The parser informes the reader about new sections it has seen 96 | // (calling SeenSection()) and asks if the reader is interested in 97 | // name/value pairs in that section. If so, it provides the reader with these 98 | // calling SeenNameValue(). 99 | // 100 | // Returns 'true' if configuration file could be parsed (no syntax errors, 101 | // and all calls to SeenNameValue() returned true). 102 | // 103 | // Reader-ownership is not taken over. 104 | bool EmitConfigValues(Reader *reader) const; 105 | 106 | private: 107 | std::string content_; 108 | }; 109 | #endif // _BEAGLEG_CONFIG_PARSER_H 110 | -------------------------------------------------------------------------------- /src/config-parser_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "config-parser.h" 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | using ::testing::Return; 28 | 29 | namespace { 30 | class MockConfigReader : public ConfigParser::Reader { 31 | public: 32 | MOCK_METHOD2(SeenSection, bool(int line_no, const std::string §ion_name)); 33 | MOCK_METHOD3(SeenNameValue, bool(int line_no, const std::string &name, 34 | const std::string &value)); 35 | MOCK_METHOD2(ReportError, void(int line_no, const std::string &msg)); 36 | }; 37 | 38 | } // namespace 39 | 40 | TEST(ConfigParserTest, BasicParser) { 41 | ConfigParser p; 42 | p.SetContent( 43 | " [ SOME-section ]\n" 44 | " # just comment\n" 45 | "\n\n" 46 | " some line = bar # foo\n" 47 | "another line = x\r\n" 48 | " something = unfinished-line"); 49 | MockConfigReader events; 50 | EXPECT_CALL(events, SeenSection(1, "some-section")).WillOnce(Return(true)); 51 | EXPECT_CALL(events, SeenNameValue(5, "some line", "bar")) 52 | .WillOnce(Return(true)); 53 | EXPECT_CALL(events, SeenNameValue(6, "another line", "x")) 54 | .WillOnce(Return(true)); 55 | EXPECT_CALL(events, SeenNameValue(7, "something", "unfinished-line")) 56 | .WillOnce(Return(true)); 57 | EXPECT_TRUE(p.EmitConfigValues(&events)); 58 | } 59 | 60 | TEST(ConfigParserTest, ErrorReporting) { 61 | ConfigParser p; 62 | p.SetContent( 63 | " incomplete line\n" 64 | "[ incomplete-section \n"); 65 | 66 | MockConfigReader events; 67 | EXPECT_CALL(events, ReportError(1, "name=value pair expected.")); 68 | EXPECT_CALL(events, ReportError(2, "Section line does not end in ']'")); 69 | 70 | EXPECT_FALSE(p.EmitConfigValues(&events)); 71 | } 72 | 73 | int main(int argc, char *argv[]) { 74 | ::testing::InitGoogleTest(&argc, argv); 75 | return RUN_ALL_TESTS(); 76 | } 77 | -------------------------------------------------------------------------------- /src/determine-print-stats.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_DETERMINE_PRINT_STATS_H 20 | #define _BEAGLEG_DETERMINE_PRINT_STATS_H 21 | 22 | #include 23 | 24 | struct MachineControlConfig; // gcode-machine-control.h 25 | 26 | struct BeagleGPrintStats { 27 | float total_time_seconds; // Total time real execution would take. 28 | float x_min, x_max; // coordinate ranges. 29 | float y_min, y_max; 30 | float z_min, z_max; 31 | float last_z_extruding; // Last z with extrusion = printed height. 32 | float filament_len; // total filament length 33 | }; 34 | 35 | // Given the input file-descriptor (which is read to EOF and then closed) 36 | // and the given constraints, determine statistics about the gcode-file. 37 | // Returns true on success. 38 | bool determine_print_stats(int input_fd, const MachineControlConfig &config, 39 | FILE *msg_out, struct BeagleGPrintStats *result); 40 | #endif // _BEAGLEG_DETERMINE_PRINT_STATS_H 41 | -------------------------------------------------------------------------------- /src/gcode-parser/Makefile: -------------------------------------------------------------------------------- 1 | # (c) 2013 h.zeller@acm.org 2 | # This is free software. License: GNU 3.0 3 | 4 | # Location of testing framework 5 | GTEST_INCLUDE=$(shell pkg-config --cflags-only-I gtest gmock 2>/dev/null || echo "-I/usr/include") 6 | GTEST_LIBS=$(shell pkg-config --libs gtest gmock 2>/dev/null || echo "-lgtest -lgmock") 7 | 8 | # Optmization flags. Typically, that should be -O3 for regluar use, but for 9 | # debugging and development "-g -O0" can be more helpful. Overridable by 10 | # environment variable. 11 | BEAGLEG_OPT_CFLAGS?=-O3 12 | 13 | CFLAGS+=-Wall -Wextra -W -Wno-unused-parameter -D_XOPEN_SOURCE=500 $(ARM_COMPILE_FLAGS) $(BEAGLEG_OPT_CFLAGS) -I$(shell pwd)/.. 14 | 15 | CXXFLAGS+=-std=c++17 $(CFLAGS) 16 | CXX?=g++ 17 | 18 | LDFLAGS+=-lpthread -lm 19 | 20 | COMMON_LIBS=../common/libbeaglegbase.a 21 | 22 | OBJECTS=gcode-parser.o gcode-streamer.o arc-gen.o simple-lexer.o \ 23 | gcode-parser-config.o 24 | GENLIB=libgcodeparser.a 25 | 26 | UNITTEST_BINARIES=gcode-parser_test gcode-streamer_test arc-gen_test simple-lexer_test 27 | 28 | DEPENDENCY_RULES=$(OBJECTS:=.d) $(UNITTEST_BINARIES:=.o.d) $(MAIN_OBJECTS:=.d) 29 | 30 | all : $(GENLIB) 31 | 32 | $(GENLIB): $(OBJECTS) 33 | $(AR) rcs $@ $^ 34 | 35 | ../common/libbeaglegbase.a: 36 | $(MAKE) -C ../common 37 | 38 | test-binaries: $(UNITTEST_BINARIES) 39 | 40 | test: test-binaries 41 | for test_bin in $(UNITTEST_BINARIES) ; do echo ; echo $$test_bin; ./$$test_bin || exit 1 ; done 42 | 43 | valgrind-test: test-binaries 44 | for test_bin in $(UNITTEST_BINARIES) ; do valgrind --track-origins=yes --leak-check=full --error-exitcode=1 -q ./$$test_bin || exit 1; done 45 | 46 | 47 | %_test: %_test.o $(GENLIB) $(COMMON_LIBS) $(TEST_FRAMEWORK_OBJECTS) compiler-flags 48 | $(CROSS_COMPILE)$(CXX) -o $@ $< $(GENLIB) $(COMMON_LIBS) $(GTEST_LIBS) $(LDFLAGS) 49 | 50 | %.o: %.cc compiler-flags 51 | $(CROSS_COMPILE)$(CXX) $(CXXFLAGS) -c $< -o $@ 52 | @$(CROSS_COMPILE)$(CXX) $(CXXFLAGS) -MM $< > $@.d 53 | 54 | %_test.o: %_test.cc compiler-flags 55 | $(CROSS_COMPILE)$(CXX) $(GTEST_INCLUDE) -Wno-inconsistent-missing-override $(CXXFLAGS) -c $< -o $@ 56 | @$(CROSS_COMPILE)$(CXX) $(GTEST_INCLUDE) $(CXXFLAGS) -MM $< > $@.d 57 | 58 | # Auto generated dependencies 59 | -include $(DEPENDENCY_RULES) 60 | 61 | clean: 62 | rm -rf $(GENLIB) $(OBJECTS) $(UNITTEST_BINARIES) $(UNITTEST_BINARIES:=.o) $(DEPENDENCY_RULES) *.gcda *.gcov *.gcno *.cc.html *.h.html 63 | 64 | compiler-flags: FORCE 65 | @echo '$(CXX) $(CXXFLAGS) $(GTEST_INCLUDE)' | cmp -s - $@ || echo '$(CXX) $(CXXFLAGS) $(GTEST_INCLUDE)' > $@ 66 | 67 | .PHONY: FORCE 68 | 69 | .SECONDARY: $(UNITTEST_BINARIES:=.o) 70 | -------------------------------------------------------------------------------- /src/gcode-parser/README.md: -------------------------------------------------------------------------------- 1 | Library providing a stand-alone 2 | [gcode parser API with callbacks](./gcode-parser.h). 3 | 4 | Depends on common lib. 5 | -------------------------------------------------------------------------------- /src/gcode-parser/gcode-parser-config.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "common/logging.h" 25 | #include "gcode-parser/gcode-parser.h" 26 | 27 | bool GCodeParser::Config::LoadParams() { 28 | if (paramfile.empty()) return false; 29 | if (parameters == NULL) { 30 | Log_error("No parameters to load into."); 31 | return false; 32 | } 33 | 34 | // The default coordinate system at start-up is G54 35 | (*parameters)["5220"] = 1.0f; // Only non-zero default. // NOLINT 36 | 37 | FILE *fp = fopen(paramfile.c_str(), "r"); 38 | if (!fp) { 39 | Log_error("Unable to read param file %s (%s)", paramfile.c_str(), 40 | strerror(errno)); 41 | return false; 42 | } 43 | 44 | int pcount = 0; 45 | char line[256]; 46 | while (fgets(line, sizeof(line), fp)) { 47 | char name[256]; 48 | float value; 49 | if (sscanf(line, "%s %f", name, &value) == 2) { 50 | // Technically, we should ignore parameters which are not coming in 51 | // order according to RS274NGC. But that sounds like a non-userfriendly 52 | // restriction. 53 | (*parameters)[name] = value; // NOLINT 54 | ++pcount; 55 | } 56 | } 57 | Log_debug("Loaded %d parameters from %s", pcount, paramfile.c_str()); 58 | fclose(fp); 59 | return true; 60 | } 61 | 62 | bool GCodeParser::Config::SaveParams() const { 63 | if (paramfile.empty()) return false; 64 | if (parameters == NULL) { 65 | Log_error("No parameters to save."); 66 | return false; 67 | } 68 | 69 | const std::string tmp_name = paramfile + ".tmp"; 70 | // create new param file 71 | FILE *fp = fopen(tmp_name.c_str(), "w"); 72 | if (!fp) { 73 | const int err = errno; 74 | Log_error("Unable to write temporary param file %s (%s)", tmp_name.c_str(), 75 | strerror(err)); 76 | if (err == EACCES) { 77 | const std::string dir = paramfile.substr(0, paramfile.find_last_of('/')); 78 | Log_error( 79 | "Params-file permission problem: Need write access to %s/ " 80 | "(FYI we run as uid=%d, gid=%d; Consider --priv option.)", 81 | dir.c_str(), getuid(), getgid()); 82 | } 83 | return false; 84 | } 85 | 86 | int pcount = 0; 87 | // We have to go through the list twice. The numeric parameters need to be 88 | // stored in numerical order, followed by all the alphanumeric fields. 89 | // 90 | // Given that we are using a string-key in the map, the numeric fields are 91 | // sorted alphanumerically, which is not the same as numerically. So we 92 | // simply copy them to a temporary structure that sorts them numerically. 93 | std::map numeric_params; 94 | for (const auto &name_value : *parameters) { 95 | if (name_value.first.empty()) continue; // Should not happen. 96 | if (!isdigit(name_value.first[0])) break; // last one with digit. 97 | numeric_params[atoi(name_value.first.c_str())] = name_value.second; 98 | } 99 | 100 | for (const auto &num_value : numeric_params) { 101 | if (num_value.first == 0) 102 | continue; // Never write this parameter. It should always be zero 103 | if (num_value.second != 0) { 104 | fprintf(fp, "%i\t%f\n", num_value.first, num_value.second); 105 | ++pcount; 106 | } 107 | } 108 | 109 | // Now, all the non-numeric parmeters 110 | int start_alpha = pcount; 111 | for (const auto &name_value : *parameters) { 112 | if (name_value.first.empty()) continue; // Should not happen. 113 | if (isdigit(name_value.first[0])) continue; // Numeric: already written 114 | if (name_value.first[0] != '_') continue; // Only write global parameters 115 | if (name_value.second == 0) continue; // Don't write boring zeroes. 116 | if (pcount == start_alpha) { 117 | fprintf(fp, "\n# Alphanumeric global parameters\n"); 118 | } 119 | fprintf(fp, "%s\t%f\n", name_value.first.c_str(), name_value.second); 120 | ++pcount; 121 | } 122 | Log_debug("Saving %d parameters to %s", pcount, paramfile.c_str()); 123 | 124 | if (fflush(fp) == 0 && fdatasync(fileno(fp)) == 0 && fclose(fp) == 0) { 125 | rename(paramfile.c_str(), (paramfile + ".bak").c_str()); 126 | if (rename(tmp_name.c_str(), paramfile.c_str()) == 0) return true; 127 | } 128 | Log_error("Trouble writing parameter file %s (%s)", paramfile.c_str(), 129 | strerror(errno)); 130 | return false; 131 | } 132 | -------------------------------------------------------------------------------- /src/gcode-parser/gcode-streamer.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2018 Leonardo Romor 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #include "gcode-parser/gcode-streamer.h" 20 | 21 | #include 22 | #include 23 | 24 | #include "common/logging.h" 25 | 26 | GCodeStreamer::GCodeStreamer(FDMultiplexer *event_server, GCodeParser *parser, 27 | GCodeParser::EventReceiver *parse_events) 28 | : event_server_(event_server), 29 | parser_(parser), 30 | parse_events_(parse_events), 31 | is_processing_(false), 32 | connection_fd_(-1), 33 | lines_processed_(0) { 34 | // Let's start the input idle tasklet 35 | // TODO: the lifetime implications are a bit problematic as we need to 36 | // outlive the Loop() of the event server. 37 | event_server_->RunOnIdle([this]() { return Timeout(); }); 38 | } 39 | 40 | bool GCodeStreamer::ConnectStream(int fd, FILE *msg_stream) { 41 | if (connection_fd_ >= 0) { 42 | return false; // Alrady connected. 43 | } 44 | 45 | // Stuff written to msg-stream needs to be unbuffered, otherwise 46 | // they'll not make it in timely response to the input. 47 | if (msg_stream) setvbuf(msg_stream, NULL, _IONBF, 0); 48 | 49 | msg_stream_ = msg_stream; 50 | connection_fd_ = fd; 51 | lines_processed_ = 0; 52 | 53 | event_server_->RunOnReadable(connection_fd_, [this]() { return ReadData(); }); 54 | return true; 55 | } 56 | 57 | void GCodeStreamer::CloseStream() { 58 | if (msg_stream_) { 59 | fflush(msg_stream_); 60 | } 61 | close(connection_fd_); 62 | connection_fd_ = -1; 63 | Log_info("Processed %d GCode blocks.", lines_processed_); 64 | } 65 | 66 | // New data to be fed into the linebuffer 67 | bool GCodeStreamer::ReadData() { 68 | // Update buffer with fresh data 69 | const ssize_t data_read = line_tokenize_buffer_.Update(connection_fd_); 70 | 71 | if (data_read <= 0) { 72 | if (data_read < 0) { 73 | Log_error("Error reading from stream (%s). Treating as EOF.", 74 | strerror(errno)); 75 | } 76 | Log_info("Reached EOF."); 77 | 78 | // Parse any potentially remaining gcode from previous connections. 79 | const char *line = line_tokenize_buffer_.IncompleteLine(); 80 | if (line) { 81 | parser_->ParseBlock(line, msg_stream_); 82 | } 83 | 84 | // always call gcode_finished() to disable motors at end of stream 85 | parse_events_->gcode_finished(true); 86 | CloseStream(); 87 | is_processing_ = false; 88 | return false; // We're done processing, remove us from fd-mux 89 | } 90 | 91 | is_processing_ = true; 92 | const char *line; 93 | while ((line = line_tokenize_buffer_.ReadAndConsumeLine())) { 94 | // NOTE:(important) 95 | // This should return true or false in case the line was movement or not 96 | // and only if is, reset the timer. 97 | parser_->ParseBlock(line, msg_stream_); 98 | ++lines_processed_; 99 | } 100 | 101 | // Loop again 102 | return true; 103 | } 104 | 105 | // We didn't receive a line within x milliseconds. 106 | bool GCodeStreamer::Timeout() { 107 | parse_events_->input_idle(is_processing_); 108 | is_processing_ = false; 109 | return true; 110 | } 111 | -------------------------------------------------------------------------------- /src/gcode-parser/gcode-streamer.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2018 Leonardo Romor 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef FD_GCODE_STREAMER_H_ 20 | #define FD_GCODE_STREAMER_H_ 21 | 22 | #include "common/fd-mux.h" 23 | #include "common/linebuf-reader.h" 24 | #include "gcode-parser/gcode-parser.h" 25 | 26 | class GCodeStreamer { 27 | public: 28 | // GCodeStreamer needs to outlive FDMultiplexer. 29 | GCodeStreamer(FDMultiplexer *event_server, GCodeParser *parser, 30 | GCodeParser::EventReceiver *parse_events); 31 | 32 | // Reads GCode lines from "fd" and feeds them to the GCodeParser. 33 | // Error messages are sent to "err_stream" if non-NULL. 34 | // Reads until EOF. 35 | // The input file descriptor is closed. 36 | bool ConnectStream(int fd, FILE *msg_stream); 37 | 38 | // Returns true if we are already connected to a stream. 39 | bool IsStreaming() { return connection_fd_ >= 0; } 40 | 41 | private: 42 | void CloseStream(); 43 | 44 | FDMultiplexer *const event_server_; 45 | GCodeParser *const parser_; 46 | GCodeParser::EventReceiver *const parse_events_; 47 | 48 | LinebufReader line_tokenize_buffer_; 49 | bool is_processing_; 50 | 51 | FILE *msg_stream_; 52 | int connection_fd_; 53 | int lines_processed_; 54 | 55 | bool ReadData(); 56 | bool Timeout(); 57 | }; 58 | 59 | #endif // FD_TASK_H_ 60 | -------------------------------------------------------------------------------- /src/gcode-parser/simple-lexer.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "gcode-parser/simple-lexer.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | static const char *skip_white(const char *line) { 28 | while (*line && isspace(*line)) line++; 29 | return line; 30 | } 31 | 32 | class SimpleLexerBase::Node { 33 | public: 34 | Node() {} 35 | 36 | Node *next_character[256] = {}; 37 | int value = 0; 38 | }; 39 | 40 | SimpleLexerBase::SimpleLexerBase() : root_(new Node()) {} 41 | 42 | SimpleLexerBase::~SimpleLexerBase() { 43 | for (size_t i = 0; i < to_delete_.size(); ++i) { 44 | delete to_delete_[i]; 45 | } 46 | delete root_; 47 | } 48 | 49 | void SimpleLexerBase::AddKeywordIntValue(const char *keyword, int value) { 50 | assert(value > 0); 51 | AddKeywordAtNode(root_, keyword, value); 52 | if (keyword_mappings_.find(value) == keyword_mappings_.end()) { 53 | keyword_mappings_[value] = keyword; 54 | } 55 | } 56 | 57 | const char *SimpleLexerBase::ReverseMapToString(int value) { 58 | if (value == 0) return "?"; 59 | KeywordMap::const_iterator found = keyword_mappings_.find(value); 60 | if (found == keyword_mappings_.end()) return NULL; 61 | return found->second; 62 | } 63 | 64 | void SimpleLexerBase::AddKeywordAtNode(Node *node, const char *keyword, 65 | int value) { 66 | if (*keyword == '\0') { 67 | assert(node->value == 0); // otherwise, the same keyword is already there. 68 | node->value = value; 69 | } else { 70 | assert(!isspace(*keyword)); // Keywords cannot have spaces. 71 | const int up = toupper(*keyword); 72 | if (node->next_character[up] == NULL) { 73 | node->next_character[up] = new Node(); 74 | to_delete_.push_back(node->next_character[up]); 75 | } 76 | AddKeywordAtNode(node->next_character[up], keyword + 1, value); 77 | } 78 | } 79 | 80 | int SimpleLexerBase::ConsumeKeyword(const char **input) { 81 | int result = 0; 82 | const char *word = *input; 83 | word = skip_white(word); 84 | for (const Node *node = root_; node; ++word) { 85 | if (node->value > 0) { 86 | *input = skip_white(word); 87 | result = node->value; 88 | } 89 | node = node->next_character[toupper(*word)]; 90 | } 91 | return result; 92 | } 93 | -------------------------------------------------------------------------------- /src/gcode-parser/simple-lexer.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #include 20 | #include 21 | 22 | class SimpleLexerBase { 23 | public: 24 | ~SimpleLexerBase(); 25 | 26 | protected: 27 | SimpleLexerBase(); 28 | // Add a keyword and the corresponding value it should be associated with. 29 | // "value" needs to be > 0. 30 | void AddKeywordIntValue(const char *keyword, int value); 31 | int ConsumeKeyword(const char **input); 32 | const char *ReverseMapToString(int value); 33 | 34 | private: 35 | class Node; 36 | typedef std::map KeywordMap; 37 | 38 | void AddKeywordAtNode(Node *node, const char *keyword, int value); 39 | 40 | Node *root_; 41 | std::vector to_delete_; 42 | KeywordMap keyword_mappings_; 43 | }; 44 | 45 | // A simple keyword matcher that can deal with ambiguous prefixes 46 | // (e.g. '<' and '<='). 47 | // It is matching keywords and maps it to a particular enumeration. 48 | // to match keywords that are mapped to a particular enumeration. 49 | // Only requirement: The Enum needs to map value zero (0) to 'invalid keyword'. 50 | template 51 | class SimpleLexer : public SimpleLexerBase { 52 | public: 53 | // Register a keyword and the corresponding value it should be associated 54 | // with. The "value" needs to be > 0 (as 0 means 'no keyword'). 55 | // The keyword is remembered for the AsString() function. If multiple 56 | // keywords are added with the same enum, the first is remembered. 57 | void AddKeyword(const char *keyword, Enum value) { 58 | AddKeywordIntValue(keyword, value); 59 | } 60 | 61 | // Get string respresentation of keyword enum or NULL if it does not exist. 62 | const char *AsString(Enum e) { return ReverseMapToString(e); } 63 | 64 | // Attempts to consume next keyword greedily (longer match wins). 65 | // Advances the input the number of consumed characters if there was 66 | // a match. 67 | // The "input" pointer is modified to point to the first non-whitespace 68 | // character after the matched keyword on success. 69 | // Returns value of matched keyword or 0 if there was no match. 70 | Enum MatchNext(const char **input) { 71 | return static_cast(ConsumeKeyword(input)); 72 | } 73 | 74 | // Expect and consume a particular keyword, otherwise return false. 75 | bool ExpectNext(const char **input, Enum e) { 76 | const char *end = *input; 77 | if (MatchNext(&end) == e) { 78 | *input = end; 79 | return true; 80 | } 81 | return false; 82 | } 83 | }; 84 | -------------------------------------------------------------------------------- /src/gcode-parser/simple-lexer_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "gcode-parser/simple-lexer.h" 21 | 22 | #include 23 | 24 | enum MyKeywords { 25 | NO_KEYWORD, // the equivalent of 'not found' needs to be first 26 | KEYWORD_IF, 27 | KEYWORD_ELSE, 28 | KEYWORD_ELSEIF, 29 | KEYWORD_LT, 30 | KEYWORD_LE 31 | }; 32 | 33 | TEST(SimpleLexerTest, SimpleKeywordMatching) { 34 | SimpleLexer lexer; 35 | lexer.AddKeyword("if", KEYWORD_IF); 36 | lexer.AddKeyword("else", KEYWORD_ELSE); 37 | lexer.AddKeyword("elseif", KEYWORD_ELSEIF); 38 | lexer.AddKeyword("<", KEYWORD_LT); 39 | lexer.AddKeyword("<=", KEYWORD_LE); 40 | 41 | const char *word = "nothing"; 42 | EXPECT_EQ(NO_KEYWORD, lexer.MatchNext(&word)); 43 | EXPECT_EQ(std::string("nothing"), word); 44 | 45 | word = "elsx"; 46 | EXPECT_EQ(NO_KEYWORD, lexer.MatchNext(&word)); 47 | EXPECT_EQ(std::string("elsx"), word); 48 | 49 | word = "else"; 50 | EXPECT_EQ(KEYWORD_ELSE, lexer.MatchNext(&word)); 51 | EXPECT_EQ(std::string(""), word); 52 | 53 | word = "elsefoo"; 54 | EXPECT_EQ(KEYWORD_ELSE, lexer.MatchNext(&word)); 55 | EXPECT_EQ(std::string("foo"), word); 56 | 57 | word = "elseifbar"; 58 | EXPECT_EQ(KEYWORD_ELSEIF, lexer.MatchNext(&word)); 59 | EXPECT_EQ(std::string("bar"), word); 60 | 61 | word = "<"; 62 | EXPECT_EQ(KEYWORD_LT, lexer.MatchNext(&word)); 63 | EXPECT_EQ(std::string(""), word); 64 | 65 | word = "<="; 66 | EXPECT_EQ(KEYWORD_LE, lexer.MatchNext(&word)); 67 | EXPECT_EQ(std::string(""), word); 68 | 69 | word = " lexer; 76 | lexer.AddKeyword("if", KEYWORD_IF); 77 | 78 | const char *word = " \n\rif nextthing"; 79 | EXPECT_EQ(KEYWORD_IF, lexer.MatchNext(&word)); 80 | EXPECT_EQ(std::string("nextthing"), word); 81 | } 82 | 83 | TEST(SimpleLexerTest, ReverseMapping) { 84 | SimpleLexer lexer; 85 | // Alternative keywords for the same enum value. The first is remembered 86 | // as canonical keyword for the ToString() method. 87 | lexer.AddKeyword("elseif", KEYWORD_ELSEIF); 88 | lexer.AddKeyword("elsif", KEYWORD_ELSEIF); 89 | lexer.AddKeyword("<", KEYWORD_LT); 90 | lexer.AddKeyword("LT", KEYWORD_LT); 91 | 92 | EXPECT_EQ(std::string("elseif"), lexer.AsString(KEYWORD_ELSEIF)); 93 | EXPECT_EQ(std::string("<"), lexer.AsString(KEYWORD_LT)); 94 | EXPECT_EQ(NULL, lexer.AsString(KEYWORD_IF)); 95 | 96 | EXPECT_EQ(std::string("?"), lexer.AsString(NO_KEYWORD)); 97 | } 98 | 99 | int main(int argc, char *argv[]) { 100 | ::testing::InitGoogleTest(&argc, argv); 101 | return RUN_ALL_TESTS(); 102 | } 103 | -------------------------------------------------------------------------------- /src/gcode-print-stats.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "common/logging.h" 30 | #include "config-parser.h" 31 | #include "determine-print-stats.h" 32 | #include "gcode-machine-control.h" 33 | 34 | int usage(const char *prog) { 35 | fprintf(stderr, 36 | "Usage: %s [options] [ ..]\n" 37 | "Options:\n" 38 | "\t-c : Machine config\n" 39 | "\t-f : Speedup-factor for feedrate.\n" 40 | "\t-H : Toggle print header line\n" 41 | "Use filename '-' for stdin.\n", 42 | prog); 43 | return 1; 44 | } 45 | 46 | static void print_file_stats(const char *filename, int indentation, 47 | FILE *msg_out, 48 | const MachineControlConfig &config) { 49 | struct BeagleGPrintStats result; 50 | int fd = strcmp(filename, "-") == 0 ? STDIN_FILENO : open(filename, O_RDONLY); 51 | if (determine_print_stats(fd, config, msg_out, &result)) { 52 | // Filament length looks a bit high, is this input or extruded ? 53 | printf("%-*s %10.0f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f %7.1f", 54 | indentation, filename, result.total_time_seconds, result.x_min, 55 | result.x_max, result.y_min, result.y_max, result.z_min, result.z_max, 56 | result.last_z_extruding, result.filament_len); 57 | printf("\n"); 58 | } else { 59 | printf("#%s not-processed\n", filename); 60 | } 61 | } 62 | 63 | int main(int argc, char *argv[]) { 64 | struct MachineControlConfig config; 65 | 66 | float factor = 1.0; // print speed factor. 67 | char print_header = 1; 68 | const char *config_file = NULL; 69 | const char *msg_out_file = "/dev/null"; 70 | 71 | int opt; 72 | while ((opt = getopt(argc, argv, "c:f:Hv")) != -1) { 73 | switch (opt) { 74 | case 'c': config_file = strdup(optarg); break; 75 | case 'f': 76 | factor = (float)atof(optarg); 77 | if (factor <= 0) return usage(argv[0]); 78 | break; 79 | case 'H': print_header = !print_header; break; 80 | case 'v': msg_out_file = "/dev/stderr"; break; 81 | default: return usage(argv[0]); 82 | } 83 | } 84 | 85 | if (optind >= argc) return usage(argv[0]); 86 | 87 | if (!config_file) { 88 | fprintf(stderr, "Expected config file -c \n"); 89 | return 1; 90 | } 91 | 92 | FILE *msg_out = fopen(msg_out_file, "w"); 93 | Log_init("/dev/null"); 94 | 95 | ConfigParser config_parser; 96 | if (!config_parser.SetContentFromFile(config_file)) { 97 | fprintf(stderr, "Cannot read config file '%s'\n", config_file); 98 | return 1; 99 | } 100 | if (!config.ConfigureFromFile(config_parser)) { 101 | fprintf(stderr, "Exiting. Parse error in configuration file '%s'\n", 102 | config_file); 103 | return 1; 104 | } 105 | 106 | config.speed_factor = factor; 107 | config.range_check = false; // don't care about clipping. 108 | 109 | // This is not connected to any machine. Don't assume homing. 110 | config.require_homing = false; 111 | for (int i = 0; i < GCODE_NUM_AXES; ++i) { 112 | config.homing_trigger[i] = HardwareMapping::TRIGGER_NONE; 113 | } 114 | 115 | int longest_filename = strlen("#[filename]"); // table header 116 | for (int i = optind; i < argc; ++i) { 117 | int len = strlen(argv[i]); 118 | if (len > longest_filename) longest_filename = len; 119 | } 120 | if (print_header) { 121 | printf("%-*s %10s %7s %7s %7s %7s %7s %7s %7s %7s\n", longest_filename, 122 | "#[filename]", "time", "min_x", "max_x", "min_y", "max_y", "min_z", 123 | "max_z", "z-last", "filament-mm"); 124 | } 125 | for (int i = optind; i < argc; ++i) { 126 | print_file_stats(argv[i], longest_filename, msg_out, config); 127 | } 128 | fclose(msg_out); 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /src/generic-gpio.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef __GENERIC_GPIO_H 21 | #define __GENERIC_GPIO_H 22 | 23 | #include 24 | 25 | #include "motor-interface-constants.h" 26 | 27 | int get_gpio(uint32_t gpio_def); 28 | 29 | void set_gpio(uint32_t gpio_def); 30 | void clr_gpio(uint32_t gpio_def); 31 | 32 | bool map_gpio(); 33 | void unmap_gpio(); 34 | 35 | #endif // __GENERIC_GPIO_H 36 | -------------------------------------------------------------------------------- /src/hershey.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2018 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_HERSHEY_H_ 20 | #define _BEAGLEG_HERSHEY_H_ 21 | 22 | #include 23 | 24 | #include "common/string-util.h" 25 | 26 | // -- Functions to draw ASCII text in the Hershey simplex font. 27 | 28 | // Determine the width of the text if drawn with DrawText() 29 | float TextWidth(std::string_view str, float size); 30 | 31 | enum class TextAlign { kLeft, kCenter, kRight }; 32 | 33 | // Draw a text at position (x,y) with the given alignment and size, 34 | // output is sent to the 2D output 'device' function that receives. 35 | // "do_line" - a boolean saying if we should line or move to the position. 36 | // "x", "y" - the position to moveto/lineto 37 | // The function makes it independent of any output device and easy to 38 | // adapt in any environment. 39 | void DrawText(std::string_view str, float tx, float ty, TextAlign align, 40 | float size, 41 | const std::function& draw); 42 | 43 | #endif // _BEAGLEG_HERSHEY_H_ 44 | -------------------------------------------------------------------------------- /src/idiv.hp: -------------------------------------------------------------------------------- 1 | ;;; -*- asm -*- 2 | ;;; Integer division operation (idiv) for the am335x Beaglebone Black PRU. 3 | ;;; Standard shift-and-substract algorithm. 4 | ;;; 5 | ;;; (c) 2014 Henner Zeller 6 | ;;; 7 | ;;; This file is part of BeagleG. http://github.com/hzeller/beagleg 8 | ;;; 9 | ;;; Note: while the rest of BeagleG is GPL v3.0, this file idiv.hp is granted 10 | ;;; the more permissible MIT license. Just keep the copyright header and you're 11 | ;;; good to include it anywhere. 12 | ;;; 13 | ;;; Permission is hereby granted, free of charge, to any person obtaining a copy 14 | ;;; of this software and associated documentation files (the "Software"), to deal 15 | ;;; in the Software without restriction, including without limitation the rights 16 | ;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | ;;; copies of the Software, and to permit persons to whom the Software is 18 | ;;; furnished to do so, subject to the following conditions: 19 | ;;; 20 | ;;; The above copyright notice and this permission notice shall be included in 21 | ;;; all copies or substantial portions of the Software. 22 | ;;; 23 | ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | ;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | ;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | ;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | ;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | ;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | ;;; THE SOFTWARE. 30 | 31 | 32 | ;;; Typical cycle count of division operation. 33 | #define IDIV_MACRO_CYCLE_COUNT 129 34 | 35 | ;;; Input: 32 bit divident, 32 bit divisor, 32 bit space to hold remainder 36 | ;;; Output: 37 | ;;; remainder := divident_becomes_quotient % divisor 38 | ;;; divident_becomes_quotient := divident_becomes_quotient / divisor 39 | ;;; divisor: untouched 40 | ;;; 41 | ;;; Uses: 3 registers; 97 .. 161 cycles (avg 129) 42 | .macro idiv_macro 43 | .mparam divident_becomes_quotient, divisor, remainder 44 | ;; divident is the lo-word and will become the quotient 45 | ;; remainder is the hi-word; is 0 initially. 46 | 47 | zero &remainder, 4 ; 1 cycle 48 | ;; Unrolled loop of 32 division steps. 32 * 3 .. 5 cycles 49 | _idiv_division_step remainder, divident_becomes_quotient, divisor 50 | _idiv_division_step remainder, divident_becomes_quotient, divisor 51 | _idiv_division_step remainder, divident_becomes_quotient, divisor 52 | _idiv_division_step remainder, divident_becomes_quotient, divisor 53 | _idiv_division_step remainder, divident_becomes_quotient, divisor 54 | _idiv_division_step remainder, divident_becomes_quotient, divisor 55 | _idiv_division_step remainder, divident_becomes_quotient, divisor 56 | _idiv_division_step remainder, divident_becomes_quotient, divisor 57 | 58 | _idiv_division_step remainder, divident_becomes_quotient, divisor 59 | _idiv_division_step remainder, divident_becomes_quotient, divisor 60 | _idiv_division_step remainder, divident_becomes_quotient, divisor 61 | _idiv_division_step remainder, divident_becomes_quotient, divisor 62 | _idiv_division_step remainder, divident_becomes_quotient, divisor 63 | _idiv_division_step remainder, divident_becomes_quotient, divisor 64 | _idiv_division_step remainder, divident_becomes_quotient, divisor 65 | _idiv_division_step remainder, divident_becomes_quotient, divisor 66 | 67 | _idiv_division_step remainder, divident_becomes_quotient, divisor 68 | _idiv_division_step remainder, divident_becomes_quotient, divisor 69 | _idiv_division_step remainder, divident_becomes_quotient, divisor 70 | _idiv_division_step remainder, divident_becomes_quotient, divisor 71 | _idiv_division_step remainder, divident_becomes_quotient, divisor 72 | _idiv_division_step remainder, divident_becomes_quotient, divisor 73 | _idiv_division_step remainder, divident_becomes_quotient, divisor 74 | _idiv_division_step remainder, divident_becomes_quotient, divisor 75 | 76 | _idiv_division_step remainder, divident_becomes_quotient, divisor 77 | _idiv_division_step remainder, divident_becomes_quotient, divisor 78 | _idiv_division_step remainder, divident_becomes_quotient, divisor 79 | _idiv_division_step remainder, divident_becomes_quotient, divisor 80 | _idiv_division_step remainder, divident_becomes_quotient, divisor 81 | _idiv_division_step remainder, divident_becomes_quotient, divisor 82 | _idiv_division_step remainder, divident_becomes_quotient, divisor 83 | _idiv_division_step remainder, divident_becomes_quotient, divisor 84 | .endm 85 | 86 | ;;; Internal division step for idiv_macro; uses between 3 and 5 cycles 87 | ;;; (hi || lo) - internal state; initially lo is divident 88 | ;;; then gradually becomes quotient, hi the remainder. 89 | ;;; d - divisor 90 | .macro _idiv_division_step 91 | .mparam hi, lo, d 92 | add lo, lo, lo ; c || lo := lo << 1 ; c : carry 93 | adc hi, hi, hi ; c || hi := (hi || c) << 1 94 | ;; If we'd support 64/32bit: now [add lo, lo, 0] [qbbs DO_SUB, lo, 0] 95 | qblt SKIP_SUB, d, hi ; if (hi >= d) (i.e. skip if hi < d) 96 | set lo, 0 ; set the low bit 97 | DO_SUB: sub hi, hi, d ; and substract divisor 98 | SKIP_SUB: 99 | .endm 100 | -------------------------------------------------------------------------------- /src/machine-control-config_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | #include "config-parser.h" 25 | #include "gcode-machine-control.h" // contains struct MachineControlConfig 26 | 27 | // TODO(hzeller): add tests for error conditions. 28 | 29 | TEST(MachineControlConfig, GeneralMapping) { 30 | ConfigParser p; 31 | p.SetContent( 32 | "[ general ]\n" 33 | "home-order = ABC\n" 34 | "require-homing = 0\n" // three ways .. 35 | "range-check = no\n" // .. to say ... 36 | "synchronous = false\n" // 'NO'. 37 | "auto-motor-disable-seconds = 188 \n"); 38 | MachineControlConfig config; 39 | EXPECT_TRUE(config.ConfigureFromFile(p)); 40 | 41 | EXPECT_EQ("ABC", config.home_order); 42 | EXPECT_FALSE(config.require_homing); 43 | EXPECT_FALSE(config.range_check); 44 | EXPECT_FALSE(config.synchronous); 45 | EXPECT_EQ(188, config.auto_motor_disable_seconds); 46 | } 47 | 48 | TEST(MachineControlConfig, AxisMapping) { 49 | ConfigParser p; 50 | p.SetContent( 51 | "[ X-Axis ]\n" 52 | "steps-per-mm = 200 / (2 * 60)\n" // simple expression support. 53 | "max-feedrate = 42\n" 54 | "max-acceleration = 4242\n" 55 | "range = 987\n" 56 | "home-pos = max\n" 57 | 58 | "[ Y-Axis ]\n" 59 | "home-pos = min\n" // Different home pos. 60 | ); 61 | 62 | MachineControlConfig config; 63 | EXPECT_TRUE(config.ConfigureFromFile(p)); 64 | 65 | EXPECT_FLOAT_EQ(200.0f / (2 * 60.0f), config.steps_per_mm[AXIS_X]); 66 | EXPECT_FLOAT_EQ(42.0f, config.max_feedrate[AXIS_X]); 67 | EXPECT_FLOAT_EQ(4242.0f, config.acceleration[AXIS_X]); 68 | EXPECT_FLOAT_EQ(987.0f, config.move_range_mm[AXIS_X]); 69 | EXPECT_EQ(HardwareMapping::TRIGGER_MAX, config.homing_trigger[AXIS_X]); 70 | EXPECT_EQ(HardwareMapping::TRIGGER_MIN, config.homing_trigger[AXIS_Y]); 71 | } 72 | 73 | #if 0 74 | // TODO: needs to move to hardware mapping test 75 | TEST(MachineControlConfig, MotorMapping) { 76 | ConfigParser p; 77 | p.SetContent("[ motor-mapping ]\n" 78 | "motor_1 = axis:x\n" 79 | "motor_2 = axis:-y\n" // Invert axis with minus characters. 80 | // No mapping for motor 3 81 | "motor_4 = axis:z"); 82 | MachineControlConfig config; 83 | EXPECT_TRUE(config.ConfigureFromFile(&p)); 84 | 85 | EXPECT_EQ("Xy_Z", config.axis_mapping); 86 | } 87 | #endif 88 | 89 | #if 0 90 | // TODO: needs to move to hardware mapping test 91 | TEST(MachineControlConfig, SwitchMapping) { 92 | ConfigParser p; 93 | p.SetContent("[ switch-mapping ]\n" 94 | "switch_3 = active:high \t min_x\n" // multiple space 95 | "switch_4 = active:low min_y max_y\n" // switch connected in series. 96 | ); 97 | MachineControlConfig config; 98 | EXPECT_TRUE(config.ConfigureFromFile(&p)); 99 | 100 | EXPECT_EQ(3, config.min_endstop_[AXIS_X].endstop_switch); 101 | EXPECT_TRUE(config.trigger_level_[3 - 1]); 102 | 103 | EXPECT_EQ(4, config.min_endstop_[AXIS_Y].endstop_switch); 104 | EXPECT_EQ(4, config.max_endstop_[AXIS_Y].endstop_switch); 105 | EXPECT_FALSE(config.trigger_level_[4 - 1]); 106 | } 107 | #endif 108 | 109 | int main(int argc, char *argv[]) { 110 | ::testing::InitGoogleTest(&argc, argv); 111 | return RUN_ALL_TESTS(); 112 | } 113 | -------------------------------------------------------------------------------- /src/motion-queue-motor-operations.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013-2020 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef MOTION_QUEUE_MOTOR_OPERATIONS_H 20 | #define MOTION_QUEUE_MOTOR_OPERATIONS_H 21 | 22 | #include 23 | 24 | #include "hardware-mapping.h" 25 | #include "motion-queue.h" 26 | #include "segment-queue.h" 27 | 28 | class MotionQueueMotorOperations : public SegmentQueue { 29 | public: 30 | // Initialize motor operations, sending planned results into the motion 31 | // backend. 32 | MotionQueueMotorOperations(HardwareMapping *hw, MotionQueue *backend); 33 | ~MotionQueueMotorOperations() override; 34 | 35 | bool Enqueue(const LinearSegmentSteps &segment) final; 36 | void MotorEnable(bool on) final; 37 | void WaitQueueEmpty() final; 38 | bool GetPhysicalStatus(PhysicalStatus *status) final; 39 | void SetExternalPosition(int axis, int position_steps) final; 40 | 41 | private: 42 | bool EnqueueInternal(const LinearSegmentSteps ¶m, 43 | int defining_axis_steps); 44 | 45 | HardwareMapping *const hardware_mapping_; 46 | MotionQueue *backend_; 47 | 48 | struct HistorySegment; 49 | std::deque *shadow_queue_; 50 | }; 51 | 52 | #endif // MOTION_QUEUE_MOTOR_OPERATIONS_H 53 | -------------------------------------------------------------------------------- /src/planner.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2016 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_PLANNER_H_ 20 | #define _BEAGLEG_PLANNER_H_ 21 | 22 | #include "gcode-parser/gcode-parser.h" // AxesRegister 23 | 24 | struct MachineControlConfig; 25 | class HardwareMapping; 26 | class SegmentQueue; 27 | 28 | // The planner receives a sequence of desired target positions. 29 | // It then plans acceleration and speed profile for the physical 30 | // machine, and emits these to the SegmentQueue backend. 31 | class Planner { 32 | public: 33 | // The planner writes out motor operations to the backend. 34 | Planner(const MachineControlConfig *config, HardwareMapping *hardware_mapping, 35 | SegmentQueue *motor_backend); 36 | ~Planner(); 37 | 38 | // Enqueue a new target position to go to in a linear movement from 39 | // the current position. 40 | // Returns true if successful, false if aborted 41 | bool Enqueue(const AxesRegister &target_pos, float speed); 42 | 43 | // Flush the queue and wait until all remaining motor 44 | // operations have been flushed. 45 | void BringPathToHalt(); 46 | 47 | // Get the latest position enqueued to the motors. 48 | // TODO(Leonardo): get actual position of the motor at this moment. 49 | void GetCurrentPosition(AxesRegister *pos); 50 | 51 | // Drive an axis directly. Should only be used for cases such as 52 | // homing which require direct motor driving. 53 | // 54 | // Precondition: path needs to be halted, so call BringPathToHalt() first. 55 | // After one or a series of DirectDrive() calls, SetExternalPosition() 56 | // must be called to inform the Planner what new absolute position we 57 | // are in. 58 | // 59 | // Returns the number of steps the stepmotor for that axis did. 60 | int DirectDrive(GCodeParserAxis axis, float distance, float v0, float v1); 61 | 62 | // Set the current absolute position of the given axis from an 63 | // machine move outside of the control of the Planner. 64 | // Precondition: BringPathToHalt() had been called before. 65 | void SetExternalPosition(GCodeParserAxis axis, float pos); 66 | 67 | // Set the internal planner queue size. 68 | // Used to trade-off between command sent - executed motion latency 69 | // and maximum achievable speed. 70 | // Requires 0 < size <= GetMaxLookahead(), returns true on success. 71 | bool SetLookahead(int size); 72 | 73 | // Retrieve the internal planning queue size. 74 | int Lookahead() const; 75 | 76 | // Get the maximum allowed lookahead size. 77 | int GetMaxLookahead() const; 78 | 79 | private: 80 | class Impl; 81 | Impl *const impl_; 82 | }; 83 | #endif 84 | -------------------------------------------------------------------------------- /src/pru-generic-io-routines.hp: -------------------------------------------------------------------------------- 1 | ;; -*- asm -*- 2 | ;; 3 | ;; (c) 2013, 2014, 2015 Henner Zeller 4 | ;; H Hartley Sweeten 5 | ;; 6 | ;; This file is part of BeagleG. http://github.com/hzeller/beagleg 7 | ;; 8 | ;; BeagleG is free software: you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | ;; 13 | ;; BeagleG is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | ;; 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with BeagleG. If not, see . 20 | 21 | ;;;; 22 | ;;; Each hardware/ subdirectory needs to include a pru-io-routines.hp 23 | ;;; file that contains the functions defined in this file. The simplest 24 | ;;; way is to just include this generic file (albeit a bit slower). 25 | ;;; (TODO: auto generate optimized assembler with a little program). 26 | ;;;; 27 | 28 | ;;; Set/Clr a GPIO pin based on 'bit' being set/clr in 'bits' 29 | ;;; Uses: 30 | ;;; r4 : the base address of the gpio bank to set/clr the pin 31 | ;;; r5 : the bitmask to set/clr the gpio pin 32 | ;;; r6 : scratch 33 | .macro SetGPIO 34 | .mparam bits, bit, gpio_def 35 | MOV r4, (gpio_def & 0xfffff000) 36 | QBEQ no_map, r4.w2, GPIO_NOT_MAPPED 37 | MOV r5, 1 << (gpio_def & 0x1f) 38 | QBBS set_gpio, bits, bit 39 | MOV r6, GPIO_CLEARDATAOUT 40 | QBA update_gpio 41 | set_gpio: 42 | MOV r6, GPIO_SETDATAOUT 43 | update_gpio: 44 | ADD r4, r4, r6 45 | SBBO r5, r4, 0, 4 46 | no_map: 47 | .endm 48 | 49 | ;;; Set the aux bit signals based on the travel_params.aux (r3) bit 0..15 50 | SetAuxBits: 51 | SetGPIO r3, 0, AUX_1_GPIO 52 | SetGPIO r3, 1, AUX_2_GPIO 53 | SetGPIO r3, 2, AUX_3_GPIO 54 | SetGPIO r3, 3, AUX_4_GPIO 55 | SetGPIO r3, 4, AUX_5_GPIO 56 | SetGPIO r3, 5, AUX_6_GPIO 57 | SetGPIO r3, 6, AUX_7_GPIO 58 | SetGPIO r3, 7, AUX_8_GPIO 59 | SetGPIO r3, 8, AUX_9_GPIO 60 | SetGPIO r3, 9, AUX_10_GPIO 61 | SetGPIO r3, 10, AUX_11_GPIO 62 | SetGPIO r3, 11, AUX_12_GPIO 63 | SetGPIO r3, 12, AUX_13_GPIO 64 | SetGPIO r3, 13, AUX_14_GPIO 65 | SetGPIO r3, 14, AUX_15_GPIO 66 | SetGPIO r3, 15, AUX_16_GPIO 67 | RET 68 | 69 | ;;; Set the motor direction signals based from queue_header.direction_bits (r3) 70 | ;;; bit 0..7 71 | SetDirections: 72 | SetGPIO r3, 0, MOTOR_1_DIR_GPIO 73 | SetGPIO r3, 1, MOTOR_2_DIR_GPIO 74 | SetGPIO r3, 2, MOTOR_3_DIR_GPIO 75 | SetGPIO r3, 3, MOTOR_4_DIR_GPIO 76 | SetGPIO r3, 4, MOTOR_5_DIR_GPIO 77 | SetGPIO r3, 5, MOTOR_6_DIR_GPIO 78 | SetGPIO r3, 6, MOTOR_7_DIR_GPIO 79 | SetGPIO r3, 7, MOTOR_8_DIR_GPIO 80 | RET 81 | 82 | ;;; Set the motor step signals based on bit 31 of the mstate of the motor 83 | SetSteps: 84 | SetGPIO mstate.m1, 31, MOTOR_1_STEP_GPIO 85 | SetGPIO mstate.m2, 31, MOTOR_2_STEP_GPIO 86 | SetGPIO mstate.m3, 31, MOTOR_3_STEP_GPIO 87 | SetGPIO mstate.m4, 31, MOTOR_4_STEP_GPIO 88 | SetGPIO mstate.m5, 31, MOTOR_5_STEP_GPIO 89 | SetGPIO mstate.m6, 31, MOTOR_6_STEP_GPIO 90 | SetGPIO mstate.m7, 31, MOTOR_7_STEP_GPIO 91 | SetGPIO mstate.m8, 31, MOTOR_8_STEP_GPIO 92 | RET 93 | -------------------------------------------------------------------------------- /src/pru-hardware-interface.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller , 3 | * Leonardo Romor , 4 | * 5 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 6 | * 7 | * BeagleG is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BeagleG is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BeagleG. If not, see . 19 | */ 20 | #ifndef BEAGLEG_PRU_HARDWARE_INTERFACE_ 21 | #define BEAGLEG_PRU_HARDWARE_INTERFACE_ 22 | 23 | #include 24 | 25 | // Pru hardware controls 26 | class PruHardwareInterface { 27 | public: 28 | virtual ~PruHardwareInterface() {} 29 | 30 | // Initialize the hardware, interrupts, etc... 31 | // return value: returns if the operation was successful. 32 | virtual bool Init() = 0; 33 | 34 | // Retrieve the pointer of the pru mapping and initialize the memory. 35 | virtual bool AllocateSharedMem(void **pru_mmap, size_t size) = 0; 36 | 37 | // Enable the PRU and start predetermined program. 38 | virtual bool StartExecution() = 0; 39 | 40 | // Wait for a beagleg-mapped event. Return number of events that have occured. 41 | virtual unsigned WaitEvent() = 0; 42 | 43 | // Halt the PRU 44 | virtual bool Shutdown() = 0; 45 | }; 46 | 47 | class UioPrussInterface : public PruHardwareInterface { 48 | public: 49 | bool Init() final; 50 | bool AllocateSharedMem(void **pru_mmap, size_t size) final; 51 | bool StartExecution() final; 52 | unsigned WaitEvent() final; 53 | bool Shutdown() final; 54 | }; 55 | 56 | #endif // BEAGLEG_PRU_HARDWARE_INTERFACE_ 57 | -------------------------------------------------------------------------------- /src/pwm-timer.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 H Hartley Sweeten 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef __PWM_TIMER_H 21 | #define __PWM_TIMER_H 22 | 23 | #include 24 | 25 | #include "motor-interface-constants.h" 26 | 27 | // Start/stop the PWM timer 28 | void pwm_timer_start(uint32_t gpio_def, bool start); 29 | 30 | // Set the PWM timer duty cycle 31 | void pwm_timer_set_duty(uint32_t gpio_def, float duty_cycle); 32 | void pwm_timer_set_freq(uint32_t gpio_def, int pwm_freq); 33 | 34 | bool pwm_timers_map(); 35 | void pwm_timers_unmap(); 36 | 37 | #endif // __PWM_TIMER_H 38 | -------------------------------------------------------------------------------- /src/pwm-timer_test.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2015 H Hartley Sweeten 3 | * Test for PWM timers 4 | */ 5 | 6 | #include "pwm-timer.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int usage(const char *progname) { 14 | fprintf(stderr, "Usage: %s [] []\n", progname); 15 | fprintf(stderr, 16 | "Options:\n" 17 | " : timer number to test (4, 5, 6, or 7) (Required)\n" 18 | " : base frequency for the PWM (in hz) (Required)\n" 19 | " : duty cycle for the PWM (0 to 1) (Optional, " 20 | "Default: 0.5 (50%%)\n" 21 | " : seconds to delay before stopping PWM (Optional, " 22 | "Default: 5 seconds\n"); 23 | fprintf(stderr, "Parameters must be in the order shown above.\n"); 24 | fprintf(stderr, "A of 0 will cause the PWM to cycle from .1 to 1.0 \n"); 25 | return 1; 26 | } 27 | 28 | int main(int argc, char *argv[]) { 29 | if (argc < 3) { 30 | return usage(argv[0]); 31 | } 32 | 33 | uint32_t gpio_def; 34 | switch (atoi(argv[1])) { 35 | case 4: gpio_def = PIN_P8_7; break; 36 | case 5: gpio_def = PIN_P8_9; break; 37 | case 6: gpio_def = PIN_P8_10; break; 38 | case 7: gpio_def = PIN_P8_8; break; 39 | default: return usage(argv[0]); 40 | } 41 | int freq = atoi(argv[2]); 42 | float dc = 0.5; 43 | if (argc > 3) dc = atof(argv[3]); 44 | int delay = 5; 45 | if (argc > 4) delay = atoi(argv[4]); 46 | 47 | if (!pwm_timers_map()) return 1; 48 | 49 | pwm_timer_set_freq(gpio_def, freq); 50 | if (dc == 0) { 51 | pwm_timer_set_duty(gpio_def, 0.1); 52 | pwm_timer_start(gpio_def, 1); 53 | sleep(1); 54 | pwm_timer_set_duty(gpio_def, 0.2); 55 | sleep(1); 56 | pwm_timer_set_duty(gpio_def, 0.3); 57 | sleep(1); 58 | pwm_timer_set_duty(gpio_def, 0.4); 59 | sleep(1); 60 | pwm_timer_set_duty(gpio_def, 0.5); 61 | sleep(1); 62 | pwm_timer_set_duty(gpio_def, 0.6); 63 | sleep(1); 64 | pwm_timer_set_duty(gpio_def, 0.7); 65 | sleep(1); 66 | pwm_timer_set_duty(gpio_def, 0.8); 67 | sleep(1); 68 | pwm_timer_set_duty(gpio_def, 0.9); 69 | sleep(1); 70 | pwm_timer_set_duty(gpio_def, 1.0); 71 | sleep(1); 72 | } else { 73 | pwm_timer_set_duty(gpio_def, dc); 74 | pwm_timer_start(gpio_def, 1); 75 | sleep(delay); 76 | } 77 | pwm_timer_start(gpio_def, 0); 78 | 79 | pwm_timers_unmap(); 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/segment-queue.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | #ifndef _BEAGLEG_MOTOR_OPERATIONS_H_ 20 | #define _BEAGLEG_MOTOR_OPERATIONS_H_ 21 | 22 | #include 23 | 24 | enum { BEAGLEG_NUM_MOTORS = 8 }; 25 | 26 | // The movement command send to the segment queue either changes speed, or 27 | // provides a steady speed. Already low-level broken down for motors. 28 | struct LinearSegmentSteps { 29 | // Speed is steps/s. If initial speed and final speed differ, the motor will 30 | // accelerate or decelerate to reach the final speed within the given number 31 | // of alotted steps of the axis with the most number of steps; all other axes 32 | // are scaled accordingly. Uses jerk-settings to increase/decrease 33 | // acceleration; the acceleration is zero at the end of the move. 34 | float v0; // initial speed 35 | float v1; // final speed 36 | 37 | // Bits that are set in parallel with the motor control that should be 38 | // set at the beginning of the motor movement. 39 | uint16_t aux_bits; // Aux-bits to switch. 40 | 41 | int steps[BEAGLEG_NUM_MOTORS]; // Steps for axis. Negative for reverse. 42 | }; 43 | 44 | // Struct used to return data about the currently executed steps 45 | // and the status of the auxes. 46 | struct PhysicalStatus { 47 | int pos_steps[BEAGLEG_NUM_MOTORS]; // Absolute position in steps. 48 | uint16_t aux_bits; // Auxes status 49 | }; 50 | 51 | class SegmentQueue { 52 | public: 53 | virtual ~SegmentQueue() {} 54 | 55 | // Enqueue a coordinated move command. 56 | // If there is space in the ringbuffer, this function returns immediately, 57 | // otherwise it waits until a slot frees up or an abort happens. 58 | // If "err_stream" is non-NULL, prints error message there. 59 | // Automatically enables motors if not already. 60 | // Returns true if the move was added, false if aborted 61 | virtual bool Enqueue(const LinearSegmentSteps &segment) = 0; 62 | 63 | // Waits for the queue to be empty and Enables/disables motors according to 64 | // the given boolean value (Right now, motors cannot be individually 65 | // addressed). 66 | virtual void MotorEnable(bool on) = 0; 67 | 68 | // Wait, until all elements in the ring-buffer are consumed. 69 | virtual void WaitQueueEmpty() = 0; 70 | 71 | // Get the absolute position and auxes status the motors currently 72 | // in, and the end of the exeuction queue. 73 | // Returns 'true' if the status was available and is updated. 74 | virtual bool GetPhysicalStatus(PhysicalStatus *status) = 0; 75 | 76 | // Set absolute position of given axis as provided from some external 77 | // source (e.g. homing). This will allow accurate reporting of the 78 | // PhysicalStatus. 79 | virtual void SetExternalPosition(int axis, int position_steps) = 0; 80 | }; 81 | 82 | #endif // _BEAGLEG_MOTOR_OPERATIONS_H_ 83 | -------------------------------------------------------------------------------- /src/sim-audio-out.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include "sim-audio-out.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "motion-queue.h" 28 | #include "motor-interface-constants.h" 29 | 30 | #define LOOPS_PER_STEP (1 << 1) 31 | 32 | static constexpr unsigned char kWavHeader[] = { 33 | 0x52, 0x49, 0x46, 0x46, 0xff, 0xff, 0xff, 0xff, 0x57, 0x41, 0x56, 34 | 0x45, 0x66, 0x6D, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 35 | 0x02, 0x00, 0x44, 0xAC, 0x00, 0x00, 0x10, 0xB1, 0x02, 0x00, 0x04, 36 | 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0xff, 0xff, 0xff, 0xff, 37 | }; 38 | 39 | class SimFirmwareAudioQueue::AudioWriter { 40 | public: 41 | explicit AudioWriter(FILE *out) : out_(out) { 42 | fwrite(kWavHeader, sizeof(kWavHeader), 1, out_); 43 | } 44 | 45 | ~AudioWriter() { 46 | fflush(out_); 47 | fseek(out_, 40, SEEK_SET); 48 | uint32_t data_size = 4 * current_sample_; 49 | fwrite(&data_size, sizeof(data_size), 1, out_); 50 | 51 | data_size += 36; 52 | fseek(out_, 4, SEEK_SET); 53 | fwrite(&data_size, sizeof(data_size), 1, out_); 54 | 55 | fclose(out_); 56 | fprintf(stderr, "WAV: wrote %u samples (%.2fs)\n", current_sample_, 57 | current_sample_ / 44100.0); 58 | } 59 | 60 | void Update(uint8_t channel_values, double until_time) { 61 | struct sample_t { 62 | int16_t left; 63 | int16_t right; 64 | } sample = {(int16_t)((channel_values & 0b01) ? 16000 : -16000), 65 | (int16_t)((channel_values & 0b10) ? 16000 : -16000)}; 66 | const uint32_t target_sample = until_time * kSampleRate; 67 | for (/**/; current_sample_ < target_sample; ++current_sample_) { 68 | fwrite(&sample, sizeof(sample), 1, out_); 69 | } 70 | } 71 | 72 | private: 73 | static constexpr int kSampleRate = 44100; 74 | uint32_t current_sample_ = 0; 75 | FILE *const out_; 76 | }; 77 | 78 | struct HardwareState { 79 | // Internal state 80 | uint32_t m[MOTION_MOTOR_COUNT]; 81 | }; 82 | 83 | static double sim_time = 0; 84 | static struct HardwareState state; 85 | 86 | // Default mapping of our motors to axis in typical test-setups. 87 | // Should match Motor-Mapping in config file. 88 | enum { X_MOTOR = 0, Y_MOTOR = 1, Z_MOTOR = 2 }; 89 | 90 | // This simulates what happens in the PRU. For testing purposes. 91 | bool SimFirmwareAudioQueue::Enqueue(MotionSegment *segment) { 92 | if (segment->state == STATE_EXIT) return true; 93 | 94 | // For each segment, we start with a fresh motor state. 95 | memset(&state, 0x00, sizeof(state)); 96 | 97 | uint32_t remainder = 0; 98 | 99 | for (;;) { 100 | uint8_t channel_value = 0x00; 101 | // Increment by motor fraction. 102 | for (int i = 0; i < MOTION_MOTOR_COUNT; ++i) { 103 | state.m[i] += segment->fractions[i]; 104 | channel_value |= ((state.m[i] & 0x80000000) != 0) << i; 105 | } 106 | 107 | sim_time += 160e-9; // Updating the motor takes this time. 108 | 109 | uint32_t delay_loops = 0; 110 | 111 | if (segment->loops_accel > 0) { 112 | if (segment->accel_series_index != 0) { 113 | const uint32_t divident = 114 | (segment->hires_accel_cycles << 1) + remainder; 115 | const uint32_t divisor = (segment->accel_series_index << 2) + 1; 116 | segment->hires_accel_cycles -= (divident / divisor); 117 | remainder = divident % divisor; 118 | } 119 | ++segment->accel_series_index; 120 | --segment->loops_accel; 121 | delay_loops = segment->hires_accel_cycles >> DELAY_CYCLE_SHIFT; 122 | } else if (segment->loops_travel > 0) { 123 | delay_loops = segment->travel_delay_cycles; 124 | --segment->loops_travel; 125 | } else if (segment->loops_decel > 0) { 126 | const uint32_t divident = (segment->hires_accel_cycles << 1) + remainder; 127 | const uint32_t divisor = (segment->accel_series_index << 2) - 1; 128 | segment->hires_accel_cycles += (divident / divisor); 129 | remainder = divident % divisor; 130 | --segment->accel_series_index; 131 | --segment->loops_decel; 132 | delay_loops = segment->hires_accel_cycles >> DELAY_CYCLE_SHIFT; 133 | } else { 134 | break; // done. 135 | } 136 | 137 | const double wait_time = 1.0 * delay_loops / TIMER_FREQUENCY; 138 | sim_time += wait_time; 139 | writer_->Update(channel_value, sim_time); 140 | } 141 | return true; 142 | } 143 | 144 | SimFirmwareAudioQueue::SimFirmwareAudioQueue(FILE *out) 145 | : writer_(new AudioWriter(out)) {} 146 | 147 | SimFirmwareAudioQueue::~SimFirmwareAudioQueue() { delete writer_; } 148 | -------------------------------------------------------------------------------- /src/sim-audio-out.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "motion-queue.h" 23 | 24 | // Output to wav file. Only motor 0/1 (X/Y) on left/right channel. Helps to 25 | // to make smooth acceleration curves audible. 26 | class SimFirmwareAudioQueue : public MotionQueue { 27 | public: 28 | explicit SimFirmwareAudioQueue(FILE *out); 29 | ~SimFirmwareAudioQueue() override; 30 | 31 | bool Enqueue(MotionSegment *segment) final; 32 | void WaitQueueEmpty() final {} 33 | void MotorEnable(bool on) final {} 34 | void Shutdown(bool flush_queue) final {} 35 | int GetPendingElements(uint32_t *head_item_progress) final { 36 | if (head_item_progress) *head_item_progress = 0; 37 | return 1; 38 | } 39 | 40 | private: 41 | class AudioWriter; 42 | AudioWriter *writer_; 43 | }; 44 | -------------------------------------------------------------------------------- /src/sim-firmware.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2013, 2014 Henner Zeller 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "motion-queue.h" 23 | 24 | class SimFirmwareQueue : public MotionQueue { 25 | public: 26 | explicit SimFirmwareQueue(FILE *out, 27 | int relevant_motors = MOTION_MOTOR_COUNT); 28 | ~SimFirmwareQueue() override; 29 | 30 | bool Enqueue(MotionSegment *segment) final; 31 | void WaitQueueEmpty() final {} 32 | void MotorEnable(bool on) final {} 33 | void Shutdown(bool flush_queue) final {} 34 | int GetPendingElements(uint32_t *head_item_progress) final { 35 | if (head_item_progress) *head_item_progress = 0; 36 | return 1; 37 | } 38 | 39 | private: 40 | class Averager; 41 | 42 | FILE *const out_; 43 | const int relevant_motors_; 44 | Averager *const averager_; 45 | }; 46 | -------------------------------------------------------------------------------- /src/spindle-control.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 H Hartley Sweeten 3 | * 4 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 5 | * 6 | * BeagleG is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * BeagleG is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with BeagleG. If not, see . 18 | */ 19 | 20 | #ifndef BEAGLEG_SPINDLE_CONTROL_ 21 | #define BEAGLEG_SPINDLE_CONTROL_ 22 | 23 | #include "common/string-util.h" 24 | 25 | class HardwareMapping; 26 | class ConfigParser; 27 | 28 | // Spindle configuration as read from config file. 29 | struct SpindleConfig { 30 | SpindleConfig(); 31 | bool ConfigureFromFile(const ConfigParser &parser); 32 | 33 | std::string type; 34 | std::string port; 35 | // TODO: other config options e.g. needed for modbus spindles. 36 | 37 | int max_rpm = 0; 38 | int max_accel = 0; 39 | int max_decel = 0; 40 | int pwr_delay_ms = 0; 41 | int on_delay_ms = 0; 42 | int off_delay_ms = 0; 43 | bool allow_ccw = false; 44 | }; 45 | 46 | class Spindle { 47 | public: 48 | // Factory for a spindle given the configuration. Returns an instance 49 | // of a spindle if it can be created given the available hardware-mapping. 50 | // Otherwise, returns nullptr and might info-log why it couldn't create a 51 | // spindle (which might be fine for many set-ups, e.g. 3D printers). 52 | static Spindle *CreateFromConfig(const SpindleConfig &config, 53 | HardwareMapping *hardware_mapping); 54 | 55 | virtual ~Spindle() {} 56 | 57 | // Turn spindle on clockwise (M3) or counterclockwise (M4) at speed (Sxx) 58 | virtual void On(bool ccw, int rpm) = 0; 59 | 60 | // Turn spindle off (M5) 61 | virtual void Off() = 0; 62 | }; 63 | 64 | #endif // BEAGLEG_SPINDLE_CONTROL_ 65 | -------------------------------------------------------------------------------- /src/test-create-html.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## 3 | 4 | if [ $# -lt 1 ] ; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | #OPTIONAL_VALGRIND="valgrind --error-exitcode=5" 10 | IMAGE_SIZE="24%" 11 | PARAMS="-q -w1200 -t16 -Viso -g10" 12 | 13 | # For now, let's use the configuration in which each axis has the same steps/mm. 14 | # The step-speed-different.config _should_ look the same in the output, but 15 | # currently the output is clearly broken, so let's not use it initially to 16 | # first fix what is broken alrady. 17 | # If config is commented out entirely, we only get the gcode output without 18 | # colored machine move. 19 | BEAGLEG_CONFIG="-c testdata/step-speed-same.config" 20 | #BEAGLEG_CONFIG="-c testdata/step-speed-different.config" 21 | 22 | GCODE2PS=$(dirname $0)/gcode2ps 23 | TEST_OUT_DIR=$(dirname $0)/test-out 24 | OUT_HTML=$TEST_OUT_DIR/test.html 25 | 26 | mkdir -p $TEST_OUT_DIR 27 | rm -f $OUT_HTML 28 | while [ $# -ne 0 ] ; do 29 | GCODE_FILE=$1 30 | BASENAME=$(basename $GCODE_FILE .gcode) 31 | $OPTIONAL_VALGRIND $GCODE2PS $PARAMS -o $TEST_OUT_DIR/${BASENAME}.ps $BEAGLEG_CONFIG -s -T2 $GCODE_FILE -C "${BASENAME}" 32 | EXIT_CODE=$? 33 | if [ $EXIT_CODE -eq 5 ] ; then 34 | ERRMSG=" Got valgrind errors " 35 | elif [ $EXIT_CODE -ne 0 ]; then 36 | ERRMSG=" Got execution errors; exit=$EXIT_CODE " 37 | else 38 | ERRMSG="" 39 | fi 40 | # create PNG 41 | gs -q -dGraphicsAlphaBits=4 -dTextAlphaBits=4 -dEPSCrop -dBATCH -dNOPAUSE -sDEVICE=png16m -sOutputFile=$TEST_OUT_DIR/${BASENAME}.png $TEST_OUT_DIR/${BASENAME}.ps 42 | 43 | cat <> $OUT_HTML 44 |
45 | ${BASENAME} 46 | 47 | $ERRMSG 48 |
49 | EOF 50 | shift # next file 51 | done 52 | 53 | echo 54 | echo "Output is in $(realpath $OUT_HTML)" 55 | -------------------------------------------------------------------------------- /src/testdata/README.md: -------------------------------------------------------------------------------- 1 | Small gcode files that will be converted to an HTML page 2 | with images with the `test-create-html.sh` script. 3 | 4 | The script can use the [step-speed-same.config](./step-speed-same.config) or 5 | the [step-speed-different.config)(./step-speed-different.config) configuration. 6 | That latter intentionally has vastly different step/mm settings for each 7 | axis to better illustrate if there are problems due to calculations taking 8 | these into account. 9 | 10 | To have things comparable easily, try to keep the output in a 100mm x 100mm 11 | rectangle and use a feedrate of 150mm/s (that way straight 12 | acceleration/deceleration in that space is clearly visible). 13 | -------------------------------------------------------------------------------- /src/testdata/angle.gcode: -------------------------------------------------------------------------------- 1 | G1 F[150 * 60] 2 | G1 X100 Y25 3 | G1 X120 Y25 4 | G1 X220 Y0 5 | -------------------------------------------------------------------------------- /src/testdata/circle.gcode: -------------------------------------------------------------------------------- 1 | G1 F[150 * 60] 2 | G03 X0 Y0 I40 J40 3 | -------------------------------------------------------------------------------- /src/testdata/coordinate-systems.gcode: -------------------------------------------------------------------------------- 1 | G10 L2 P1 X25 Y25 Z0 2 | G10 L2 P2 X75 Y25 Z20 3 | G10 L2 P3 X25 Y75 Z40 4 | G10 L2 P4 X74 Y75 Z60 5 | 6 | F150 7 | 8 | G54 9 | G0 X20 Y0 Z0 10 | G2 X20 Y0 I-20 J0 11 | 12 | G55 13 | G0 X20 Y0 Z0 14 | G2 X20 Y0 I-20 J0 15 | 16 | G56 17 | G0 X20 Y0 Z0 18 | G2 X20 Y0 I-20 J0 19 | 20 | G57 21 | G0 X20 Y0 Z0 22 | G2 X20 Y0 I-20 J0 23 | -------------------------------------------------------------------------------- /src/testdata/line-different-speeds.gcode: -------------------------------------------------------------------------------- 1 | G1 X87.3 F[70 * 60] 2 | G1 X193 F[90 * 60] 3 | G1 X210 F[20 * 60] 4 | G1 X256 F[56 * 60] 5 | G1 X310 F[180 * 60] 6 | G1 X400 F[70 * 60] 7 | G1 X420 F[111 * 60] 8 | -------------------------------------------------------------------------------- /src/testdata/polygon-24-vs-arc.gcode: -------------------------------------------------------------------------------- 1 | #faces=24 ; Polygon faces count 2 | #angle=[360/#faces] ; Angle. 3 | #aoff=[-#angle/2] ; rotation offset. Half a segment off so that we have vertical lines. 4 | 5 | #poly_r=50 ; polygon radius 6 | #cg2_r=45 ; circle radius G2 7 | #=40 ; circle radius G3. Example with parameter bracket syntax. 8 | 9 | G92 X[-#poly_r] Y[-#poly_r] ; Put center of circle to (0,0) coordinate. 10 | 11 | G1 F[150 * 60] 12 | #i=0 ; Loop counter 13 | WHILE [#i <= #faces] DO 14 | X[#poly_r * cos[#i * #angle + #aoff]] Y[#poly_r * sin[#i * #angle + #aoff]] 15 | #i++ 16 | END 17 | 18 | ; Now compare that to an inner 'regular' circle. 19 | G1 X#cg2_r Y0 20 | G2 X#cg2_r Y0 I[-#cg2_r] J0 21 | 22 | G1 X#cg3_r Y0 23 | G3 X#cg3_r Y0 I[-#cg3_r] J0 24 | -------------------------------------------------------------------------------- /src/testdata/rounded-bracket-parametrized.gcode: -------------------------------------------------------------------------------- 1 | ; cut a L shape with rounded corners 2 | #1=[150 * 60] (feedrate) 3 | #2=100 (side length) 4 | #3=20 (inner space) 5 | #4=5 (corner radius) 6 | 7 | g28 8 | g1 f#1 9 | g1 x[#2-#4] 10 | g3 x#2 y#4 j#4 11 | g1 y[#3-#4] 12 | g3 x[#2-#4] y#3 i [-abs[#4]] 13 | g1 x[#3+#4] 14 | g2 x#3 y[#3+#4] j#4 15 | g1 y[#2-#4] 16 | g3 x[#3-#4] y#2 i [-abs[#4]] 17 | g1 x#4 18 | g3 x0 y[#2-#4] j [-abs[#4]] 19 | g1 x0 y0 20 | 21 | ; slightly smaller L using radius arcs 22 | #5=4 (offset) 23 | #2=[#2-[#5*2]] 24 | #3=[#3-#5] 25 | #4=[#4-[#5/2]] 26 | g1 x#5 y#5 27 | g1 x[#5+#2-#4] 28 | g3 x[#5+#2] y[#5+#4] r#4 29 | g1 y[#3-#4] 30 | g3 x[#5+#2-#4] y[#3] r#4 31 | g1 x[#3+#4] 32 | g2 x#3 y[#3+#4] r#4 33 | ;g2 x#3 y[#3+#4] r [-abs[#4]] (negative radius takes a longer path) 34 | g1 y[#5+#2-#4] 35 | g3 x[#3-#4] y[#5+#2] r#4 36 | g1 x[#5+#4] 37 | g3 x#5 y[#5+#2-#4] r#4 38 | g1 x#5 y#5 39 | 40 | g1 x0 y0 41 | m18 (turn off motors) 42 | m107 (turn off fan) 43 | -------------------------------------------------------------------------------- /src/testdata/rounded-bracket-simple.gcode: -------------------------------------------------------------------------------- 1 | G1 F[150 * 60] 2 | X0 Y100 (up) 3 | X20 Y100 (short right) 4 | Y30 (down to the knee) 5 | G3 X30 Y20 I10 J0 (rounded knee) 6 | X100 (right to end of bracket) 7 | Y0 (to the bottom) 8 | X0 Y0 (and back to origin) 9 | -------------------------------------------------------------------------------- /src/testdata/spiral-cut.gcode: -------------------------------------------------------------------------------- 1 | ; A spiral cut in the YZ plane so that it shows 2 | ; up neatly as sine as watchde from the XY plane 3 | #r=50 4 | G19 5 | F[150 * 60] 6 | G1 X0 Y#r Z0 7 | G2 Y#r Z0 I0 K#r X25 8 | G2 Y#r Z0 I0 K#r X50 9 | G2 Y#r Z0 I0 K#r X75 10 | G2 Y#r Z0 I0 K#r X100 11 | -------------------------------------------------------------------------------- /src/testdata/spline-character.gcode: -------------------------------------------------------------------------------- 1 | #1=0.004 ; scaled so that the result roughly fits in a (100mm,100mm) square 2 | #=5 ; Hovering this for rapid moves 3 | #=0 ; Since we don't have any probe in test, pretend zero 4 | 5 | g28 6 | g21 7 | G10 L2 P2 X[3.1159-[.8999/2]] Y[0.7502-[.6198/2]] 8 | G55 9 | g1 f[150 * 60] ; 150mm/s is our desired target speed in all testcases 10 | g0 z# 11 | g0 x[#1 * 12884] y[#1 * 6592] 12 | g4 p25 g30 g1 z# 13 | g5 i[#1 * 18] j[#1 * -975] p[#1 * -281] q[#1 * 704] x[#1 * 13332] y[#1 * 4074] 14 | g5 i[#1 * 280] j[#1 * -702] p[#1 * -450] q[#1 * 348] x[#1 * 14426] y[#1 * 2499] 15 | g5 i[#1 * 448] j[#1 * -346] p[#1 * -459] q[#1 * 151] x[#1 * 15786] y[#1 * 1754] 16 | g5 i[#1 * 458] j[#1 * -150] p[#1 * -486] q[#1 * 0] x[#1 * 17202] y[#1 * 1529] 17 | g5 i[#1 * 1888] j[#1 * 0] p[#1 * -692] q[#1 * -1930] x[#1 * 21072] y[#1 * 4424] 18 | g1 x[#1 * 23512] y[#1 * 4424] 19 | g5 i[#1 * -303] j[#1 * -1576] p[#1 * 1119] q[#1 * 901] x[#1 * 21380] y[#1 * 709] 20 | g5 i[#1 * -1117] j[#1 * -899] p[#1 * 1687] q[#1 * 1] x[#1 * 17174] y[#1 * -640] 21 | g5 i[#1 * -2544] j[#1 * 0] p[#1 * 1048] q[#1 * -2009] x[#1 * 11786] y[#1 * 2373] 22 | g5 i[#1 * -37] j[#1 * 37] p[#1 * 1] q[#1 * -19] x[#1 * 11730] y[#1 * 2457] 23 | g5 i[#1 * -1038] j[#1 * -1088] p[#1 * 938] q[#1 * 489] x[#1 * 8767] y[#1 * 92] 24 | g5 i[#1 * -936] j[#1 * -488] p[#1 * 1096] q[#1 * 0] x[#1 * 5720] y[#1 * -640] 25 | g5 i[#1 * -1474] j[#1 * 0] p[#1 * 893] q[#1 * -788] x[#1 * 2170] y[#1 * 542] 26 | g5 i[#1 * -892] j[#1 * 788] p[#1 * 0] q[#1 * -1333] x[#1 * 832] y[#1 * 3723] 27 | g5 i[#1 * 0] j[#1 * 712] p[#1 * -247] q[#1 * -536] x[#1 * 1202] y[#1 * 5594] 28 | g5 i[#1 * 246] j[#1 * 535] p[#1 * -400] q[#1 * -338] x[#1 * 2170] y[#1 * 6903] 29 | g5 i[#1 * 399] j[#1 * 338] p[#1 * -665] q[#1 * -225] x[#1 * 3765] y[#1 * 7747] 30 | g5 i[#1 * 664] j[#1 * 225] p[#1 * -675] q[#1 * -113] x[#1 * 5773] y[#1 * 8254] 31 | g5 i[#1 * 674] j[#1 * 112] p[#1 * -968] q[#1 * -74] x[#1 * 8236] y[#1 * 8533] 32 | g5 i[#1 * 968] j[#1 * 74] p[#1 * -334] q[#1 * -238] x[#1 * 10188] y[#1 * 9000] 33 | g5 i[#1 * 333] j[#1 * 237] p[#1 * -1] q[#1 * -531] x[#1 * 10688] y[#1 * 10151] 34 | g1 x[#1 * 10688] y[#1 * 10754] 35 | g5 i[#1 * 0] j[#1 * 1424] p[#1 * 2184] q[#1 * -1] x[#1 * 7413] y[#1 * 12891] 36 | g5 i[#1 * -2072] j[#1 * 0] p[#1 * 186] q[#1 * 1707] x[#1 * 4027] y[#1 * 10331] 37 | g1 x[#1 * 1408] y[#1 * 10331] 38 | g5 i[#1 * 116] j[#1 * 3246] p[#1 * -3925] q[#1 * 0] x[#1 * 7469] y[#1 * 15200] 39 | g5 i[#1 * 2379] j[#1 * 0] p[#1 * -875] q[#1 * 1631] x[#1 * 12349] y[#1 * 12754] 40 | g5 i[#1 * 504] j[#1 * 756] p[#1 * -861] q[#1 * -438] x[#1 * 14396] y[#1 * 14544] 41 | g5 i[#1 * 860] j[#1 * 437] p[#1 * -1011] q[#1 * -1] x[#1 * 17202] y[#1 * 15200] 42 | g5 i[#1 * 1384] j[#1 * 0] p[#1 * -1063] q[#1 * 696] x[#1 * 20872] y[#1 * 14156] 43 | g5 i[#1 * 1062] j[#1 * -696] p[#1 * -494] q[#1 * 1205] x[#1 * 23205] y[#1 * 11305] 44 | g5 i[#1 * 398] j[#1 * -1034] p[#1 * -1] q[#1 * 2108] x[#1 * 23803] y[#1 * 6592] 45 | g1 x[#1 * 12884] y[#1 * 6592] 46 | g1 z# 47 | g0 x[#1 * 6247] y[#1 * 1416] 48 | g4 p25 g30 g1 z# 49 | g5 i[#1 * 1295] j[#1 * 0] p[#1 * -833] q[#1 * -760] x[#1 * 9439] y[#1 * 2555] 50 | g5 i[#1 * 832] j[#1 * 760] p[#1 * -1] q[#1 * -488] x[#1 * 10688] y[#1 * 4426] 51 | g1 x[#1 * 10688] y[#1 * 7268] 52 | g5 i[#1 * -555] j[#1 * -244] p[#1 * 953] q[#1 * 160] x[#1 * 8426] y[#1 * 6662] 53 | g5 i[#1 * -952] j[#1 * -159] p[#1 * 658] q[#1 * 95] x[#1 * 6011] y[#1 * 6282] 54 | g5 i[#1 * -656] j[#1 * -93] p[#1 * 526] q[#1 * 413] x[#1 * 4238] y[#1 * 5523] 55 | g5 i[#1 * -524] j[#1 * -412] p[#1 * 1] q[#1 * 751] x[#1 * 3451] y[#1 * 3779] 56 | g5 i[#1 * 0] j[#1 * -731] p[#1 * -504] q[#1 * 423] x[#1 * 4206] y[#1 * 2049] 57 | g5 i[#1 * 503] j[#1 * -422] p[#1 * -858] q[#1 * 0] x[#1 * 6247] y[#1 * 1416] 58 | g1 z# 59 | g0 x[#1 * 12940] y[#1 * 8507] 60 | g4 p25 g30 g1 z# 61 | g1 x[#1 * 21184] y[#1 * 8507] 62 | g5 i[#1 * 0] j[#1 * 1296] p[#1 * 748] q[#1 * -814] x[#1 * 20062] y[#1 * 11671] 63 | g5 i[#1 * -747] j[#1 * 813] p[#1 * 1197] q[#1 * -1] x[#1 * 17146] y[#1 * 12891] 64 | g5 i[#1 * -1177] j[#1 * 0] p[#1 * 767] q[#1 * 795] x[#1 * 14230] y[#1 * 11699] 65 | g5 i[#1 * -766] j[#1 * -794] p[#1 * 94] q[#1 * 1334] x[#1 * 12940] y[#1 * 8507] 66 | g1 z# 67 | g54 68 | g0 x0 y0 69 | -------------------------------------------------------------------------------- /src/testdata/spline-loop.gcode: -------------------------------------------------------------------------------- 1 | G90 G17 2 | 3 | G1 F[150 * 60] 4 | 5 | G1 X0 Y0 6 | G5 I200 J130 X100 Y0 P-200 Q130 7 | -------------------------------------------------------------------------------- /src/testdata/splines.gcode: -------------------------------------------------------------------------------- 1 | G90 G17 2 | 3 | G1 F[150 * 60] 4 | 5 | G1 X10 Y10 6 | 7 | ; Cubic splines 8 | G5 I0 J60 P0 Q-60 X30 Y30 (a curvy N) 9 | G5 P0 Q-60 X50 Y50 (another curvy N, attached smoothly) 10 | G5 P0 Q-60 X70 Y70 (another curvy N, attached smoothly) 11 | G5 P0 Q-60 X90 Y90 (another curvy N, attached smoothly) 12 | 13 | G1 X100 Y100 14 | 15 | ; Quadratic spline 16 | G5.1 X0 I-50 J-150 (a parabola) 17 | -------------------------------------------------------------------------------- /src/testdata/square-moves-direct.gcode: -------------------------------------------------------------------------------- 1 | G1 F[150 * 60] (150mm/s) 2 | ; Simple one-segment movement. 3 | X100 (right) 4 | Y100 (up) 5 | X0 (left) 6 | Y0 (down) 7 | X100 Y100 (diagonal top right) 8 | -------------------------------------------------------------------------------- /src/testdata/square-moves-small-segments.gcode: -------------------------------------------------------------------------------- 1 | G1 F[150 * 60] (150mm/s) 2 | ; Chop each movement into smaller segments to see if the 3 | ; planner does enough look-ahead to start decelerating early 4 | ; enough. 5 | #step_size=[100/20] 6 | 7 | ; right 8 | #d=0 9 | while [ #d <= 100 ] DO 10 | X#d 11 | #d+=#step_size 12 | END 13 | 14 | ; up 15 | #d=0 16 | while [ #d <= 100 ] DO 17 | Y#d 18 | #d+=#step_size 19 | END 20 | 21 | ; left 22 | #d=100 23 | while [ #d >= 0 ] DO 24 | X#d 25 | #d-=#step_size 26 | END 27 | 28 | ; down 29 | #d=100 30 | while [ #d >= 0 ] DO 31 | Y#d 32 | #d-=#step_size 33 | END 34 | 35 | ; Diagonal top right 36 | #d=0 37 | while [ #d <= 100 ] DO 38 | X#d Y#d 39 | #d+=#step_size 40 | END 41 | -------------------------------------------------------------------------------- /src/testdata/step-speed-different.config: -------------------------------------------------------------------------------- 1 | # A configuration in which each axis has a different number 2 | # of steps/mm. This helps in identifying if there is trouble 3 | # because of different handling of these. 4 | [ X-Axis ] 5 | steps-per-mm = 100 6 | max-feedrate = 300 7 | max-acceleration = 200 8 | home-pos = min 9 | range = 500 10 | 11 | [ Y-Axis ] 12 | steps-per-mm = 1000 13 | max-feedrate = 300 14 | max-acceleration = 200 15 | home-pos = min 16 | range = 500 17 | 18 | [ Z-Axis ] 19 | steps-per-mm = 10000 20 | max-feedrate = 4 21 | max-acceleration = 100 22 | home-pos = max 23 | range = 100 24 | -------------------------------------------------------------------------------- /src/testdata/step-speed-same.config: -------------------------------------------------------------------------------- 1 | [ X-Axis ] 2 | steps-per-mm = 100 3 | max-feedrate = 300 4 | max-acceleration = 200 5 | home-pos = min 6 | range = 500 7 | 8 | [ Y-Axis ] 9 | steps-per-mm = 100 10 | max-feedrate = 300 11 | max-acceleration = 200 12 | home-pos = min 13 | range = 500 14 | 15 | [ Z-Axis ] 16 | steps-per-mm = 100 17 | max-feedrate = 300 18 | max-acceleration = 100 19 | home-pos = max 20 | range = 100 21 | -------------------------------------------------------------------------------- /src/uio-pruss-interface.cc: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 2 | * (c) 2016 Henner Zeller , 3 | * Leonardo Romor , 4 | * 5 | * This file is part of BeagleG. http://github.com/hzeller/beagleg 6 | * 7 | * BeagleG is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * BeagleG is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with BeagleG. If not, see . 19 | */ 20 | 21 | // Implementation of the hardware interface of the PRU using the uio_pruss 22 | // driver from the bone line kernel. 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "common/logging.h" 33 | #include "pru-hardware-interface.h" 34 | 35 | // Generated PRU code from motor-interface-pru.p 36 | #include "motor-interface-pru_bin.h" 37 | 38 | // Target PRU 39 | #define PRU_NUM 0 40 | 41 | #if PRU_NUM == 0 42 | #define PRU_DATARAM PRUSS0_PRU0_DATARAM 43 | #define PRU_INSTRUCTIONRAM PRUSS0_PRU0_IRAM 44 | #define PRU_ARM_INTERRUPT PRU0_ARM_INTERRUPT 45 | #elif PRU_NUM == 1 46 | #define PRU_DATARAM PRUSS0_PRU1_DATARAM 47 | #define PRU_INSTRUCTIONRAM PRUSS0_PRU1_IRAM 48 | #define PRU_ARM_INTERRUPT PRU1_ARM_INTERRUPT 49 | #endif 50 | 51 | bool UioPrussInterface::Init() { 52 | tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; 53 | prussdrv_init(); 54 | 55 | /* Get the interrupt initialized */ 56 | int ret = prussdrv_open(PRU_EVTOUT_0); // allow access. 57 | if (ret) { 58 | Log_error("prussdrv_open() failed (%d) %s\n", ret, strerror(errno)); 59 | return false; 60 | } 61 | prussdrv_pruintc_init(&pruss_intc_initdata); 62 | return true; 63 | } 64 | 65 | bool UioPrussInterface::AllocateSharedMem(void **pru_mmap, const size_t size) { 66 | prussdrv_map_prumem(PRU_DATARAM, pru_mmap); 67 | if (*pru_mmap == NULL) { 68 | Log_error("Couldn't map PRU memory.\n"); 69 | return false; 70 | } 71 | memset(*pru_mmap, 0x00, size); 72 | return true; 73 | } 74 | 75 | bool UioPrussInterface::StartExecution() { 76 | prussdrv_pru_write_memory(PRU_INSTRUCTIONRAM, 0, PRUcode, sizeof(PRUcode)); 77 | prussdrv_pru_enable(PRU_NUM); 78 | return true; 79 | } 80 | 81 | unsigned UioPrussInterface::WaitEvent() { 82 | const unsigned num_events = prussdrv_pru_wait_event(PRU_EVTOUT_0); 83 | prussdrv_pru_clear_event(PRU_EVTOUT_0, PRU_ARM_INTERRUPT); 84 | return num_events; 85 | } 86 | 87 | bool UioPrussInterface::Shutdown() { 88 | prussdrv_pru_disable(PRU_NUM); 89 | prussdrv_exit(); 90 | return true; 91 | } 92 | -------------------------------------------------------------------------------- /systemd/Makefile: -------------------------------------------------------------------------------- 1 | PREFIX?=/usr/local 2 | install: 3 | install beagleg.service /etc/systemd/system/ 4 | install run-beagleg.sh $(PREFIX)/bin 5 | -------------------------------------------------------------------------------- /systemd/README: -------------------------------------------------------------------------------- 1 | Support to start BeagleG using systemd. 2 | 3 | Just modify according to your taste, then 4 | sudo make install 5 | 6 | Copy your configuration file to /etc/beagleg.config 7 | 8 | Pretty basic right now; Questions (as I am more comfortable with SysV init:) 9 | * is it an ok practice to have a start script like run-beagleg.sh which then is 10 | called from systemd ? 11 | * What is the recommended service to depend on so that the uio_pruss module 12 | is properly loaded ? Right now this is happening manually. 13 | -------------------------------------------------------------------------------- /systemd/beagleg.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BeagleG - CNC motion control 3 | 4 | [Service] 5 | User=root 6 | ExecStart=/usr/local/bin/run-beagleg.sh 7 | 8 | [Install] 9 | WantedBy=basic.target 10 | 11 | -------------------------------------------------------------------------------- /systemd/run-beagleg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Dropping permisisons to this after hardware is initialized 3 | PERMISSION_DROP=daemon:daemon 4 | 5 | VARDIR=/var/beagleg 6 | mkdir -p $VARDIR 7 | chown $PERMISSION_DROP $VARDIR 8 | 9 | # The port we're listening for gcode commands. 10 | PORT=4444 11 | 12 | # Status server port. 13 | STATUS_PORT=4445 14 | 15 | # Machine configuration of motors and switches etc. 16 | CONFIG=/etc/beagleg.config 17 | 18 | # Permanent storage of variables used in GCode 19 | PARAMS_FILE=$VARDIR/beagleg.params 20 | 21 | # Logfile 22 | LOGFILE=$VARDIR/beagleg.log 23 | 24 | # Machine control binary. Default 'make install' location is in /usr/local/bin 25 | MACHINE_CONTROL=/usr/local/bin/machine-control 26 | 27 | # We do need the uio-pruss module to be loaded. 28 | # TODO: figure out what in systemd the preferred 'After' target is to 29 | # have his already taken care of. 30 | modprobe uio_pruss 31 | 32 | exec ${MACHINE_CONTROL} --priv=${PERMISSION_DROP} --config=${CONFIG} --port=${PORT} --status-server=${STATUS_PORT} --logfile=${LOGFILE} --param=${PARAMS_FILE} 33 | --------------------------------------------------------------------------------